diff options
1288 files changed, 63638 insertions, 36014 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index c274a6c44..be13c30aa 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -51,6 +51,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinim $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/dictionaries/cs_wordlist.combined.gz b/dictionaries/cs_wordlist.combined.gz Binary files differindex 7829d6573..94ba863a2 100644 --- a/dictionaries/cs_wordlist.combined.gz +++ b/dictionaries/cs_wordlist.combined.gz diff --git a/dictionaries/da_wordlist.combined.gz b/dictionaries/da_wordlist.combined.gz Binary files differindex e7140195b..b4baf627f 100644 --- a/dictionaries/da_wordlist.combined.gz +++ b/dictionaries/da_wordlist.combined.gz diff --git a/dictionaries/de_wordlist.combined.gz b/dictionaries/de_wordlist.combined.gz Binary files differindex 6a4bd445c..400718df1 100644 --- a/dictionaries/de_wordlist.combined.gz +++ b/dictionaries/de_wordlist.combined.gz diff --git a/dictionaries/el_wordlist.combined.gz b/dictionaries/el_wordlist.combined.gz Binary files differindex 74effa34b..599734cf8 100644 --- a/dictionaries/el_wordlist.combined.gz +++ b/dictionaries/el_wordlist.combined.gz diff --git a/dictionaries/en_GB_wordlist.combined.gz b/dictionaries/en_GB_wordlist.combined.gz Binary files differindex 50647b847..22685d1ce 100644 --- a/dictionaries/en_GB_wordlist.combined.gz +++ b/dictionaries/en_GB_wordlist.combined.gz diff --git a/dictionaries/en_US_wordlist.combined.gz b/dictionaries/en_US_wordlist.combined.gz Binary files differindex 19f9ab4ff..92a3761df 100644 --- a/dictionaries/en_US_wordlist.combined.gz +++ b/dictionaries/en_US_wordlist.combined.gz diff --git a/dictionaries/en_emoji.combined.gz b/dictionaries/en_emoji.combined.gz Binary files differindex 0fc009df7..4d9cf1b59 100644 --- a/dictionaries/en_emoji.combined.gz +++ b/dictionaries/en_emoji.combined.gz diff --git a/dictionaries/en_wordlist.combined.gz b/dictionaries/en_wordlist.combined.gz Binary files differindex 874a5de20..f8b71c821 100644 --- a/dictionaries/en_wordlist.combined.gz +++ b/dictionaries/en_wordlist.combined.gz diff --git a/dictionaries/es_wordlist.combined.gz b/dictionaries/es_wordlist.combined.gz Binary files differindex 0a48b6d11..56617db99 100644 --- a/dictionaries/es_wordlist.combined.gz +++ b/dictionaries/es_wordlist.combined.gz diff --git a/dictionaries/fi_wordlist.combined.gz b/dictionaries/fi_wordlist.combined.gz Binary files differindex eefbfe51a..b7332ad3e 100644 --- a/dictionaries/fi_wordlist.combined.gz +++ b/dictionaries/fi_wordlist.combined.gz diff --git a/dictionaries/fr_emoji.combined.gz b/dictionaries/fr_emoji.combined.gz Binary files differindex f2929770d..5c9c7a096 100644 --- a/dictionaries/fr_emoji.combined.gz +++ b/dictionaries/fr_emoji.combined.gz diff --git a/dictionaries/fr_wordlist.combined.gz b/dictionaries/fr_wordlist.combined.gz Binary files differindex 49dfd7988..697f36799 100644 --- a/dictionaries/fr_wordlist.combined.gz +++ b/dictionaries/fr_wordlist.combined.gz diff --git a/dictionaries/hr_wordlist.combined.gz b/dictionaries/hr_wordlist.combined.gz Binary files differindex 864f67651..9a2086f1f 100644 --- a/dictionaries/hr_wordlist.combined.gz +++ b/dictionaries/hr_wordlist.combined.gz diff --git a/dictionaries/it_wordlist.combined.gz b/dictionaries/it_wordlist.combined.gz Binary files differindex dfb175259..5a5cbdc7a 100644 --- a/dictionaries/it_wordlist.combined.gz +++ b/dictionaries/it_wordlist.combined.gz diff --git a/dictionaries/iw_wordlist.combined.gz b/dictionaries/iw_wordlist.combined.gz Binary files differindex 36b047894..13eab9f17 100644 --- a/dictionaries/iw_wordlist.combined.gz +++ b/dictionaries/iw_wordlist.combined.gz diff --git a/dictionaries/lt_wordlist.combined.gz b/dictionaries/lt_wordlist.combined.gz Binary files differindex 029722d95..961266bb8 100644 --- a/dictionaries/lt_wordlist.combined.gz +++ b/dictionaries/lt_wordlist.combined.gz diff --git a/dictionaries/lv_wordlist.combined.gz b/dictionaries/lv_wordlist.combined.gz Binary files differindex 41e1c28bd..ae906a9db 100644 --- a/dictionaries/lv_wordlist.combined.gz +++ b/dictionaries/lv_wordlist.combined.gz diff --git a/dictionaries/nb_wordlist.combined.gz b/dictionaries/nb_wordlist.combined.gz Binary files differindex b699912b7..1c0f2cfb9 100644 --- a/dictionaries/nb_wordlist.combined.gz +++ b/dictionaries/nb_wordlist.combined.gz diff --git a/dictionaries/nl_wordlist.combined.gz b/dictionaries/nl_wordlist.combined.gz Binary files differindex 89c238830..37ba8ab42 100644 --- a/dictionaries/nl_wordlist.combined.gz +++ b/dictionaries/nl_wordlist.combined.gz diff --git a/dictionaries/pl_wordlist.combined.gz b/dictionaries/pl_wordlist.combined.gz Binary files differindex 2b53f69cb..ba71a5581 100644 --- a/dictionaries/pl_wordlist.combined.gz +++ b/dictionaries/pl_wordlist.combined.gz diff --git a/dictionaries/pt_BR_wordlist.combined.gz b/dictionaries/pt_BR_wordlist.combined.gz Binary files differindex 2d22447e4..02df1c1ee 100644 --- a/dictionaries/pt_BR_wordlist.combined.gz +++ b/dictionaries/pt_BR_wordlist.combined.gz diff --git a/dictionaries/pt_PT_wordlist.combined.gz b/dictionaries/pt_PT_wordlist.combined.gz Binary files differindex 1504165d0..bcd50ab03 100644 --- a/dictionaries/pt_PT_wordlist.combined.gz +++ b/dictionaries/pt_PT_wordlist.combined.gz diff --git a/dictionaries/ru_wordlist.combined.gz b/dictionaries/ru_wordlist.combined.gz Binary files differindex 572314db6..acde9bc73 100644 --- a/dictionaries/ru_wordlist.combined.gz +++ b/dictionaries/ru_wordlist.combined.gz diff --git a/dictionaries/sl_wordlist.combined.gz b/dictionaries/sl_wordlist.combined.gz Binary files differindex 55e1bb1c8..a7240fe5b 100644 --- a/dictionaries/sl_wordlist.combined.gz +++ b/dictionaries/sl_wordlist.combined.gz diff --git a/dictionaries/sr_wordlist.combined.gz b/dictionaries/sr_wordlist.combined.gz Binary files differindex 8488a08b4..30ce99670 100644 --- a/dictionaries/sr_wordlist.combined.gz +++ b/dictionaries/sr_wordlist.combined.gz diff --git a/dictionaries/sv_wordlist.combined.gz b/dictionaries/sv_wordlist.combined.gz Binary files differindex 63425206e..b6ebab320 100644 --- a/dictionaries/sv_wordlist.combined.gz +++ b/dictionaries/sv_wordlist.combined.gz diff --git a/dictionaries/tr_wordlist.combined.gz b/dictionaries/tr_wordlist.combined.gz Binary files differindex 0251778c7..306cea184 100644 --- a/dictionaries/tr_wordlist.combined.gz +++ b/dictionaries/tr_wordlist.combined.gz diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 031d62e0c..6f4e602ce 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -18,7 +18,7 @@ coreApp="true" package="com.android.inputmethod.latin"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> @@ -32,9 +32,10 @@ <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" /> <application android:label="@string/english_ime_name" - android:icon="@mipmap/ic_launcher_keyboard" + android:icon="@drawable/ic_launcher_keyboard" android:killAfterRestore="false" - android:supportsRtl="true"> + android:supportsRtl="true" + android:allowBackup="true"> <service android:name="LatinIME" android:label="@string/english_ime_name" @@ -56,8 +57,9 @@ </service> <activity android:name=".setup.SetupActivity" + android:theme="@style/platformActivityTheme" android:label="@string/english_ime_name" - android:icon="@mipmap/ic_launcher_keyboard" + android:icon="@drawable/ic_launcher_keyboard" android:launchMode="singleTask" android:noHistory="true"> <intent-filter> @@ -67,6 +69,7 @@ </activity> <activity android:name=".setup.SetupWizardActivity" + android:theme="@style/platformActivityTheme" android:label="@string/english_ime_name" android:clearTaskOnLaunch="true"> <intent-filter> @@ -83,6 +86,7 @@ </receiver> <activity android:name=".settings.SettingsActivity" + android:theme="@style/platformActivityTheme" android:label="@string/english_ime_settings" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> @@ -91,6 +95,7 @@ </activity> <activity android:name=".spellcheck.SpellCheckerSettingsActivity" + android:theme="@style/platformActivityTheme" android:label="@string/android_spell_checker_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -98,6 +103,7 @@ </activity> <activity android:name=".settings.DebugSettingsActivity" + android:theme="@style/platformActivityTheme" android:label="@string/english_ime_debug_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -110,13 +116,14 @@ </intent-filter> </receiver> - <receiver android:name=".personalization.DictionaryDecayBroadcastReciever"> + <receiver android:name=".personalization.DictionaryDecayBroadcastReciever" + android:exported="false"> <intent-filter> <action android:name="com.android.inputmethod.latin.personalization.DICT_DECAY" /> </intent-filter> </receiver> - <receiver android:name=".DictionaryPackInstallBroadcastReceiver"> + <receiver android:name=".DictionaryPackInstallBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.android.inputmethod.dictionarypack.aosp.UNKNOWN_CLIENT" /> </intent-filter> @@ -143,8 +150,8 @@ </receiver> <activity android:name="com.android.inputmethod.dictionarypack.DictionarySettingsActivity" + android:theme="@style/platformActivityTheme" android:label="@string/dictionary_settings_title" - android:theme="@android:style/Theme.Holo" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> <action android:name="android.intent.action.MAIN"/> @@ -152,8 +159,8 @@ </activity> <activity android:name="com.android.inputmethod.dictionarypack.DownloadOverMeteredDialog" - android:label="@string/dictionary_install_over_metered_network_prompt" - android:theme="@android:style/Theme.Holo"> + android:theme="@style/platformActivityTheme" + android:label="@string/dictionary_install_over_metered_network_prompt"> <intent-filter> <action android:name="android.intent.action.MAIN"/> </intent-filter> diff --git a/java/proguard.flags b/java/proguard.flags index c08a968bc..f7b7f2898 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -14,3 +14,10 @@ -keepclassmembers class * { native <methods>; } + +# Keep classes that are used as a parameter type of methods that are also marked as keep +# to preserve changing those methods' signature. +-keep class com.android.inputmethod.latin.utils.LanguageModelParam +-keep class com.android.inputmethod.latin.AssetFileAddress +-keep class com.android.inputmethod.latin.makedict.ProbabilityInfo +-keep class com.android.inputmethod.latin.Dictionary diff --git a/java/res/color/emoji_tab_label_color_gb.xml b/java/res/color/emoji_tab_label_color_gb.xml deleted file mode 100644 index e1d2f715e..000000000 --- a/java/res/color/emoji_tab_label_color_gb.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item - android:state_focused="true" - android:color="@color/key_text_color_gb" /> - <item - android:state_pressed="true" - android:color="@color/key_text_color_gb" /> - <item - android:state_selected="true" - android:color="@color/key_text_color_gb" /> - <item - android:color="@color/key_text_inactivated_color_gb" /> -</selector> diff --git a/java/res/color/key_text_color_holo.xml b/java/res/color/key_text_color_holo.xml deleted file mode 100644 index d034a945f..000000000 --- a/java/res/color/key_text_color_holo.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> - <item android:state_single="true" android:state_pressed="true" - android:color="@color/key_text_color_functional_holo" /> - <item android:state_single="true" - android:color="@color/key_text_color_functional_holo" /> - - <!-- Action keys. --> - <item android:state_active="true" android:state_pressed="true" - android:color="@color/key_text_color_normal_holo" /> - <item android:state_active="true" - android:color="@color/key_text_color_normal_holo" /> - - <!-- Toggle keys. Use checkable/checked state. --> - <item android:state_checkable="true" android:state_checked="true" android:state_pressed="true" - android:color="@color/key_text_color_normal_holo" /> - <item android:state_checkable="true" android:state_pressed="true" - android:color="@color/key_text_color_normal_holo" /> - <item android:state_checkable="true" android:state_checked="true" - android:color="@color/key_text_color_normal_holo" /> - <item android:state_checkable="true" - android:color="@color/key_text_color_normal_holo" /> - - <!-- Empty background keys. --> - <item android:state_empty="true" - android:color="@color/key_text_color_normal_holo" /> - - <!-- Normal keys. --> - <item android:state_pressed="true" - android:color="@color/key_text_color_normal_holo" /> - <item android:color="@color/key_text_color_normal_holo" /> -</selector> diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png Binary files differdeleted file mode 100644 index 3e25180f0..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png Binary files differdeleted file mode 100644 index bad360f77..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png Binary files differdeleted file mode 100644 index 49f519860..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png Binary files differdeleted file mode 100644 index e784eddf8..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png Binary files differdeleted file mode 100644 index a4731cf1a..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png Binary files differdeleted file mode 100644 index 03e163c9c..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/ic_launcher_keyboard.png b/java/res/drawable-hdpi/ic_launcher_keyboard.png Binary files differnew file mode 100644 index 000000000..7ae00ed3f --- /dev/null +++ b/java/res/drawable-hdpi/ic_launcher_keyboard.png diff --git a/java/res/drawable-hdpi/ic_subtype_mic_dark.png b/java/res/drawable-hdpi/ic_subtype_mic_dark.png Binary files differdeleted file mode 100644 index eacbcd255..000000000 --- a/java/res/drawable-hdpi/ic_subtype_mic_dark.png +++ /dev/null diff --git a/java/res/drawable-hdpi/keyboard_background_gb.9.png b/java/res/drawable-hdpi/keyboard_background_gb.9.png Binary files differdeleted file mode 100644 index fa3d449f7..000000000 --- a/java/res/drawable-hdpi/keyboard_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_klp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_klp.9.png Binary files differindex 50ed568ff..be394151a 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_background_klp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_klp.9.png diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png Binary files differdeleted file mode 100644 index baff80950..000000000 --- a/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png Binary files differdeleted file mode 100644 index 7cab5a899..000000000 --- a/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png Binary files differindex d75fcacd5..d85663bf3 100644 --- a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png +++ b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png diff --git a/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png Binary files differindex 5af09ad8c..2ea4a74a5 100644 --- a/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png +++ b/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png diff --git a/java/res/drawable-hdpi/sym_keyboard_space.png b/java/res/drawable-hdpi/sym_keyboard_space.png Binary files differindex 780733ec5..78cd6b7bf 100644 --- a/java/res/drawable-hdpi/sym_keyboard_space.png +++ b/java/res/drawable-hdpi/sym_keyboard_space.png diff --git a/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png Binary files differdeleted file mode 100644 index c76f64b94..000000000 --- a/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png Binary files differdeleted file mode 100644 index 12bc97928..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png Binary files differdeleted file mode 100644 index 44bd414a1..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png Binary files differdeleted file mode 100644 index 43fdf5b88..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png Binary files differdeleted file mode 100644 index 1c1f3d711..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png Binary files differdeleted file mode 100644 index dacb675a9..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png Binary files differdeleted file mode 100644 index 3daa69f31..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/ic_launcher_keyboard.png b/java/res/drawable-mdpi/ic_launcher_keyboard.png Binary files differnew file mode 100644 index 000000000..cc73f3be1 --- /dev/null +++ b/java/res/drawable-mdpi/ic_launcher_keyboard.png diff --git a/java/res/drawable-mdpi/keyboard_background_gb.9.png b/java/res/drawable-mdpi/keyboard_background_gb.9.png Binary files differdeleted file mode 100644 index 4f81704c4..000000000 --- a/java/res/drawable-mdpi/keyboard_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_klp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_klp.9.png Binary files differindex 564f5460c..625490b1f 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_background_klp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_klp.9.png diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png Binary files differdeleted file mode 100644 index 0d9ab97f0..000000000 --- a/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png Binary files differdeleted file mode 100644 index fa6c0feff..000000000 --- a/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/more_keys_divider.png b/java/res/drawable-mdpi/more_keys_divider.png Binary files differindex a46284f21..0f71c6172 100644 --- a/java/res/drawable-mdpi/more_keys_divider.png +++ b/java/res/drawable-mdpi/more_keys_divider.png diff --git a/java/res/drawable-mdpi/more_suggestions_divider.png b/java/res/drawable-mdpi/more_suggestions_divider.png Binary files differindex a46284f21..0f71c6172 100644 --- a/java/res/drawable-mdpi/more_suggestions_divider.png +++ b/java/res/drawable-mdpi/more_suggestions_divider.png diff --git a/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png Binary files differindex a10dc8fa2..fee15807c 100644 --- a/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png +++ b/java/res/drawable-mdpi/sym_keyboard_feedback_tab.png diff --git a/java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.png Binary files differdeleted file mode 100644 index 537f39b02..000000000 --- a/java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.png +++ /dev/null diff --git a/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png b/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png Binary files differdeleted file mode 100644 index 84a63dc7f..000000000 --- a/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png +++ /dev/null diff --git a/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png Binary files differindex 36c8c9623..613f4dc88 100644 --- a/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png +++ b/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png diff --git a/java/res/drawable-mdpi/sym_keyboard_space.png b/java/res/drawable-mdpi/sym_keyboard_space.png Binary files differindex cbe4a88d6..6d03e6347 100644 --- a/java/res/drawable-mdpi/sym_keyboard_space.png +++ b/java/res/drawable-mdpi/sym_keyboard_space.png diff --git a/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png Binary files differdeleted file mode 100644 index 1c1ca2cc7..000000000 --- a/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png Binary files differdeleted file mode 100644 index 026005d6f..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal_off.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal_off.9.png Binary files differdeleted file mode 100644 index 38c5f244b..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_off.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal_on.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal_on.9.png Binary files differdeleted file mode 100644 index f1223e50e..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_on.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png Binary files differdeleted file mode 100644 index ec35db54d..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_off.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_pressed_off.9.png Binary files differdeleted file mode 100644 index bd30464d6..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_off.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_on.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_pressed_on.9.png Binary files differdeleted file mode 100644 index a3ff5d1bb..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/ic_launcher_keyboard.png b/java/res/drawable-xhdpi/ic_launcher_keyboard.png Binary files differnew file mode 100644 index 000000000..f2ac50dfe --- /dev/null +++ b/java/res/drawable-xhdpi/ic_launcher_keyboard.png diff --git a/java/res/drawable-xhdpi/ic_subtype_mic_dark.png b/java/res/drawable-xhdpi/ic_subtype_mic_dark.png Binary files differdeleted file mode 100644 index 17581ba89..000000000 --- a/java/res/drawable-xhdpi/ic_subtype_mic_dark.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/keyboard_background_gb.9.png b/java/res/drawable-xhdpi/keyboard_background_gb.9.png Binary files differdeleted file mode 100644 index 27b7a108c..000000000 --- a/java/res/drawable-xhdpi/keyboard_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_klp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_klp.9.png Binary files differindex e8c65f677..c211d89c8 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_background_klp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_klp.9.png diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png Binary files differdeleted file mode 100644 index 79f7ab00a..000000000 --- a/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png Binary files differdeleted file mode 100644 index 1b568df03..000000000 --- a/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png Binary files differindex 0650e01cb..b0ee35d59 100644 --- a/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png +++ b/java/res/drawable-xhdpi/sym_keyboard_feedback_tab.png diff --git a/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png Binary files differindex 99ee97dbf..15a97394e 100644 --- a/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png +++ b/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png diff --git a/java/res/drawable-xhdpi/sym_keyboard_space.png b/java/res/drawable-xhdpi/sym_keyboard_space.png Binary files differindex 66fc3e9d3..3691280e3 100644 --- a/java/res/drawable-xhdpi/sym_keyboard_space.png +++ b/java/res/drawable-xhdpi/sym_keyboard_space.png diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png Binary files differdeleted file mode 100644 index 6525fefab..000000000 --- a/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/ic_launcher_keyboard.png b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png Binary files differnew file mode 100644 index 000000000..df386e827 --- /dev/null +++ b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png diff --git a/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png b/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png Binary files differdeleted file mode 100644 index 811103a56..000000000 --- a/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_klp.9.png Binary files differindex 11eee94f3..fd2f9e514 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_klp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_klp.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png Binary files differindex 2079e0462..3ab79007e 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_klp.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png Binary files differindex c4178d9a8..99543a1e0 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_klp.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png Binary files differindex d3d8733fd..e9e379287 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_klp.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png Binary files differindex d7ec8bcb2..6c1143aeb 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_klp.9.png diff --git a/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png Binary files differindex 7041bb6ce..bf643e1d8 100644 --- a/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png +++ b/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png diff --git a/java/res/drawable/btn_keyboard_key_gb.xml b/java/res/drawable/btn_keyboard_key_gb.xml deleted file mode 100644 index 3fc253e85..000000000 --- a/java/res/drawable/btn_keyboard_key_gb.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> - <item android:state_single="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed" /> - <item android:state_single="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal" /> - - <!-- Action keys. --> - <item android:state_active="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed" /> - <item android:state_active="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal" /> - - <!-- Toggle keys. Use checkable/checked state. --> - <item android:state_checkable="true" android:state_checked="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_on" /> - <item android:state_checkable="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_off" /> - <item android:state_checkable="true" android:state_checked="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal_on" /> - <item android:state_checkable="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal_off" /> - - <!-- Empty background keys. --> - <item android:state_empty="true" - android:drawable="@drawable/transparent" /> - - <!-- Normal keys. --> - <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_light_pressed" /> - <item android:drawable="@drawable/btn_keyboard_key_light_normal" /> -</selector> diff --git a/java/res/drawable/btn_keyboard_key_functional_gb.xml b/java/res/drawable/btn_keyboard_spacebar_ics.xml index 431359c20..4530ea079 100644 --- a/java/res/drawable/btn_keyboard_key_functional_gb.xml +++ b/java/res/drawable/btn_keyboard_spacebar_ics.xml @@ -15,8 +15,7 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed" /> - <item android:drawable="@drawable/btn_keyboard_key_dark_normal" /> + android:drawable="@drawable/btn_keyboard_key_light_pressed_ics" /> + <item android:drawable="@drawable/btn_keyboard_key_light_normal_holo" /> </selector> diff --git a/java/res/drawable/btn_keyboard_key_popup_gb.xml b/java/res/drawable/btn_keyboard_spacebar_klp.xml index 9e3670d22..6b07a392f 100644 --- a/java/res/drawable/btn_keyboard_key_popup_gb.xml +++ b/java/res/drawable/btn_keyboard_spacebar_klp.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- Copyright (C) 2013 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. @@ -16,6 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_light_popup_selected" /> - <item android:drawable="@drawable/transparent" /> + android:drawable="@drawable/btn_keyboard_key_light_pressed_klp" /> + <item android:drawable="@drawable/btn_keyboard_key_light_normal_holo" /> </selector> diff --git a/java/res/drawable/keyboard_key_feedback_gb.xml b/java/res/drawable/keyboard_key_feedback_gb.xml deleted file mode 100644 index 397e948d8..000000000 --- a/java/res/drawable/keyboard_key_feedback_gb.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<selector - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" -> - <item latin:state_has_morekeys="true" - android:drawable="@drawable/keyboard_key_feedback_more_background" /> - <item android:drawable="@drawable/keyboard_key_feedback_background" /> -</selector> diff --git a/java/res/layout/emoji_keyboard_page.xml b/java/res/layout/emoji_keyboard_page.xml index e0b752b32..9afad366a 100644 --- a/java/res/layout/emoji_keyboard_page.xml +++ b/java/res/layout/emoji_keyboard_page.xml @@ -18,16 +18,9 @@ */ --> -<com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier +<com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/emoji_keyboard_scroller" - android:clipToPadding="false" - android:layout_width="match_parent" - android:layout_height="match_parent" -> - <com.android.inputmethod.keyboard.internal.ScrollKeyboardView - android:id="@+id/emoji_keyboard_page" - android:layoutDirection="ltr" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> -</com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier> + android:id="@+id/emoji_keyboard_page" + android:layoutDirection="ltr" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> diff --git a/java/res/layout/emoji_keyboard_tab_icon.xml b/java/res/layout/emoji_keyboard_tab_icon.xml index 1609f6a26..13bb41ca2 100644 --- a/java/res/layout/emoji_keyboard_tab_icon.xml +++ b/java/res/layout/emoji_keyboard_tab_icon.xml @@ -18,10 +18,12 @@ */ --> +<!-- Note: contentDescription will be added programatically in {@link EmojiPalettesView}. --> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dip" android:layout_weight="1.0" android:layout_height="wrap_content" android:gravity="center" android:scaleType="center" + android:contentDescription="@null" /> diff --git a/java/res/layout/emoji_palettes_view.xml b/java/res/layout/emoji_palettes_view.xml index 1c6da90ba..552a474b4 100644 --- a/java/res/layout/emoji_palettes_view.xml +++ b/java/res/layout/emoji_palettes_view.xml @@ -29,7 +29,7 @@ <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="@dimen/suggestions_strip_height" + android:layout_height="@dimen/config_suggestions_strip_height" > <TabHost android:id="@+id/emoji_category_tabhost" @@ -71,7 +71,8 @@ android:layout_weight="12.5" android:layout_height="match_parent" android:background="@color/emoji_key_background_color" - android:src="@drawable/sym_keyboard_delete_holo_dark" /> + android:src="@drawable/sym_keyboard_delete_holo_dark" + android:contentDescription="@string/spoken_description_delete" /> </LinearLayout> <android.support.v4.view.ViewPager android:id="@+id/emoji_keyboard_pager" @@ -89,22 +90,23 @@ android:layout_height="0dip" android:layout_weight="1" > - <ImageButton - android:id="@+id/emoji_keyboard_alphabet" + <TextView + android:id="@+id/emoji_keyboard_alphabet_left" android:layout_width="0dip" android:layout_weight="0.15" - android:layout_height="match_parent" - android:src="@drawable/ic_ime_switcher_dark" /> + android:gravity="center" + android:layout_height="match_parent" /> <ImageButton android:id="@+id/emoji_keyboard_space" android:layout_width="0dip" android:layout_weight="0.70" - android:layout_height="match_parent" /> - <ImageButton - android:id="@+id/emoji_keyboard_alphabet2" + android:layout_height="match_parent" + android:contentDescription="@string/spoken_description_space"/> + <TextView + android:id="@+id/emoji_keyboard_alphabet_right" android:layout_width="0dip" android:layout_weight="0.15" - android:layout_height="match_parent" - android:src="@drawable/ic_ime_switcher_dark" /> + android:gravity="center" + android:layout_height="match_parent" /> </LinearLayout> </com.android.inputmethod.keyboard.EmojiPalettesView> diff --git a/java/res/layout/hint_add_to_dictionary.xml b/java/res/layout/hint_add_to_dictionary.xml deleted file mode 100644 index 68a9faf19..000000000 --- a/java/res/layout/hint_add_to_dictionary.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?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. -*/ ---> - -<!-- This is derived from suggestion_word.xml without minWidth attribute and padding --> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:textSize="@dimen/suggestion_text_size" - android:gravity="center" - android:paddingLeft="0dp" - android:paddingTop="0dp" - android:paddingRight="0dp" - android:paddingBottom="0dp" - android:focusable="false" - android:clickable="false" - android:singleLine="true" - android:ellipsize="none" - style="?attr/suggestionWordStyle" /> diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml index 1e7a3844e..ed387e5b2 100644 --- a/java/res/layout/input_view.xml +++ b/java/res/layout/input_view.xml @@ -41,10 +41,10 @@ android:id="@+id/suggestion_strip_view" android:layoutDirection="ltr" android:layout_width="match_parent" - android:layout_height="@dimen/suggestions_strip_height" + android:layout_height="@dimen/config_suggestions_strip_height" android:gravity="center_vertical" - android:paddingRight="@dimen/suggestions_strip_padding" - android:paddingLeft="@dimen/suggestions_strip_padding" + android:paddingRight="@dimen/config_suggestions_strip_horizontal_padding" + android:paddingLeft="@dimen/config_suggestions_strip_horizontal_padding" style="?attr/suggestionStripViewStyle" /> <!-- To ensure that key preview popup is correctly placed when the current system locale is diff --git a/java/res/layout/key_preview_klp.xml b/java/res/layout/key_preview.xml index 160aeb9a9..16d4c72c3 100644 --- a/java/res/layout/key_preview_klp.xml +++ b/java/res/layout/key_preview.xml @@ -21,7 +21,7 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/keyboard_key_feedback_klp" android:minWidth="32dp" android:gravity="center" + style="?attr/keyPreviewTextViewStyle" /> diff --git a/java/res/layout/more_keys_keyboard.xml b/java/res/layout/more_keys_keyboard.xml index 6637117e0..f3795afdc 100644 --- a/java/res/layout/more_keys_keyboard.xml +++ b/java/res/layout/more_keys_keyboard.xml @@ -22,11 +22,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - style="?attr/moreKeysKeyboardContainerStyle" + android:orientation="vertical" > <com.android.inputmethod.keyboard.MoreKeysKeyboardView - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" android:id="@+id/more_keys_keyboard_view" 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 8659f0761..0869992c9 100644 --- a/java/res/layout/more_suggestions.xml +++ b/java/res/layout/more_suggestions.xml @@ -22,16 +22,15 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - style="?attr/moreKeysKeyboardContainerStyle" + android:orientation="vertical" > <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_width="wrap_content" android:layout_height="wrap_content" - latin:keyLetterSize="@dimen/suggestion_text_size" - latin:keyLabelSize="@dimen/suggestion_text_size" - latin:keyHintLetterRatio="@fraction/more_suggestions_info_ratio" + latin:keyLetterSize="@dimen/config_suggestion_text_size" + latin:keyLabelSize="@dimen/config_suggestion_text_size" + latin:keyHintLetterRatio="@fraction/config_more_suggestions_info_ratio" latin:keyHintLetterColor="@android:color/white" /> </LinearLayout> diff --git a/java/res/layout/research_feedback_fragment_layout.xml b/java/res/layout/research_feedback_fragment_layout.xml index 505a1e8d9..fb5c27815 100644 --- a/java/res/layout/research_feedback_fragment_layout.xml +++ b/java/res/layout/research_feedback_fragment_layout.xml @@ -84,40 +84,32 @@ android:checked="false" android:text="@string/research_feedback_include_recording_label" /> <LinearLayout + style="?android:attr/buttonBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:divider="?android:attr/dividerHorizontal" - android:showDividers="beginning" - android:dividerPadding="0dip"> - <LinearLayout - style="?android:attr/buttonBarStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:layoutDirection="locale" - android:measureWithLargestChild="true"> - <Button - android:id="@+id/research_feedback_cancel_button" - android:layout_width="wrap_content" - android:layout_gravity="left" - android:layout_weight="1" - android:maxLines="2" - style="?android:attr/buttonBarButtonStyle" - android:textSize="14sp" - android:text="@string/research_feedback_cancel" - android:layout_height="wrap_content" /> - <Button - android:id="@+id/research_feedback_send_button" - android:layout_width="wrap_content" - android:layout_gravity="right" - android:layout_weight="1" - android:maxLines="2" - style="?android:attr/buttonBarButtonStyle" - android:textSize="14sp" - android:text="@string/research_feedback_send" - android:layout_height="wrap_content" /> - </LinearLayout> + android:orientation="horizontal" + android:layoutDirection="locale" + android:measureWithLargestChild="true"> + <Button + android:id="@+id/research_feedback_cancel_button" + android:layout_width="wrap_content" + android:layout_gravity="left" + android:layout_weight="1" + android:maxLines="2" + style="?android:attr/buttonBarButtonStyle" + android:textSize="14sp" + android:text="@string/research_feedback_cancel" + android:layout_height="wrap_content" /> + <Button + android:id="@+id/research_feedback_send_button" + android:layout_width="wrap_content" + android:layout_gravity="right" + android:layout_weight="1" + android:maxLines="2" + style="?android:attr/buttonBarButtonStyle" + android:textSize="14sp" + android:text="@string/research_feedback_send" + android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> </ScrollView> diff --git a/java/res/layout/seek_bar_dialog.xml b/java/res/layout/seek_bar_dialog.xml index a47e9a038..e723ad9bb 100644 --- a/java/res/layout/seek_bar_dialog.xml +++ b/java/res/layout/seek_bar_dialog.xml @@ -33,7 +33,7 @@ <TextView android:id="@+id/seek_bar_dialog_value" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="20dp"/> + android:textSize="20sp"/> </LinearLayout> <SeekBar android:id="@+id/seek_bar_dialog_bar" diff --git a/java/res/layout/setup_steps_title.xml b/java/res/layout/setup_steps_title.xml index e3694bfe0..9ee8693f8 100644 --- a/java/res/layout/setup_steps_title.xml +++ b/java/res/layout/setup_steps_title.xml @@ -21,7 +21,5 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/setup_title" - style="@style/setupTitleStyle" - android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" /> + style="@style/setupTitleStyle" /> </merge> diff --git a/java/res/layout/setup_welcome_title.xml b/java/res/layout/setup_welcome_title.xml index af7053a37..2c3b48919 100644 --- a/java/res/layout/setup_welcome_title.xml +++ b/java/res/layout/setup_welcome_title.xml @@ -21,9 +21,7 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/setup_welcome_title" - style="@style/setupTitleStyle" - android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" /> + style="@style/setupTitleStyle" /> <TextView android:id="@+id/setup_welcome_description" android:text="@string/setup_welcome_additional_description" diff --git a/java/res/layout/suggestion_divider.xml b/java/res/layout/suggestion_divider.xml index a8b78c082..149095147 100644 --- a/java/res/layout/suggestion_divider.xml +++ b/java/res/layout/suggestion_divider.xml @@ -23,5 +23,6 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:src="@drawable/suggestions_strip_divider" + android:contentDescription="@null" android:padding="0dp" android:gravity="center" /> diff --git a/java/res/layout/suggestion_info.xml b/java/res/layout/suggestion_info.xml deleted file mode 100644 index 0aa26000d..000000000 --- a/java/res/layout/suggestion_info.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. -*/ ---> - -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="6dp" - android:textColor="@android:color/white" - style="?attr/suggestionWordStyle" /> diff --git a/java/res/layout/suggestion_word.xml b/java/res/layout/suggestion_word.xml deleted file mode 100644 index c82a13c99..000000000 --- a/java/res/layout/suggestion_word.xml +++ /dev/null @@ -1,39 +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. -*/ ---> - -<!-- Provide a haptic feedback by ourselves based on the keyboard settings. - We just need to ignore the system's haptic feedback settings. --> -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:minWidth="@dimen/suggestion_min_width" - android:textSize="@dimen/suggestion_text_size" - android:gravity="center" - android:paddingLeft="@dimen/suggestion_padding" - android:paddingTop="0dp" - android:paddingRight="@dimen/suggestion_padding" - android:paddingBottom="0dp" - android:hapticFeedbackEnabled="false" - android:focusable="false" - android:clickable="false" - android:singleLine="true" - android:ellipsize="none" - style="?attr/suggestionWordStyle" /> diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml index cbf31e6dc..0b614993b 100644 --- a/java/res/layout/suggestions_strip.xml +++ b/java/res/layout/suggestions_strip.xml @@ -19,12 +19,43 @@ --> <merge - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" -> + xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:id="@+id/suggestions_strip" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" /> + <LinearLayout + android:id="@+id/add_to_dictionary_strip" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="invisible"> + <TextView + android:id="@+id/word_to_save" + android:layout_width="match_parent" + android:layout_height="match_parent" + style="?attr/suggestionWordStyle" /> + <include + layout="@layout/suggestion_divider" /> + <TextView + android:id="@+id/hint_add_to_dictionary" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textAlignment="viewStart" + style="?attr/suggestionWordStyle" /> + </LinearLayout> + <LinearLayout + android:id="@+id/important_notice_strip" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TextView + android:id="@+id/important_notice_title" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="6sp" + android:textSize="16sp" + style="?attr/suggestionWordStyle" /> + </LinearLayout> </merge> diff --git a/java/res/layout/user_dictionary_add_word.xml b/java/res/layout/user_dictionary_add_word.xml index bbf9b1b5b..615fde589 100644 --- a/java/res/layout/user_dictionary_add_word.xml +++ b/java/res/layout/user_dictionary_add_word.xml @@ -52,48 +52,39 @@ android:hint="@string/user_dict_settings_add_word_hint" android:imeOptions="flagNoFullscreen" android:inputType="textNoSuggestions" - android:maxLength="@integer/user_dictionary_max_word_length" > + android:maxLength="@integer/config_user_dictionary_max_word_length" > <requestFocus /> </EditText> <LinearLayout + style="?android:attr/buttonBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:divider="?android:attr/dividerHorizontal" - android:dividerPadding="0dip" - android:orientation="vertical" - android:showDividers="beginning" > + android:measureWithLargestChild="true" + android:orientation="horizontal" > - <LinearLayout - style="?android:attr/buttonBarStyle" - android:layout_width="match_parent" + <Button + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dip" android:layout_height="wrap_content" - android:measureWithLargestChild="true" - android:orientation="horizontal" > - - <Button - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_gravity="start" - android:layout_weight="1" - android:maxLines="2" - android:onClick="onClickCancel" - android:text="@string/cancel" - android:textSize="14sp" /> + android:layout_gravity="start" + android:layout_weight="1" + android:maxLines="2" + android:onClick="onClickCancel" + android:text="@string/cancel" + android:textSize="14sp" /> - <Button - style="?android:attr/buttonBarButtonStyle" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_gravity="end" - android:layout_weight="1" - android:maxLines="2" - android:onClick="onClickConfirm" - android:text="@string/user_dict_settings_add_dialog_confirm" - android:textSize="14sp" /> - </LinearLayout> + <Button + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_weight="1" + android:maxLines="2" + android:onClick="onClickConfirm" + android:text="@string/user_dict_settings_add_dialog_confirm" + android:textSize="14sp" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/java/res/layout/user_dictionary_add_word_fullscreen.xml b/java/res/layout/user_dictionary_add_word_fullscreen.xml index 219485b66..9bcb189b4 100644 --- a/java/res/layout/user_dictionary_add_word_fullscreen.xml +++ b/java/res/layout/user_dictionary_add_word_fullscreen.xml @@ -30,7 +30,7 @@ android:hint="@string/user_dict_settings_add_word_hint" android:imeOptions="flagNoFullscreen" android:inputType="textNoSuggestions" - android:maxLength="@integer/user_dictionary_max_word_length" > + android:maxLength="@integer/config_user_dictionary_max_word_length" > <requestFocus /> </EditText> @@ -61,7 +61,7 @@ android:hint="@string/user_dict_settings_add_shortcut_hint" android:imeOptions="flagNoFullscreen" android:inputType="textNoSuggestions" - android:maxLength="@integer/user_dictionary_max_word_length" /> + android:maxLength="@integer/config_user_dictionary_max_word_length" /> <TextView android:id="@+id/user_dictionary_add_locale_label" diff --git a/java/res/layout/user_dictionary_item.xml b/java/res/layout/user_dictionary_item.xml index 56bad7743..b8d48b56d 100644 --- a/java/res/layout/user_dictionary_item.xml +++ b/java/res/layout/user_dictionary_item.xml @@ -19,10 +19,11 @@ android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeight" - android:paddingEnd="?android:attr/scrollbarSize" > + android:paddingEnd="?android:attr/scrollbarSize" + android:baselineAligned="false" > <RelativeLayout - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:padding="6dip" android:layout_weight="1" > diff --git a/java/res/mipmap-hdpi/ic_launcher_keyboard.png b/java/res/mipmap-hdpi/ic_launcher_keyboard.png Binary files differdeleted file mode 100644 index 36b1ccae2..000000000 --- a/java/res/mipmap-hdpi/ic_launcher_keyboard.png +++ /dev/null diff --git a/java/res/mipmap-mdpi/ic_launcher_keyboard.png b/java/res/mipmap-mdpi/ic_launcher_keyboard.png Binary files differdeleted file mode 100644 index 67ef189ff..000000000 --- a/java/res/mipmap-mdpi/ic_launcher_keyboard.png +++ /dev/null diff --git a/java/res/mipmap-xhdpi/ic_launcher_keyboard.png b/java/res/mipmap-xhdpi/ic_launcher_keyboard.png Binary files differdeleted file mode 100644 index b33208332..000000000 --- a/java/res/mipmap-xhdpi/ic_launcher_keyboard.png +++ /dev/null diff --git a/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png b/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png Binary files differdeleted file mode 100644 index acc424fe2..000000000 --- a/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png +++ /dev/null diff --git a/java/res/raw/main_de.dict b/java/res/raw/main_de.dict Binary files differindex 69796bbaa..3cbf7105d 100644 --- a/java/res/raw/main_de.dict +++ b/java/res/raw/main_de.dict diff --git a/java/res/raw/main_en.dict b/java/res/raw/main_en.dict Binary files differindex 09b69927f..49adc9a19 100644 --- a/java/res/raw/main_en.dict +++ b/java/res/raw/main_en.dict diff --git a/java/res/raw/main_es.dict b/java/res/raw/main_es.dict Binary files differindex 261ab8c87..fe24cd624 100644 --- a/java/res/raw/main_es.dict +++ b/java/res/raw/main_es.dict diff --git a/java/res/raw/main_fr.dict b/java/res/raw/main_fr.dict Binary files differindex 0e5a71360..94d1b9670 100644 --- a/java/res/raw/main_fr.dict +++ b/java/res/raw/main_fr.dict diff --git a/java/res/raw/main_it.dict b/java/res/raw/main_it.dict Binary files differindex e161c2475..ff11b9798 100644 --- a/java/res/raw/main_it.dict +++ b/java/res/raw/main_it.dict diff --git a/java/res/raw/main_pt_br.dict b/java/res/raw/main_pt_br.dict Binary files differindex 21bbe7c67..9fa50442a 100644 --- a/java/res/raw/main_pt_br.dict +++ b/java/res/raw/main_pt_br.dict diff --git a/java/res/raw/main_ru.dict b/java/res/raw/main_ru.dict Binary files differindex 7dec62425..0f08f1735 100644 --- a/java/res/raw/main_ru.dict +++ b/java/res/raw/main_ru.dict diff --git a/java/res/values-af/strings-config-important-notice.xml b/java/res/values-af/strings-config-important-notice.xml new file mode 100644 index 000000000..edd54d6f0 --- /dev/null +++ b/java/res/values-af/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Leer uit jou kommunikasie en getikte data om voorstelle te verbeter"</string> +</resources> diff --git a/java/res/values-af/strings-talkback-descriptions.xml b/java/res/values-af/strings-talkback-descriptions.xml new file mode 100644 index 000000000..3529e5a5d --- /dev/null +++ b/java/res/values-af/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Koppel \'n kopstuk om te hoor hoe wagwoordsleutels hardop gesê word."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Huidige teks is %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Geen teks is ingevoer nie"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> korrigeer <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> voer outokorrigering uit"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Sleutelkode %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift aan (tik om te deaktiveer)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Kasslot aan (tik om te deaktiveer)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Vee uit"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simbole"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letters"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Nommers"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Instellings"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Spasie"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Steminvoer"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emosiekone"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Keer terug"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Soek"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Verander taal"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Volgende"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Vorige"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift geaktiveer"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Bokas-slot geaktiveer"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift gedeaktiveer"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Simboolmodus"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Lettermodus"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Foonmodus"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Foonsimbool-modus"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Sleutelbord is versteek"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Wys tans <xliff:g id="KEYBOARD_MODE">%s</xliff:g>-sleutelbord"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum en tyd"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-pos"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"boodskappe"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"nommer"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"foon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teks"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"tyd"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Onlangse emosiekone"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Mense"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Voorwerpe"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natuur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Plekke"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simbole"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emosiekone"</string> +</resources> diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 045e97d94..ce7cb18fc 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Stelsel se verstek"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Gepersonaliseerde voorstelle"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbeltik op spasiebalk voeg \'n punt in, gevolg deur \'n spasie"</string> <string name="auto_cap" msgid="1719746674854628252">"Outohoofletters"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Wys gebaarspoor"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamiese sweefvoorskou"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Sien die voorgestelde woord tydens gebare"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gestoor"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Koppel \'n kopstuk om te hoor hoe wagwoordsleutels hardop gesê word."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Huidige teks is %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Geen teks ingevoer nie"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> korrigeer <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> voer outokorreksie uit"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Sleutelkode %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift aan (tik om te deaktiveer)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Kasslot aan (tik om te deaktiveer)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Vee uit"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simbole"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Nommers"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Instellings"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Oortjie"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spasie"</string> - <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_search" msgid="1247236163755920808">"Soek"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Verander taal"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Volgende"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorige"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift geaktiveer"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kasslot geaktiveer"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift gedeaktiveer"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Simboolmodus"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Lettermodus"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Foonmodus"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Foonsimbool-modus"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Sleutelbord versteek"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Wys <xliff:g id="MODE">%s</xliff:g>-sleutelbord"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum en tyd"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-pos"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"boodskappe"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"nommer"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"foon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teks"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"tyd"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frasegebaar"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Voer spasies tydens gebare in deur na die spasiesleutel te gly"</string> <string name="voice_input" msgid="3583258583521397548">"Steminvoerinstellings"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Op hoofsleutelbord"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Op simbolesleutelbord"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Af"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofoon op hoofsleutelbord"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofoon op simbolesleutelbord"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Steminvoer is gedeaktiveer"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen steminvoermetodes geaktiveer nie. Gaan taal- en invoerinstellings na."</string> <string name="configure_input_method" msgid="373356270290742459">"Stel invoermetodes op"</string> <string name="language_selection_title" msgid="1651299598555326750">"Invoertale"</string> <string name="send_feedback" msgid="1780431884109392046">"Stuur terugvoer"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engels (VK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spaans (VS)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engels (VK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engels (VS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spaans (VS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Tradisioneel)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engels (VK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engels (VS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spaans (VS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisioneel)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyrillies)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latyns)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Geen taal nie (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lees eksterne woordeboeklêer"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Geen woordeboeklêers in die aflaaiselsvouer nie"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Kies \'n woordeboeklêer om te installeer"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Moet hierdie lêer regtig vir <xliff:g id="LOCALE_NAME">%s</xliff:g> geïnstalleer word?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Moet hierdie lêer regtig vir <xliff:g id="LANGUAGE_NAME">%s</xliff:g> geïnstalleer word?"</string> <string name="error" msgid="8940763624668513648">"Daar was \'n fout"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Lys kontaktewoordeboek"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Lys persoonlike woordeboek"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Lys gebruikergeskiedeniswoordeboek"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Lys personaliseringwoordeboek"</string> <string name="button_default" msgid="3988017840431881491">"Verstek"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Welkom by <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"met Gebaar-tik"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Verfris"</string> <string name="last_update" msgid="730467549913588780">"Laas opgedateer"</string> <string name="message_updating" msgid="4457761393932375219">"Kontroleer vir opdaterings"</string> - <string name="message_loading" msgid="8689096636874758814">"Laai tans…"</string> + <string name="message_loading" msgid="5638680861387748936">"Laai tans…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Hoofwoordeboek"</string> <string name="cancel" msgid="6830980399865683324">"Kanselleer"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Instellings"</string> <string name="install_dict" msgid="180852772562189365">"Installeer"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Kanselleer"</string> <string name="delete_dict" msgid="756853268088330054">"Vee uit"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Die gekose taal op jou mobiele toestel het \'n beskikbare woordeboek.<br/> Ons beveel aan dat die <xliff:g id="LANGUAGE">%1$s</xliff:g>-woordeboek <b>afgelaai</b> word om jou tikervaring te verbeter.<br/> <br/> Dit kan \'n minuut of twee neem om oor 3G af te laai. Heffings kan dalk geld as jy nie \'n <b>onbeperkte dataplan</b> het nie.<br/> As jy onseker oor jou dataplan is, beveel ons aan dat jy \'n Wi-Fi-verbinding soek om outomaties te begin aflaai.<br/> <br/> Wenk: Jy kan woordeboeke aflaai en verwyder deur te gaan na <b>Taal en invoer</b> in die <b>Instellings</b>-kieslys van jou mobiele toestel."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Die gekose taal op jou mobiele toestel het \'n beskikbare woordeboek.<br/> Ons beveel aan dat die <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-woordeboek <b>afgelaai</b> word om jou tikervaring te verbeter.<br/> <br/> Dit kan \'n minuut of twee duur om oor 3G af te laai. Heffings kan dalk geld as jy nie \'n <b>onbeperkte dataplan</b> het nie.<br/> As jy onseker is oor watter dataplan jy het, beveel ons aan dat jy \'n Wi-Fi-verbinding soek om outomaties te begin aflaai.<br/> <br/> Wenk: Jy kan woordeboeke aflaai en verwyder deur te gaan na <b>Taal en invoer</b> in die <b>Instellings</b>-kieslys van jou mobiele toestel."</string> <string name="download_over_metered" msgid="1643065851159409546">"Laai nou af (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Laai oor Wi-Fi af"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"\'n Woordeboek is vir <xliff:g id="LANGUAGE">%1$s</xliff:g> beskikbaar"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"\'n Woordeboek is beskikbaar vir <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Druk om te hersien en af te laai"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Laai tans af: voorstelle vir <xliff:g id="LANGUAGE">%1$s</xliff:g> sal binnekort gereed wees."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Laai tans af: voorstelle vir <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sal binnekort gereed wees."</string> <string name="version_text" msgid="2715354215568469385">"Weergawe <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Voeg by"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Voeg by woordeboek"</string> diff --git a/java/res/values-am/strings-config-important-notice.xml b/java/res/values-am/strings-config-important-notice.xml new file mode 100644 index 000000000..db537dc25 --- /dev/null +++ b/java/res/values-am/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"የአስተያየት ጥቆማዎችን ለማሻሻል ከእርስዎ ግንኙነቶች እና የተተየበ ውሂብ ይማሩ"</string> +</resources> diff --git a/java/res/values-am/strings-talkback-descriptions.xml b/java/res/values-am/strings-talkback-descriptions.xml new file mode 100644 index 000000000..2d6f0e56d --- /dev/null +++ b/java/res/values-am/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"የይለፍ ቃል ቁልፎች ጮክ ተብለው ሲነገሩ ለመስማት የጆሮ ማዳመጫ ይሰኩ።"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"የአሁኑ ፅሁፍ %s ነው"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"ምንም ፅሁፍ አልገባም"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>ን ወደ <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> ያርመዋል"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> የራስ ሰር እርማት ያከናውናል"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"የቁልፍ ኮድ %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"ቀይር"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"መቀያየሪያ ቁልፍ በርቷል (ለማሰናከል መታ ያድርጉ)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"አብይ ፊደል ማድረጊያ ቁልፍ በርቷል (ለማሰናክል ነካ ያድርጉ)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"ሰርዝ"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"ምልክቶች"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"ደብዳቤዎች"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"ቁጥሮች"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"ቅንብሮች"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"ትር"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"ባዶ ቦታ"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"የድምፅ ግቤት"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"ኢሞጂ"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"ተመለስ"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"ፈልግ"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"ነጥብ"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"ቋንቋ ቀይር"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"ቀጣይ"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"ቀዳሚ"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"መቀያየሪያ ቁልፍ ነቅቷል"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"አብይ ፊደል ማድረጊያ ቁልፍ ነቅቷል"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"መቀያየሪያ ቁልፍ ተሰናክሏል"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"የምልክቶች ሁኔታ"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"የደብዳቤዎች ሁኔታ"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"የስልክ ሁኔታ"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"የስልክ ምልክቶች ሁኔታ"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"የቁልፍ ሰሌዳ ተደብቋል"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"የ<xliff:g id="KEYBOARD_MODE">%s</xliff:g> የቁልፍ ሰሌዳ በማሳየት ላይ"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ቀን"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ቀን እና ሰዓት"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ኢሜይል"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"መልዕክት መላላክ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"ቁጥር"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"ስልክ"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"ፅሁፍ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ጊዜ"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"ዩአርኤል"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"የቅርብ ጊዜዎቹ"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"ሰዎች"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"ነገሮች"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"ተፈጥሮ"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"ቦታዎች"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"ምልክቶች"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"ስሜት ገላጭ አዶዎች"</string> +</resources> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index 0b81034f4..32eed413b 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"የስርዓት ነባሪ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"የዕውቂያ ስም ጠቁም"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ከዕውቂያዎች ለጥቆማዎች እና ማስተካከያዎች ስሞች ተጠቀም"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"ግላዊ የጥቆማ አስተያየቶች"</string> <string name="use_double_space_period" msgid="8781529969425082860">"የድርብ-ክፍተት ነጥብ"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"የክፍተት አሞሌው ላይ ሁለቴ መታ ማድረግ አንድ ነጥብ እና ክፍተት አስከትሎ ያስገባል"</string> <string name="auto_cap" msgid="1719746674854628252">"ራስ-ሰር አቢይ ማድረግ"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"ምልክት የሚሄድበት መንገድ አሳይ"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"ተለዋዋጭ ተንሳፋፊ ቅድመ-እይታ"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ምልክት እየሰጡ ሳሉ በአስተያየት የተጠቆመው ቃል ይመልከቱ"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ተቀምጧል"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"የይለፍቃል ቁልፎች ጮክ በለው ሲነገሩ ለመስማት የጆሮ ማዳመጫ ሰካ::"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"የአሁኑ ፅሁፍ %s ነው"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"ምንም ፅሁፍ አልገባም"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>ን ወደ <xliff:g id="CORRECTED">%3$s</xliff:g> ያርመዋል"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> ራስ-ሰር እርማትን ያከናውናል"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"የቁልፍ ኮድ%d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"ቀይር"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"ቅያር በርቷል (ለማሰናክል ንካ)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"አቢያት ማድረጊያ ቁልጥ በርቷል (ለማሰናክል ንካ)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"ሰርዝ"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"ምልክቶች"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"ደብዳቤዎች"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"ቁጥሮች"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"ቅንብሮች"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"ትር"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"ባዶ ቦታ"</string> - <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_search" msgid="1247236163755920808">"ፍለጋ"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"ነጥብ"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"ቋንቋ ቀይር"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"ቀጣይ"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"ቀዳሚ"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"ቅያር ቁልፍ ነቅቷል"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"አቢያት ማድረጊያ ነቅቷል"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ቅያር ተሰናክሏል"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"የምልክቶች ሁኔታ ላይ"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"የደብዳቤዎች ሁኔታ ላይ"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"የስልክ ሁኔታ ላይ"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"የስልክ ምልክቶች ሁኔታ ላይ"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"የቁልፍ ሰሌዳ ተደብቋል"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"የ<xliff:g id="MODE">%s</xliff:g> ቁልፍ ሰሌዳን በማሳየት ላይ"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ቀን"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ቀን እና ሰዓት"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"ኢሜይል"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"አላላክ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"ቁጥር"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"ስልክ"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"ፅሁፍ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ጊዜ"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"ዩ አር ኤል"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"የሐረግ ምልክት"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ምልክት በሚሰጡበት ጊዜ ወደ ክፍተት ቁልፉ በማንሸራተት ክፍተቶችን ያስገቡ"</string> <string name="voice_input" msgid="3583258583521397548">"የድምፅ ግቤት ቁልፍ"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"በዋናቁልፍ ሰሌዳ ላይ"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"በምልክቶች ቁልፍ ሰሌዳ ላይ"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"ውጪ"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ድምፅ ማጉያ በዋናው ቁልፍሰሌዳው ላይ"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"የድምፅ ማጉያ ምልክትበቁልፍ ሰሌዳላይ"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"የድምፅ ግቤት ቦዝኗል"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ምንም የግቤት ስልቶች አልነቁም። የቋንቋ እና የግቤት ቅንብሮችን ይፈትሹ።"</string> <string name="configure_input_method" msgid="373356270290742459">"ግቤት ሜተዶችን አዋቀር"</string> <string name="language_selection_title" msgid="1651299598555326750">"ቋንቋዎች አግቤት"</string> <string name="send_feedback" msgid="1780431884109392046">"ግብረ-መልስ ላክ"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"እንግሊዘኛ (የታላቋ ብሪታንያ)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"እንግሊዘኛ (ዩ.ኤስ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"ስፓኒሽኛ (ዩኤስ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"እንግሊዘኛ (ዩናይትድ ኪንግደም) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"እንግሊዘኛ (አሜሪካ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"ስፓኒሽኛ (ዩኤስ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (ተለምዷዊ)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"እንግሊዝኛ (ዩኬ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"እንግሊዝኛ (አሜሪካ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"ስፓኒሽ (አሜሪካ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ተለምዷዊ)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ሳይሪሊክ)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ላቲን)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"ምንም ቋንቋ (ፊደላት)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"ፊደላት (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"ፊደላት (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"ውጫዊ የመዝገበቃላት ፋይል አንብብ"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"በውርዶች አቃፊው ውስጥ ምንም የመዝገበ-ፋይሎች የሉም"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"የሚጭኑት የመዝገበ-ቃላት ፋይል ይምረጡ"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"እውን ይሄ ፋይል ለ<xliff:g id="LOCALE_NAME">%s</xliff:g> ይጫን?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"እውን ይሄ ፋይል ለ<xliff:g id="LANGUAGE_NAME">%s</xliff:g> ይጫን?"</string> <string name="error" msgid="8940763624668513648">"ስህተት ተከስቶ ነበር"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"የእውቂያዎች መዝገበ-ቃላትን ዝርዝር ይፍጠሩ"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"የግል መዝገበ-ቃላትን ዝርዝር ይፍጠሩ"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"የተጠቃሚ ታሪክ መዝገበ-ቃላትን ዝርዝር ይፍጠሩ"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"የግላዊነት ማላበሻ መዝገበ-ቃላትን ዝርዝር ይፍጠሩ"</string> <string name="button_default" msgid="3988017840431881491">"ነባሪ"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"እንኳን ወደ <xliff:g id="APPLICATION_NAME">%s</xliff:g> በደህና መጡ"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"በጣት ምልክት መተየብ"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"አድስ"</string> <string name="last_update" msgid="730467549913588780">"ለመጨረሻ ጊዜ የተዘመነው"</string> <string name="message_updating" msgid="4457761393932375219">"ዝማኔዎችን በመፈለግ ላይ"</string> - <string name="message_loading" msgid="8689096636874758814">"በመጫን ላይ..."</string> + <string name="message_loading" msgid="5638680861387748936">"በመጫን ላይ…"</string> <string name="main_dict_description" msgid="3072821352793492143">"ዋና መዝገበ-ቃላት"</string> - <string name="cancel" msgid="6830980399865683324">"ሰርዝ"</string> + <string name="cancel" msgid="6830980399865683324">"ይቅር"</string> + <string name="go_to_settings" msgid="3876892339342569259">"ቅንብሮች"</string> <string name="install_dict" msgid="180852772562189365">"ጫን"</string> - <string name="cancel_download_dict" msgid="7843340278507019303">"ሰርዝ"</string> + <string name="cancel_download_dict" msgid="7843340278507019303">"ይቅር"</string> <string name="delete_dict" msgid="756853268088330054">"ሰርዝ"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"ተንቀሳቃሽ መሣሪያዎ ላይ ለተመረጠው ቋንቋ የሚሆን መዝገበ-ቃላት ይገኛል።<br/> የትየባ ተሞክሮዎን ለማሻሻል የ<xliff:g id="LANGUAGE">%1$s</xliff:g> መዝገበ-ቃላቱን <b>እንዲያወርዱ</b> እንመክራለን።<br/> <br/> ውርዱ በ3ጂ ላይ አንድ ወይም ሁለት ደቂቃ ሊወስድ ይችላል። <b>ያልተገደበ የውሂብ ዕቅድ</b> ከሌለዎት ክፍያዎች መከፈል ሊኖርባቸው ይችላል።<br/> የትኛው የውሂብ ዕቅድ እንዳለዎት እርግጠኛ ካልሆኑ ውርዱን በራስ-ሰር ለመጀመር የWi-Fi ግንኙነት እንዲፈልጉ እንመክራለን።<br/> <br/> ጠቃሚ ምክር፦ የተንቀሳቃሽ መሣሪያዎ <b>ቅንብሮች</b> ምናሌ ውስጥ ወዳለው <b>ቋንቋ እና ግብዓት</b> በመሄድ መዝገበ-ቃላትን ማውረድና ማስወገድ ይችላሉ።"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"በተንቀሳቃሽ መሣሪያዎ ላይ ለተመረጠው ቋንቋ የሚሆን መዝገበ-ቃላት ይገኛል።<br/> የትየባ ተሞክሮዎን ለማሻሻል የ<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> መዝገበ-ቃላቱን <b>እንዲያወርዱ</b> እንመክራለን።<br/> <br/> ማውረድ በ3ጂ ላይ አንድ ወይም ሁለት ደቂቃ ሊወስድ ይችላል። <b>ያልተገደበ የውሂብ ዕቅድ</b> ከሌለዎት ክፍያዎች መከፈል ሊኖርባቸው ይችላል።<br/> የትኛው የውሂብ ዕቅድ እንዳለዎት እርግጠኛ ካልሆኑ ውርዱን በራስ-ሰር ለመጀመር የWi-Fi ግንኙነት እንዲፈልጉ እንመክራለን።<br/> <br/> ጠቃሚ ምክር፦ የተንቀሳቃሽ መሣሪያዎ <b>ቅንብሮች</b> ምናሌ ውስጥ ወዳለው <b>ቋንቋ እና ግብዓት</b> በመሄድ መዝገበ-ቃላትን ማውረድና ማስወገድ ይችላሉ።"</string> <string name="download_over_metered" msgid="1643065851159409546">"አሁን አውርድ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> ሜባ)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"በWi-Fi አውርድ"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"መዝገበ-ቃላት ለ<xliff:g id="LANGUAGE">%1$s</xliff:g> ይገኛል"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"የ<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> መዝገበ-ቃላት ማግኘት ይችላል"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"ለመገምገምና ለማውረድ ይጫኑ"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"በማውረድ ላይ፦ የ<xliff:g id="LANGUAGE">%1$s</xliff:g> ጥቆማ አስተያየቶች በቅርቡ ዝግጁ ይሆናሉ።"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"በማውረድ ላይ፦ ለ<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> የሚሰጡ ጥቆማዎች በቅርቡ ዝግጁ ይሆናሉ።"</string> <string name="version_text" msgid="2715354215568469385">"ሥሪት <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"አክል"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"ወደ መዝገበ-ቃላት አክል"</string> diff --git a/java/res/values-ar-sw600dp/donottranslate-config-spacing-and-punctuations.xml b/java/res/values-ar-sw600dp/donottranslate-config-spacing-and-punctuations.xml new file mode 100644 index 000000000..d7aca6fb4 --- /dev/null +++ b/java/res/values-ar-sw600dp/donottranslate-config-spacing-and-punctuations.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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 --> + <!-- U+061F: "؟" ARABIC QUESTION MARK + U+061B: "؛" ARABIC SEMICOLON --> + <string name="suggested_punctuations">!,؟,:,؛,\",\',(|),)|(,-,/,@,_</string> +</resources> diff --git a/java/res/values-iw/donottranslate.xml b/java/res/values-ar/donottranslate-config-spacing-and-punctuations.xml index 57de2538b..21bb3318f 100644 --- a/java/res/values-iw/donottranslate.xml +++ b/java/res/values-ar/donottranslate-config-spacing-and-punctuations.xml @@ -21,5 +21,8 @@ <!-- 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">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string> + <!-- U+061F: "؟" ARABIC QUESTION MARK + U+060C: "،" ARABIC COMMA + U+061B: "؛" ARABIC SEMICOLON --> + <string name="suggested_punctuations">!,؟,،,:,؛,\",(|),)|(,\',-,/,@,_</string> </resources> diff --git a/java/res/values-ar/strings-config-important-notice.xml b/java/res/values-ar/strings-config-important-notice.xml new file mode 100644 index 000000000..7af5f6d5c --- /dev/null +++ b/java/res/values-ar/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"التعلم من اتصالاتك والبيانات التي تكتبها لتحسين الاقتراحات"</string> +</resources> diff --git a/java/res/values-ar/strings-talkback-descriptions.xml b/java/res/values-ar/strings-talkback-descriptions.xml new file mode 100644 index 000000000..9d2eab5ae --- /dev/null +++ b/java/res/values-ar/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"يمكنك توصيل سماعة رأس لسماع مفاتيح كلمة المرور منطوقة بصوت عالٍ."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"النص الحالي هو %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"لم يتم إدخال نص"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> لتصحيح <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> إلى <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> لإجراء التصحيح التلقائي"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"رمز المفتاح %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift يعمل (انقر للتعطيل)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock يعمل (انقر للتعطيل)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"حذف"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"رموز"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"أحرف"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"أرقام"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"الإعدادات"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"مسافة"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"إدخال صوتي"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"رمز تعبيري"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"رجوع"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"بحث"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"نقطة"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"تبديل اللغة"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"التالي"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"السابق"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"تم تمكين Shift"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"تم تمكين Caps lock"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"تم تعطيل Shift"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"وضع الرموز"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"وضع الأحرف"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"وضع الهاتف"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"وضع رموز الهاتف"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"لوحة المفاتيح مخفية"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"إظهار لوحة مفاتيح <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"التاريخ"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"التاريخ والوقت"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"بريد إلكتروني"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"مراسلة"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"رقم"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"هاتف"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"نص"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"الوقت"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"عنوان URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"الحديثة"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"أشخاص"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"كائنات"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"الطبيعة"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"أماكن"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"رموز"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"رموز تعبيرية"</string> +</resources> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index da331196c..13aef2a67 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"الإعداد الافتراضي للنظام"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"اقتراح أسماء جهات الاتصال"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"استخدام الأسماء من جهات الاتصال للاقتراحات والتصحيحات"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"اقتراحات مخصصة"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطة المسافة المزدوجة"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"يؤدي النقر نقرًا مزدوجًا على مفتاح المسافة إلى إدخال نقطة متبوعة بمسافة"</string> <string name="auto_cap" msgid="1719746674854628252">"أحرف كبيرة تلقائيًا"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"عرض مسار الإيماءة"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"معاينة نصوص متحركة ديناميكية"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"مشاهدة الكلمة المقترحة أثناء الإيماءة"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"يمكنك توصيل سماعة رأس لسماع مفاتيح كلمة المرور منطوقة بصوت عالٍ."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"النص الحالي هو %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"لم يتم إدخال نص"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> لتصحيح <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> إلى <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> للتصحيح التلقائي"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"رمز المفتاح %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"العالي"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift يعمل (انقر للتعطيل)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock يعمل (انقر للتعطيل)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"حذف"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"الرموز"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"أحرف"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"أرقام"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"الإعدادات"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"علامة تبويب"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"مسافة"</string> - <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_search" msgid="1247236163755920808">"بحث"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"نقطة"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"تبديل اللغة"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"التالي"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"السابق"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"تم تمكين Shift"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"تم تمكين Caps lock"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"تم تعطيل Shift"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"وضع الرموز"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"وضع الأحرف"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"وضع الهاتف"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"وضع رموز الهاتف"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"لوحة المفاتيح مخفية"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"إظهار لوحة مفاتيح <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"التاريخ"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"التاريخ والوقت"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"البريد الإلكتروني"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"المراسلة"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"الرقم"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"الهاتف"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"النص"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"الوقت"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"عنوان URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"عبارة الإيماء"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"إدخال مسافات خلال الإيماءات من خلال تمرير مفتاح المسافة"</string> <string name="voice_input" msgid="3583258583521397548">"مفتاح الإدخال الصوتي"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"لوحة مفاتيح رئيسية"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"لوحة مفاتيح الرموز"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"إيقاف"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ميكروفون على لوحة مفاتيح رئيسية"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"ميكروفون على لوحة مفاتيح الرموز"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"الإدخال الصوتي مُعطل"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"لم يتم تمكين أي أساليب إدخال صوتي. تحقق من إعدادات اللغة والإدخال."</string> <string name="configure_input_method" msgid="373356270290742459">"تهيئة طرق الإدخال"</string> <string name="language_selection_title" msgid="1651299598555326750">"لغات الإدخال"</string> <string name="send_feedback" msgid="1780431884109392046">"إرسال تعليقات"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"الإنجليزية (المملكة المتحدة)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"الإنجليزية (الولايات المتحدة)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"الإسبانية (الأميركية)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"الإنجليزية (المملكة المتحدة) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"الإنجليزية (الولايات المتحدة) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"الإسبانية (الأمريكية) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (التقليدية)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"الإنجليزية (المملكة المتحدة) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"الإنجليزية (الولايات المتحدة) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"الإسبانية (الولايات المتحدة) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (التقليدية)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (السريلية)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (اللاتينية)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"بدون لغة (أبجدية)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"الأبجدية (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"الأبجدية (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"قراءة ملف قاموس خارجي"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"ليست هناك ملفات قواميس في مجلد التنزيلات"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"تحديد ملف قاموس للتثبيت"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"هل تريد حقًا تثبيت هذا الملف للغة <xliff:g id="LOCALE_NAME">%s</xliff:g>؟"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"هل تريد حقًا تثبيت هذا الملف للغة <xliff:g id="LANGUAGE_NAME">%s</xliff:g>؟"</string> <string name="error" msgid="8940763624668513648">"حدث خطأ"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"عرض جهات الاتصال"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"تفريغ المعجم الشخصي"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"تفريغ معجم سجل المستخدم"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"تفريغ معجم التخصيص"</string> <string name="button_default" msgid="3988017840431881491">"الافتراضية"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"مرحبا بكم في <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"مع الكتابة بالإشارة"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"تحديث"</string> <string name="last_update" msgid="730467549913588780">"تاريخ آخر تحديث"</string> <string name="message_updating" msgid="4457761393932375219">"جارٍ البحث عن تحديثات"</string> - <string name="message_loading" msgid="8689096636874758814">"جارٍ التحميل..."</string> + <string name="message_loading" msgid="5638680861387748936">"جارٍ التحميل…"</string> <string name="main_dict_description" msgid="3072821352793492143">"القاموس الرئيسي"</string> <string name="cancel" msgid="6830980399865683324">"إلغاء"</string> + <string name="go_to_settings" msgid="3876892339342569259">"إعدادات"</string> <string name="install_dict" msgid="180852772562189365">"تثبيت"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"إلغاء"</string> <string name="delete_dict" msgid="756853268088330054">"حذف"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"اللغة المحددة على جهازك الجوال تشتمل على قاموس متوفر.<br/> نوصي <b>بتنزيل</b> قاموس <xliff:g id="LANGUAGE">%1$s</xliff:g> لتحسين تجربة الكتابة.<br/> <br/> قد يستغرق التنزيل دقيقة أو دقيقتين أكثر من المدة التي يستغرقها التنزيل عبر شبكة الجيل الثالث. قد تنطبق الرسوم إذا لم تكن مشتركًا في <b>خطة البيانات غير المحدودة</b>.<br/> إذا لم تكن متأكدًا من خطة البيانات المتوفرة لديك، فنحن نوصي بالبحث عن اتصال Wi-Fi لبدء عملية التنزيل تلقائيًا.<br/> <br/> نصيحة: يمكنك تنزيل القواميس وإزالتها عن طريق الانتقال إلى <b>اللغة والإدخال</b> في قائمة <b>إعدادات</b> في جهازك الجوَّال."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"اللغة المحددة على جهازك الجوّال تشتمل على قاموس متوفر.<br/> نوصي <b>بتنزيل</b> قاموس <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> لتحسين تجربة الكتابة.<br/> <br/> قد يستغرق التنزيل دقيقة أو دقيقتين عبر شبكة الجيل الثالث. قد تنطبق الرسوم إذا لم تكن مشتركًا في <b>خطة البيانات غير المحدودة</b>.<br/> إذا لم تكن متأكدًا من خطة البيانات المتوفرة لديك، فنحن نوصي بالبحث عن اتصال Wi-Fi لبدء عملية التنزيل تلقائيًا.<br/> <br/> نصيحة: يمكنك تنزيل القواميس وإزالتها من خلال الانتقال إلى <b>اللغة والإدخال</b> في القائمة <b>إعدادات</b> في جهازك الجوّال."</string> <string name="download_over_metered" msgid="1643065851159409546">"التنزيل الآن (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> ميغابايت)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"التنزيل عبر شبكة Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"هناك قاموس متوفر للغة <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"هناك قاموس متوفر للغة <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"اضغط للمراجعة والتنزيل"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"جارٍ التنزيل: ستتوفر اقتراحات للغة <xliff:g id="LANGUAGE">%1$s</xliff:g> بعد قليل."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"جارٍ التنزيل: ستتوفر اقتراحات للغة <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> قريبًا."</string> <string name="version_text" msgid="2715354215568469385">"الإصدار <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"إضافة"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"إضافة إلى القاموس"</string> diff --git a/java/res/values-az-rAZ/strings-action-keys.xml b/java/res/values-az-rAZ/strings-action-keys.xml new file mode 100644 index 000000000..513712c40 --- /dev/null +++ b/java/res/values-az-rAZ/strings-action-keys.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2013, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="label_go_key" msgid="4033615332628671065">"Keç"</string> + <string name="label_next_key" msgid="5586407279258592635">"Növbəti"</string> + <string name="label_previous_key" msgid="1421141755779895275">"Öncəki"</string> + <string name="label_done_key" msgid="7564866296502630852">"Hazırdır"</string> + <string name="label_send_key" msgid="482252074224462163">"Göndər"</string> + <string name="label_pause_key" msgid="2225922926459730642">"Pauza"</string> + <string name="label_wait_key" msgid="5891247853595466039">"Gözlə"</string> +</resources> diff --git a/java/res/values-be/strings-appname.xml b/java/res/values-az-rAZ/strings-appname.xml index 2f9593bdc..2fcb76c69 100644 --- a/java/res/values-be/strings-appname.xml +++ b/java/res/values-az-rAZ/strings-appname.xml @@ -20,8 +20,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="5940510615957428904">"Клавіятура Android (AOSP)"</string> - <string name="spell_checker_service_name" msgid="1254221805440242662">"Iнструмент праверкi правапiсу для Android (AOSP)"</string> - <string name="english_ime_settings" msgid="5760361067176802794">"Налады клавіятуры Android (AOSP)"</string> - <string name="android_spell_checker_settings" msgid="6123949487832861885">"Налады інструмента праверкі правапісу для Android (AOSP)"</string> + <string name="english_ime_name" msgid="5940510615957428904">"Android Klaviatura (AOYP)"</string> + <string name="spell_checker_service_name" msgid="1254221805440242662">"Android Orfoqrafik Yoxlanış (AOYP)"</string> + <string name="english_ime_settings" msgid="5760361067176802794">"Android Klaviatura Parametrləri (AOYP)"</string> + <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Orfoqrafik Yoxlanış Parametrləri (AOYP)"</string> </resources> diff --git a/java/res/values-az-rAZ/strings-config-important-notice.xml b/java/res/values-az-rAZ/strings-config-important-notice.xml new file mode 100644 index 000000000..a5f1c6128 --- /dev/null +++ b/java/res/values-az-rAZ/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Əlaqələrdən və təkliflərin inkişafı üçün yazdığınız datadan öyrənin "</string> +</resources> diff --git a/java/res/values-az-rAZ/strings-talkback-descriptions.xml b/java/res/values-az-rAZ/strings-talkback-descriptions.xml new file mode 100644 index 000000000..c5abc5cf5 --- /dev/null +++ b/java/res/values-az-rAZ/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Parolu səsli eşitmək üçün qulaqlığı taxın."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Cari mətn %s\'dir"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Mətn daxil edilməyib"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> sözünü <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> sözü ilə əvəzləyərək düzəldir"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> avto-korreksiyanı həyata keçirir"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"%d açar kodu"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Sürüşdürmə"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Sürüşdürmə aktivdir (deaktiv etmək üçün klikləyin)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Böyük hərf kilidi aktivdir (deaktiv etmək üçün klikləyin)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Sil"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simvollar"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Hərflər"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Nömrələr"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Ayarlar"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Boşluq"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Səs daxiletməsi"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Geri qayıt"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Axtarış"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Nöqtə"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Dil keçidi"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Növbəti"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Əvvəlki"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Sürüşdürmə aktivdir"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Böyük hərf kilidi aktivdir"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Sürüşdürmə deaktivdir"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Simvol rejimi"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Hərf rejimi"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefon rejimi"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefon simvol rejimi"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Gizlədilmiş klaviatura"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> klaviaturası göstərilir"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"tarix"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"gün və tarix"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"E-poçt"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mesajlaşma"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"nömrə"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"mesaj"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"vaxt"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Sonuncular"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Adamlar"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Obyektlər"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Təbiə"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Yerlər"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simvollar"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikonlar"</string> +</resources> diff --git a/java/res/values-az-rAZ/strings.xml b/java/res/values-az-rAZ/strings.xml new file mode 100644 index 000000000..5a40e9f14 --- /dev/null +++ b/java/res/values-az-rAZ/strings.xml @@ -0,0 +1,204 @@ +<?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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="english_ime_input_options" msgid="3909945612939668554">"Daxiletmə seçimləri"</string> + <string name="english_ime_research_log" msgid="8492602295696577851">"Araşdırma Jurnalı Əmrləri"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakt adlarına baxın"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Orfoqrafik yoxlanış kontakt siyahınızdakı qeydlərdən istifadə edir"</string> + <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrasiyalı klikləmə"</string> + <string name="sound_on_keypress" msgid="6093592297198243644">"Klikləmə səsi"</string> + <string name="popup_on_keypress" msgid="123894815723512944">"Klikləmədə popup"</string> + <string name="general_category" msgid="1859088467017573195">"Ümumi"</string> + <string name="correction_category" msgid="2236750915056607613">"Mətn korreksiyası"</string> + <string name="gesture_typing_category" msgid="497263612130532630">"Jestlərlə yazma"</string> + <string name="misc_category" msgid="6894192814868233453">"Digər seçənəklər"</string> + <string name="advanced_settings" msgid="362895144495591463">"Qabaqcıl ayarlar"</string> + <string name="advanced_settings_summary" msgid="4487980456152830271">"Ekspertlər üçün seçimlər"</string> + <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Digər daxiletmə metodlarına keçin"</string> + <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Dil keçid düyməsi başqa daxiletmə metodlarını da əhatə edir"</string> + <string name="show_language_switch_key" msgid="5915478828318774384">"Dil keçidi düyməsi"</string> + <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Çoxsaylı daxiletmə dilləri aktivləşdikdə göstər"</string> + <string name="sliding_key_input_preview" msgid="6604262359510068370">"Slayd indikatorunu göstər"</string> + <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Sürüşdürmə və ya Simvol düymələrinə keçərkən vizual işarəni göstər"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Klaviş popup kənarlaşdırılmasında gecikmə"</string> + <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Gecikmə yoxdur"</string> + <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> millisaniyə"</string> + <string name="settings_system_default" msgid="6268225104743331821">"Sistem defoltu"</string> + <string name="use_contacts_dict" msgid="4435317977804180815">"Kontakt adları təklif edin"</string> + <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Təklif və korreksiya üçün Kontaktlardakı adlardan istifadə edin"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Fərdiləşmiş təkliflər"</string> + <string name="use_double_space_period" msgid="8781529969425082860">"İkili boşluq periodu"</string> + <string name="use_double_space_period_summary" msgid="6532892187247952799">"Boşluqdakı iki klik boşluqdan sonra pauza daxil edir"</string> + <string name="auto_cap" msgid="1719746674854628252">"Avtomatik böyük hərfləşmə"</string> + <string name="auto_cap_summary" msgid="7934452761022946874">"Hər cümlənin ilk sözünü böyük hərflə yaz"</string> + <string name="edit_personal_dictionary" msgid="3996910038952940420">"Şəxsi lüğət"</string> + <string name="configure_dictionaries_title" msgid="4238652338556902049">"Əlavə lüğətlər"</string> + <string name="main_dictionary" msgid="4798763781818361168">"Əsas lüğət"</string> + <string name="prefs_show_suggestions" msgid="8026799663445531637">"Korreksiya təkliflərini göstər"</string> + <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Yazarkən təklif edilən sözləri ekranda göstər"</string> + <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Həmişə göstər"</string> + <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Portret rejimində göstər"</string> + <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Həmişə gizlət"</string> + <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Təhqiredici sözləri əngəlləyin"</string> + <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Potensial təhqiredici sözlər təklif etməyin"</string> + <string name="auto_correction" msgid="7630720885194996950">"Avtomatik-korreksiya"</string> + <string name="auto_correction_summary" msgid="5625751551134658006">"Boşluq və punktuasiya avtomatik yanlış sözləri düzəldir"</string> + <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Deaktiv"</string> + <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Orta"</string> + <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Aqressiv"</string> + <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Çox aqressiv"</string> + <string name="bigram_prediction" msgid="1084449187723948550">"Növbəti-söz təklifləri"</string> + <string name="bigram_prediction_summary" msgid="3896362682751109677">"Təkliflər edilməsində əvvəlki sözdən istifadə et"</string> + <string name="gesture_input" msgid="826951152254563827">"Jestlərlə yazmağı aktiv et"</string> + <string name="gesture_input_summary" msgid="9180350639305731231">"Hərflər üzərində sürüşdürərək söz daxil edin"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"Jest izini göstər"</string> + <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamik üzmə önizləməsi"</string> + <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Jest zamanı təklif edilmiş sözə baxın"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Jest bildirin"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Jest zamanı boşluq düyməsinə toxunmaqla boşluq daxil edin"</string> + <string name="voice_input" msgid="3583258583521397548">"Səs daxiletmə klavişi"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Heç bir səs daxiletmə metodu aktiv deyil. Dil və daxiletmə ayarlarını yoxlayın."</string> + <string name="configure_input_method" msgid="373356270290742459">"Daxiletmə üsullarını sazla"</string> + <string name="language_selection_title" msgid="1651299598555326750">"Daxiletmə dilləri"</string> + <string name="send_feedback" msgid="1780431884109392046">"Cavab rəyi göndərin"</string> + <string name="select_language" msgid="3693815588777926848">"Daxiletmə dilləri"</string> + <string name="hint_add_to_dictionary" msgid="573678656946085380">"Yadda saxlamaq üçün yenidən toxunun"</string> + <string name="has_dictionary" msgid="6071847973466625007">"Lüğət mövcuddur"</string> + <string name="prefs_enable_log" msgid="6620424505072963557">"İstifadəçi əks əlaqəsini aktiv et"</string> + <string name="prefs_description_log" msgid="7525225584555429211">"İstifadə statistikası və xəta haqqında hesabatları avtomatik göndərməklə daxiletmə metodu redaktəsini təkmilləşdirməyə kömək edin."</string> + <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatura teması"</string> + <string name="subtype_en_GB" msgid="88170601942311355">"İngilis (BK)"</string> + <string name="subtype_en_US" msgid="6160452336634534239">"İngilis (ABŞ)"</string> + <string name="subtype_es_US" msgid="5583145191430180200">"İspan (ABŞ)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"İngilis (Britaniya) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"İngilis (Amerika) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"İspan (Amerika) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Ənənəvi)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Kiril)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latın)"</string> + <string name="subtype_no_language" msgid="7137390094240139495">"Dil yoxdur (Əlifba)"</string> + <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Əlifba (QWERTY)"</string> + <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Əlifba (QWERTZ)"</string> + <string name="subtype_no_language_azerty" msgid="8144348527575640087">"Əlifba (AZERTY)"</string> + <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Əlifba (Dvorak)"</string> + <string name="subtype_no_language_colemak" msgid="5837418400010302623">"Əlifba (Colemak)"</string> + <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Əlifba (PC)"</string> + <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string> + <string name="keyboard_color_scheme" msgid="9192934113872818070">"Rəng sxemi"</string> + <string name="keyboard_color_scheme_white" msgid="6684064723850265438">"Ağ"</string> + <string name="keyboard_color_scheme_blue" msgid="2488527224758177593">"Mavi"</string> + <string name="custom_input_styles_title" msgid="8429952441821251512">"Xüsusi daxiletmə üslubları"</string> + <string name="add_style" msgid="6163126614514489951">"Stil əlavə et"</string> + <string name="add" msgid="8299699805688017798">"Əlavə et"</string> + <string name="remove" msgid="4486081658752944606">"Ləğv et"</string> + <string name="save" msgid="7646738597196767214">"Yadda saxla"</string> + <string name="subtype_locale" msgid="8576443440738143764">"Dil"</string> + <string name="keyboard_layout_set" msgid="4309233698194565609">"Tərtibat"</string> + <string name="custom_input_style_note_message" msgid="8826731320846363423">"Xüsusi daxiletmə üslubunuz istifadəyə başlamazdan əvvəl aktivləşdirilməlidir. Aktiv etmək istəyirsiniz?"</string> + <string name="enable" msgid="5031294444630523247">"Aktiv et"</string> + <string name="not_now" msgid="6172462888202790482">"İndi yox"</string> + <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Eyni daxiletmə üslubu artıq mövcuddur: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string> + <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Rahat işləmə rejimi"</string> + <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Klavişi uzun müddət basmada gecikmə"</string> + <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrasiyalı klikləmə müddəti"</string> + <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Səsli klikləmə səsi"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Xarici lüğət faylını oxuyun"</string> + <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Endirmə Qovluğunda heç bir lüğət faylı yoxdur"</string> + <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Yükləmək üçün lüğət faylı seçin"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> üçün faylı quraşdırmaq istədiyinizə əminsiniz?"</string> + <string name="error" msgid="8940763624668513648">"Xəta var idi"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Kontaktlar lüğətini toplayın"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Şəxsi lüğəti toplayın"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"İstifadəçi tarixi lüğətini toplayın"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Fərdiləşmə lüğətini toplayın"</string> + <string name="button_default" msgid="3988017840431881491">"Defolt"</string> + <string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> təbiqinə xoş gəlmisiniz"</string> + <string name="setup_welcome_additional_description" msgid="8150252008545768953">"Jest Yazısı ilə"</string> + <string name="setup_start_action" msgid="8936036460897347708">"Başlayın"</string> + <string name="setup_next_action" msgid="371821437915144603">"Növbəti addım"</string> + <string name="setup_steps_title" msgid="6400373034871816182">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> quraşdırılır"</string> + <string name="setup_step1_title" msgid="3147967630253462315">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> tətbiqini aktivləşdir"</string> + <string name="setup_step1_instruction" msgid="2578631936624637241">"Lütfən, \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" tətbiqini Dil və daxiletmə parametrlərinizdə yoxlayın. Bununla tətbiqin cihazınızda işləməsinə icazə veriləcək."</string> + <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> artıq sizin Dil və daxiletmə parametrlərinizdə aktivləşdirildi, beləliklə da bu mərhələ tamamlandı. İndi isə növbəti mərhələyə eçin!"</string> + <string name="setup_step1_action" msgid="4366513534999901728">"Parametrlərdə aktivləşdir"</string> + <string name="setup_step2_title" msgid="6860725447906690594">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> tətbiqinə keçin"</string> + <string name="setup_step2_instruction" msgid="9141481964870023336">"Sonra, \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" tətbiqini aktiv mətn-daxiletmə metodu olaraq seçin."</string> + <string name="setup_step2_action" msgid="1660330307159824337">"Daxil metodlarına keç"</string> + <string name="setup_step3_title" msgid="3154757183631490281">"Təbrik edirik, tam hazırsınız!"</string> + <string name="setup_step3_instruction" msgid="8025981829605426000">"İndi siz <xliff:g id="APPLICATION_NAME">%s</xliff:g> ilə bütün sevimli tətbiqlərinizdə yaza bilərsiniz."</string> + <string name="setup_step3_action" msgid="600879797256942259">"Əlavə dillər quraşdır"</string> + <string name="setup_finish_action" msgid="276559243409465389">"Sona çatdı"</string> + <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Tətbiq ikonasını göstər"</string> + <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Başlatma panelində tətbiq ikonasını göstər"</string> + <string name="app_name" msgid="6320102637491234792">"Lüğət Provayderi"</string> + <string name="dictionary_provider_name" msgid="3027315045397363079">"Lüğət Provayderi"</string> + <string name="dictionary_service_name" msgid="6237472350693511448">"Lüğət Xidməti"</string> + <string name="download_description" msgid="6014835283119198591">"Lüğət yeniləmə məlumatı"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"Əlavə lüğətlər"</string> + <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Lüğət mövcuddur"</string> + <string name="dictionary_settings_summary" msgid="5305694987799824349">"Lüğət üçün ayarlar"</string> + <string name="user_dictionaries" msgid="3582332055892252845">"İstifadəçi lüğətləri"</string> + <string name="default_user_dict_pref_name" msgid="1625055720489280530">"İstifadəçi lüğəti"</string> + <string name="dictionary_available" msgid="4728975345815214218">"Lüğət mövcuddur"</string> + <string name="dictionary_downloading" msgid="2982650524622620983">"Hazırda endirilir"</string> + <string name="dictionary_installed" msgid="8081558343559342962">"Quraşdırılıb"</string> + <string name="dictionary_disabled" msgid="8950383219564621762">"Quraşdırılıb, deaktiv edilib"</string> + <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Lüğət xidmətinə bağlantı problemi"</string> + <string name="no_dictionaries_available" msgid="8039920716566132611">"Lüğət mövcud deyil"</string> + <string name="check_for_updates_now" msgid="8087688440916388581">"Təzələ"</string> + <string name="last_update" msgid="730467549913588780">"Son yeniləmə"</string> + <string name="message_updating" msgid="4457761393932375219">"Güncəlləmələr yoxlanılır"</string> + <string name="message_loading" msgid="5638680861387748936">"Yüklənir..."</string> + <string name="main_dict_description" msgid="3072821352793492143">"Əsas lüğət"</string> + <string name="cancel" msgid="6830980399865683324">"Ləğv et"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Ayarlar"</string> + <string name="install_dict" msgid="180852772562189365">"Quraşdırın"</string> + <string name="cancel_download_dict" msgid="7843340278507019303">"Ləğv et"</string> + <string name="delete_dict" msgid="756853268088330054">"Sil"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobil telefonunuzda seçilmiş dilin əlçatımlı lüğəti var. Daha rahat yazmaq üçün <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> lüğətini endirməyinizi məsləhət görürük. Lüğətin endirilməsi 3G üzərindən bir-iki dəqiqə vaxt ala bilər. Limitsiz data planınızın olmadığı halda, data ödənişləri də tətbiq edilə bilər. Əgər hansı data planına malik olmağınıza əmin deyilsinizsə, Sizə Wi-Fi bağlantısı üzərindən avtomatik endirməyi məsləhət görürük. İpucu: Lüğətləri endirmək və ya sistemdən silmək üçün mobil cihazınızın menyusunda Ayarlar>Dil>Daxiletmə bölməsinə keçə bilərsiniz."</string> + <string name="download_over_metered" msgid="1643065851159409546">"İndi endirin (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> + <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi ilə endir"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> üçün lüğət əlçatımlıdır"</string> + <string name="dict_available_notification_description" msgid="1075194169443163487">"Nəzərdən keçirmək və endirmək üçün klikləyin"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Endirmə: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> üçün təkliflər tezliklə hazır olacaq."</string> + <string name="version_text" msgid="2715354215568469385">"<xliff:g id="VERSION_NUMBER">%1$s</xliff:g> nömrəli versiya"</string> + <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Əlavə edin"</string> + <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Lüğətə əlavə edin"</string> + <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"İfadə"</string> + <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"Daha çox seçim"</string> + <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Daha az seçim"</string> + <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OK"</string> + <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Söz:"</string> + <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Qısayol:"</string> + <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Dil:"</string> + <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Bir söz yazın"</string> + <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Könüllü qısayol"</string> + <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Sözü redaktə edin"</string> + <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Düzəliş edin"</string> + <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Silin"</string> + <string name="user_dict_settings_empty_text" msgid="558499587532668203">"İstifadəçi lüğətinizdə heç bir söz yoxdur. Əlavə et (+) düyməsinə toxunmqla bir söz əlavə edin."</string> + <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"Bütün dillər üçün"</string> + <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"Digər dillər..."</string> + <string name="user_dict_settings_delete" msgid="110413335187193859">"Silin"</string> + <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> +</resources> diff --git a/java/res/values-be/bools.xml b/java/res/values-be-rBY/bools.xml index 840d20c21..840d20c21 100644 --- a/java/res/values-be/bools.xml +++ b/java/res/values-be-rBY/bools.xml diff --git a/java/res/values-be/strings-action-keys.xml b/java/res/values-be-rBY/strings-action-keys.xml index 91416c8b7..91416c8b7 100644 --- a/java/res/values-be/strings-action-keys.xml +++ b/java/res/values-be-rBY/strings-action-keys.xml diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml deleted file mode 100644 index 02972f07e..000000000 --- a/java/res/values-be/strings.xml +++ /dev/null @@ -1,253 +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. -*/ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="english_ime_input_options" msgid="3909945612939668554">"Параметры ўводу"</string> - <string name="english_ime_research_log" msgid="8492602295696577851">"Каманды гiсторыя даследаванняў"</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> - <string name="general_category" msgid="1859088467017573195">"Агульныя"</string> - <string name="correction_category" msgid="2236750915056607613">"Выпраўленне тэксту"</string> - <string name="gesture_typing_category" msgid="497263612130532630">"Набор жэстамі"</string> - <string name="misc_category" msgid="6894192814868233453">"Іншыя параметры"</string> - <string name="advanced_settings" msgid="362895144495591463">"Адмысловыя налады"</string> - <string name="advanced_settings_summary" msgid="4487980456152830271">"Функцыi для спецыялістаў"</string> - <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Перакл. да інш. спос. ув."</string> - <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Кнопка пераключэння мовы звязана i з iншымi спосабамi ўводу"</string> - <string name="show_language_switch_key" msgid="5915478828318774384">"Кнопка пераключэння мовы"</string> - <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Паказваць, калі ўключана некалькі моў ўводу"</string> - <string name="sliding_key_input_preview" msgid="6604262359510068370">"Iндыкатар слайд-шоу"</string> - <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Паказаць візуальны сігнал падчас слiзгання клавiш Shift або Symbol"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Затрым. скр. падк. клав."</string> - <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Няма затрымкі"</string> - <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Па змаўчанні"</string> - <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string> - <!-- no translation found for settings_system_default (6268225104743331821) --> - <skip /> - <string name="use_contacts_dict" msgid="4435317977804180815">"Прапан. імёны кантактаў"</string> - <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Выкарыстоўваць імёны са спісу кантактаў для прапаноў і выпраўл."</string> - <string name="use_double_space_period" msgid="8781529969425082860">"Падвойны iнтэрвал"</string> - <string name="use_double_space_period_summary" msgid="6532892187247952799">"Падвойнае нацiсканне на прабел ўстаўляе iнтэрвал з наступным прабелам"</string> - <string name="auto_cap" msgid="1719746674854628252">"Аўтаматычна рабіць вялікія літары"</string> - <string name="auto_cap_summary" msgid="7934452761022946874">"Пісаць з загалоўнай літары першае слова ў кожным сказе"</string> - <string name="edit_personal_dictionary" msgid="3996910038952940420">"Персанальны слоўнік"</string> - <string name="configure_dictionaries_title" msgid="4238652338556902049">"Дадатковыя слоўнікі"</string> - <string name="main_dictionary" msgid="4798763781818361168">"Асноўны слоўнік"</string> - <string name="prefs_show_suggestions" msgid="8026799663445531637">"Паказаць прапановы на выпраўленне"</string> - <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Паказваць прапанаваныя словы падчас набору тэксту"</string> - <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Заўсёды паказваць"</string> - <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Паказаць у партрэтным рэжыме"</string> - <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Заўседы хаваць"</string> - <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Блакіраваць абразлівыя словы"</string> - <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Не прапануйце патэнцыяльна абразлівых слоў"</string> - <string name="auto_correction" msgid="7630720885194996950">"Аўтавыпраўленне"</string> - <string name="auto_correction_summary" msgid="5625751551134658006">"Прабелы і пунктуацыйныя знакі дазваляюць аўтаматычна выпраўляць памылкова ўведзеныя словы"</string> - <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Адключаны"</string> - <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Сціплы"</string> - <!-- no translation found for auto_correction_threshold_mode_aggressive (7319007299148899623) --> - <skip /> - <!-- no translation found for auto_correction_threshold_mode_very_aggressive (1853309024129480416) --> - <skip /> - <string name="bigram_prediction" msgid="1084449187723948550">"Падказкi для наступнага слова"</string> - <string name="bigram_prediction_summary" msgid="3896362682751109677">"Выкарыстоўваць папярэдняе слова, каб атрымлiваць падказкi"</string> - <string name="gesture_input" msgid="826951152254563827">"Уключыць набор жэстамі"</string> - <string name="gesture_input_summary" msgid="9180350639305731231">"Уводзьце слова, перасоўваючы палец па літарах"</string> - <string name="gesture_preview_trail" msgid="3802333369335722221">"Паказаць след жэста"</string> - <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Дынамічны плаваючы прагляд"</string> - <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Праглядаць прапанаванае слова падчас жэсту"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Захаваныя"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Каб праслухаць паролi, падключыце гарнiтуру."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Бягучы тэкст %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Тэкст не ўведзены"</string> - <!-- no translation found for spoken_auto_correct (8005997889020109763) --> - <skip /> - <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> - <skip /> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Клавішны код %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Зрух"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift уключаны (націснiце, каб адключыць)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock уключаны (націснiце, каб адключыць)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Выдаліць"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Сімвалы"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Літары"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Лічбы"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Налады"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Укладка"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Прабел"</string> - <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_search" msgid="1247236163755920808">"Пошук"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Кропка"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Пераключыць мову"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Далей"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift уключаны"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock уключаны"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift адключаны"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Рэжым знакаў"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Рэжым лiтар"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Рэжым тэлефона"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Рэжым тэлефонных знакаў"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Клавіятура схавана"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Паказана клавiятура ў рэжыме \" <xliff:g id="MODE">%s</xliff:g>\""</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"дата"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"дата i час"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"электронная пошта"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"абмен паведамленнямі"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"нумар"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"тэлефон"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"тэкст"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"час"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> - <string name="voice_input" msgid="3583258583521397548">"Ключ галасавога ўводу"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На асн. клавіятуры"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"На сімв. клавіятуры"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Адключана"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Мік. на асн. клав."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Мік. на сімв. клав."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Галасавы набор адкл."</string> - <string name="configure_input_method" msgid="373356270290742459">"Налада метадаў уводу"</string> - <string name="language_selection_title" msgid="1651299598555326750">"Мовы ўводу"</string> - <string name="send_feedback" msgid="1780431884109392046">"Адправіць водгук"</string> - <string name="select_language" msgid="3693815588777926848">"Мовы ўводу"</string> - <string name="hint_add_to_dictionary" msgid="573678656946085380">"Дакраніцеся зноў, каб захаваць"</string> - <string name="has_dictionary" msgid="6071847973466625007">"Слоўнік даступны"</string> - <string name="prefs_enable_log" msgid="6620424505072963557">"Уключыць зваротную сувязь з карыстальнікамі"</string> - <string name="prefs_description_log" msgid="7525225584555429211">"Дапамажыце палепшыць гэты рэдактар метаду ўводу, аўтаматычна адпраўляючы статыстыку выкарыстання і справаздачы аб збоях Google."</string> - <string name="keyboard_layout" msgid="8451164783510487501">"Тэма клавіятуры"</string> - <string name="subtype_en_GB" msgid="88170601942311355">"Англійская (ЗК)"</string> - <string name="subtype_en_US" msgid="6160452336634534239">"Англійская (ЗША)"</string> - <string name="subtype_es_US" msgid="5583145191430180200">"iспанская (ЗША)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Англійская (Вялікабрытанія) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Англійская (ЗША) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"iспанская (ЗША) ( <xliff:g id="LAYOUT">%s</xliff:g> )"</string> - <!-- no translation found for subtype_nepali_traditional (9032247506728040447) --> - <skip /> - <!-- no translation found for subtype_no_language (7137390094240139495) --> - <skip /> - <!-- no translation found for subtype_no_language_qwerty (244337630616742604) --> - <skip /> - <!-- no translation found for subtype_no_language_qwertz (443066912507547976) --> - <skip /> - <!-- no translation found for subtype_no_language_azerty (8144348527575640087) --> - <skip /> - <!-- no translation found for subtype_no_language_dvorak (1564494667584718094) --> - <skip /> - <!-- no translation found for subtype_no_language_colemak (5837418400010302623) --> - <skip /> - <!-- no translation found for subtype_no_language_pcqwerty (5354918232046200018) --> - <skip /> - <!-- no translation found for subtype_emoji (7483586578074549196) --> - <skip /> - <string name="custom_input_styles_title" msgid="8429952441821251512">"Карыстальніцкія стылі ўводу"</string> - <string name="add_style" msgid="6163126614514489951">"Дадаць стыль"</string> - <string name="add" msgid="8299699805688017798">"Дадаць"</string> - <string name="remove" msgid="4486081658752944606">"Выдаліць"</string> - <string name="save" msgid="7646738597196767214">"Захаваць"</string> - <string name="subtype_locale" msgid="8576443440738143764">"Мова"</string> - <string name="keyboard_layout_set" msgid="4309233698194565609">"Раскладка"</string> - <string name="custom_input_style_note_message" msgid="8826731320846363423">"Карыстальніцкі метад уводу павінен быць уключаны, перш чым пачаць выкарыстоўваць яго. Жадаеце ўключыць яго зараз?"</string> - <string name="enable" msgid="5031294444630523247">"Уключыць"</string> - <string name="not_now" msgid="6172462888202790482">"Не цяпер"</string> - <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Такі метад уводу ўжо існуе: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string> - <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Рэжым даследвання выкарыстальнасці"</string> - <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Затрымка доўгага націску клавішы"</string> - <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Працягласць вібрацыі пры націску клавіш"</string> - <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Гучнасць гуку пры націску клавіш"</string> - <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Чытанне знешняга файла слоўніка"</string> - <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"У папцы загрузак няма файлаў слоўніка"</string> - <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Вылучыце файл слоўніка для ўсталёўкі"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Сапраўды ўсталяваць гэты файл на мове: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> - <string name="error" msgid="8940763624668513648">"Была памылка"</string> - <string name="button_default" msgid="3988017840431881491">"Па змаўчанні"</string> - <string name="setup_welcome_title" msgid="6112821709832031715">"Вітаем у прыкладанні <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> - <string name="setup_welcome_additional_description" msgid="8150252008545768953">"з уводам жэстамі"</string> - <string name="setup_start_action" msgid="8936036460897347708">"Пачаць"</string> - <string name="setup_next_action" msgid="371821437915144603">"Далей"</string> - <string name="setup_steps_title" msgid="6400373034871816182">"Наладка прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> - <string name="setup_step1_title" msgid="3147967630253462315">"Уключыць прыкладанне <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> - <string name="setup_step1_instruction" msgid="2578631936624637241">"Праверце прыкладанне \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" на сваёй мове і параметры ўводу. Гэта дасць магчымасць дазволіць яму працаваць на вашай прыладзе."</string> - <string name="setup_step1_finished_instruction" msgid="10761482004957994">"Прыкладанне <xliff:g id="APPLICATION_NAME">%s</xliff:g> ужо ўключана для вашай мовы і параметраў уводу, так што гэты крок зроблены. Пераходзім да наступнага!"</string> - <string name="setup_step1_action" msgid="4366513534999901728">"Уключыць у наладах"</string> - <string name="setup_step2_title" msgid="6860725447906690594">"Пераключыцца на прыкладанне <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string> - <string name="setup_step2_instruction" msgid="9141481964870023336">"Выберыце \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" як актыўны метад уводу тэксту."</string> - <string name="setup_step2_action" msgid="1660330307159824337">"Пераключэнне метадаў уводу"</string> - <string name="setup_step3_title" msgid="3154757183631490281">"Усё гатова!"</string> - <string name="setup_step3_instruction" msgid="8025981829605426000">"Цяпер вы можаце ўводзіць ўсе свае любімыя прыкладанні з iмем <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string> - <string name="setup_step3_action" msgid="600879797256942259">"Наладка дадатковых моў"</string> - <string name="setup_finish_action" msgid="276559243409465389">"Гатова"</string> - <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Паказаць значок прыкладання"</string> - <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Паказаць значок прыкладання ў панэлi запуску"</string> - <string name="app_name" msgid="6320102637491234792">"Пастаўшчык слоўніка"</string> - <string name="dictionary_provider_name" msgid="3027315045397363079">"Пастаўшчык слоўніка"</string> - <string name="dictionary_service_name" msgid="6237472350693511448">"Слоўнік"</string> - <string name="download_description" msgid="6014835283119198591">"Інфармацыя абнаўлення слоўніка"</string> - <string name="dictionary_settings_title" msgid="8091417676045693313">"Дадатковыя слоўнікі"</string> - <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Даступны слоўнік"</string> - <string name="dictionary_settings_summary" msgid="5305694987799824349">"Налады для слоўнікаў"</string> - <string name="user_dictionaries" msgid="3582332055892252845">"Карыстальніцкія слоўнікі"</string> - <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Карыстацкі слоўнік"</string> - <string name="dictionary_available" msgid="4728975345815214218">"Даступны слоўнік"</string> - <string name="dictionary_downloading" msgid="2982650524622620983">"Спампоўваецца зараз"</string> - <string name="dictionary_installed" msgid="8081558343559342962">"Усталявана"</string> - <string name="dictionary_disabled" msgid="8950383219564621762">"Усталявана, адключана"</string> - <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Праблема падключэння да слоўніка"</string> - <string name="no_dictionaries_available" msgid="8039920716566132611">"Слоўнікаў няма"</string> - <string name="check_for_updates_now" msgid="8087688440916388581">"Абнавіць"</string> - <string name="last_update" msgid="730467549913588780">"Апошняе абнаўленне"</string> - <string name="message_updating" msgid="4457761393932375219">"Праверка наяўнасці абнаўленняў"</string> - <string name="message_loading" msgid="8689096636874758814">"Загрузка..."</string> - <string name="main_dict_description" msgid="3072821352793492143">"Асноўны слоўнік"</string> - <string name="cancel" msgid="6830980399865683324">"Адмяніць"</string> - <string name="install_dict" msgid="180852772562189365">"Усталяваць"</string> - <string name="cancel_download_dict" msgid="7843340278507019303">"Адмена"</string> - <string name="delete_dict" msgid="756853268088330054">"Выдаліць"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Для выбранай мовы на мабільнай прыладзе ёсць слоўнік.<br/> Мы рэкамендуем <b>спампаваць</b> слоўнік для мовы \"<xliff:g id="LANGUAGE">%1$s</xliff:g>\" для паляпшэння зручнасці набору.<br/> <br/> Спампоўка можа заняць хвіліну або дзве ў 3G-сетках. Калі ў вас няма <b>безлімітнага тарыфнага плану перадачы дадзеных</b>, могуць прымяняцца дадатковыя плацяжы<br/>. Калі вы не ведаеце дакладна, які ў вас тарыфны план, мы рэкамендуем знайсці падлучэнне да сеткі Wi-Fi, каб пачаць аўтаматычную спампоўку.<br/> <br/> Парада: можна спампоўваць і выдаляць слоўнікі, перайшоўшы ў раздзел <b>Мова і ўвод</b> у меню <b>Налады</b> вашай мабільнай прылады."</string> - <string name="download_over_metered" msgid="1643065851159409546">"Спампаваць зараз (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>МБ)"</string> - <string name="do_not_download_over_metered" msgid="2176209579313941583">"Спампаваць праз Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Слоўнік для мовы \"<xliff:g id="LANGUAGE">%1$s</xliff:g>\""</string> - <string name="dict_available_notification_description" msgid="1075194169443163487">"Нацiснiце, каб прагледзець i спампаваць"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Загрузка: прапановы для мовы \"<xliff:g id="LANGUAGE">%1$s</xliff:g>\" хутка з\'явяцца."</string> - <string name="version_text" msgid="2715354215568469385">"Версія <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> - <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Дадаць"</string> - <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Дадаць у слоўнік"</string> - <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Выраз"</string> - <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"Дадатковыя параметры"</string> - <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Асн. параметры"</string> - <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OК"</string> - <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Слова:"</string> - <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Шлях хуткага доступу:"</string> - <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Мова:"</string> - <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Увядзіце слова"</string> - <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Дадатковы цэтлiк"</string> - <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Рэдагаваць слова"</string> - <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Рэдагаваць"</string> - <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Выдаліць"</string> - <string name="user_dict_settings_empty_text" msgid="558499587532668203">"У вашым карыстальніцкім слоўніку няма ніводнага слова. Вы можаце дадаваць словы, дакранаючыся да кнопкі \"+\" у пункце меню \"Дадаць\"."</string> - <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"Для ўсіх моў"</string> - <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"Іншыя мовы..."</string> - <string name="user_dict_settings_delete" msgid="110413335187193859">"Выдаліць"</string> - <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> -</resources> diff --git a/java/res/values-bg/strings-config-important-notice.xml b/java/res/values-bg/strings-config-important-notice.xml new file mode 100644 index 000000000..465ed85dd --- /dev/null +++ b/java/res/values-bg/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Ползване на съобщ. ви и въведени от вас данни за подобр. на предлож."</string> +</resources> diff --git a/java/res/values-bg/strings-talkback-descriptions.xml b/java/res/values-bg/strings-talkback-descriptions.xml new file mode 100644 index 000000000..c944c579f --- /dev/null +++ b/java/res/values-bg/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Включете слушалки, за да чуете клавишите за паролата на висок глас."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Текущият текст е „%s“"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Няма въведен текст"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"„<xliff:g id="KEY_NAME">%1$s</xliff:g>“ коригира „<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>“ на „<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>“"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"„<xliff:g id="KEY_NAME">%1$s</xliff:g>“ изпълнява автоматично коригиране"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Код на клавишa %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"„Shift“ е включен (докоснете за деактивиране)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"„Caps lock“ е включен (докоснете за деактивиране)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Delete"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Символи"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Букви"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Цифри"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Настройки"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Интервал"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Гласово въвеждане"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Емоджи"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Търсене"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Точка"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Превключване на езика"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Напред"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Назад"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"„Shift“ е активиран"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"„Caps Lock“ е активиран"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"„Shift“ е деактивиран"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Режим за символи"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Режим за букви"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Режим за телефонни номера"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Режим за символи на телефона"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Клавиатурата е скрита"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Показва се клавиатурата за <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"дати"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"дати и часове"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"имейл aдреси"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"съобщения"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"числа"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"телефонни номера"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"текст"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"часове"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL адреси"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Скорошни"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Хора"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Предмети"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Природа"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Места"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Символи"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Емотикони"</string> +</resources> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index c3fbd7982..562e71b4f 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Станд. за системата"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложения за контакти"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Използване на имена от „Контакти“ за предложения и поправки"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Персонализ. предложения"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Точка чрез двоен интервал"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Двукр. докосване на клав. за интервал вмъква точка, следвана от интервал"</string> <string name="auto_cap" msgid="1719746674854628252">"Автоматично поставяне на главни букви"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Следа на жестовете: Показване"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамична плаваща визуализация"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Преглед на предложената дума при използване на жестове"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Включете слушалки, за да чуете клавишите за паролата на висок глас."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Текущият текст е %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Няма въведен текст"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"„<xliff:g id="KEY">%1$s</xliff:g>“ коригира „<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>“ на „<xliff:g id="CORRECTED">%3$s</xliff:g>“"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"„<xliff:g id="KEY">%1$s</xliff:g>“ изпълнява автоматично коригиране"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Код на клавишa %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"„Shift“ е включен (докоснете за деактивиране)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"„Caps lock“ е включен (докоснете за деактивиране)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Символи"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Букви"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Цифри"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Настройки"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Интервал"</string> - <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_search" msgid="1247236163755920808">"Търсене"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Смяна на езика"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Следващ"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Предишен"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"„Shift“ е активиран"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"„Caps Lock“ е активиран"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"„Shift“ е деактивиран"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Режим за символи"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Режим за букви"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Режим за телефон"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Режим за символи на телефона"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Клавиатурата е скрита"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Показва се клавиатурата за <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"дата"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"дата и час"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"имейл aдреси"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"съобщения"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"числа"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"телефонни номера"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"текст"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"часа"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL адреси"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Жест за фрази"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"При жестове въвеждaйте интервали чрез плъзгане през съотв. клавиш"</string> <string name="voice_input" msgid="3583258583521397548">"Клавиш за гласово въвеждане"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На осн. клавиатура"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"На клав. на симв."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Изкл."</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Микр. на осн. клав."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Микр. на клав. на симв."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Глас. въвежд. е деакт."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Няма активирани методи на гласово въвеждане. Проверете настройките за език и въвеждане."</string> <string name="configure_input_method" msgid="373356270290742459">"Конфигуриране на въвеждането"</string> <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string> <string name="send_feedback" msgid="1780431884109392046">"Изпращане на отзиви"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"английски (Великобритания)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"английски (САЩ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"испански (САЩ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"английски (Великобр.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"английски (САЩ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"испански (САЩ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (традиционен)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"английски (Великобр.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"английски (САЩ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"испански (САЩ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (традиционна клавиатура)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (кирилица)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (латиница)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Без език (латиница)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Латиница (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Латиница (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Четене на файл за външен речник"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"В папката „Изтегляния“ няма файлове за речник"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Изберете файл за речника, който да инсталирате"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Наистина ли да се инсталира този файл за <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Наистина ли да се инсталира този файл за <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Възникна грешка"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Разтоварване на речника с контакти"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Разтоварване на частния речник"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Речник с потреб. ист.: Разтоварване"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Речник за персонализ.: Разтоварване"</string> <string name="button_default" msgid="3988017840431881491">"Стандартни"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Добре дошли в/ъв <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"с въвеждане чрез жест"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Опресняване"</string> <string name="last_update" msgid="730467549913588780">"Последна актуализация:"</string> <string name="message_updating" msgid="4457761393932375219">"Проверява се за актуализации"</string> - <string name="message_loading" msgid="8689096636874758814">"Зарежда се..."</string> + <string name="message_loading" msgid="5638680861387748936">"Зарежда се…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Основен речник"</string> <string name="cancel" msgid="6830980399865683324">"Отказ"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Настройки"</string> <string name="install_dict" msgid="180852772562189365">"Инсталиране"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Отказ"</string> <string name="delete_dict" msgid="756853268088330054">"Изтриване"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Налице е речник за избрания език на мобилното ви устройство.<br/> Препоръчваме ви <b>dда изтеглите</b> речника за <xliff:g id="LANGUAGE">%1$s</xliff:g>, за да подобрите практическата си работа при писане.<br/> <br/> Изтеглянето през 3G може да отнеме една до две минути. Възможно е да бъдете таксувани, ако нямате <b>неограничен план за данни</b>.<br/> В случай че не сте сигурни какъв е вашият план, ви препоръчваме да намерите Wi-Fi връзка, за да започнете автоматично изтеглянето.<br/> <br/> Съвет: Можете да изтегляте и премахвате речници, като отворите <b>Език и въвеждане</b> в менюто <b>Настройки</b> на мобилното си устройство."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Налице е речник за избрания език на мобилното ви устройство.<br/> Препоръчваме ви <b>да изтеглите</b> речника за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>, за да подобрите практическата си работа при писане.<br/> <br/> Изтеглянето през 3G може да отнеме една до две минути. Възможно е да бъдете таксувани, ако нямате <b>неограничен план за данни</b>.<br/> В случай че не сте сигурни какъв е вашият план, ви препоръчваме да намерите Wi-Fi връзка, за да започнете автоматично изтеглянето.<br/> <br/> Съвет: Можете да изтегляте и премахвате речници, като отворите <b>Език и въвеждане</b> в менюто <b>Настройки</b> на мобилното си устройство."</string> <string name="download_over_metered" msgid="1643065851159409546">"Изтегляне сега (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> МБ)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Изтегляне през Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"За <xliff:g id="LANGUAGE">%1$s</xliff:g> е налице речник"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"За <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> е налице речник"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Натиснете, за да прегледате и изтеглите"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Изтегля се: Предложенията за <xliff:g id="LANGUAGE">%1$s</xliff:g> ще бъдат готови скоро."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Изтегля се: Предложенията за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ще бъдат готови скоро."</string> <string name="version_text" msgid="2715354215568469385">"Версия <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Добавяне"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Добавяне в речника"</string> diff --git a/java/res/values-ca/strings-config-important-notice.xml b/java/res/values-ca/strings-config-important-notice.xml new file mode 100644 index 000000000..279314571 --- /dev/null +++ b/java/res/values-ca/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Considera comunicacions i dades introd. per millorar suggeriments"</string> +</resources> diff --git a/java/res/values-ca/strings-talkback-descriptions.xml b/java/res/values-ca/strings-talkback-descriptions.xml new file mode 100644 index 000000000..389200b43 --- /dev/null +++ b/java/res/values-ca/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Connecta uns auriculars per sentir les tecles que s\'utilitzen per introduir la contrasenya en veu alta."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"El text actual és %s."</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"No s\'ha introduït cap text."</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corregeix <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> per <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> executa la correcció automàtica."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Clau de codi %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Maj"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Maj activat (toca per desactivar)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Bloq Maj activat (toca per desactivar)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Suprimeix"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Símbols"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Lletres"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Números"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Configuració"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulador"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espai"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrada de veu"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Retorn"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Cerca"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Canvia l\'idioma"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Següent"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Anterior"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Maj activat"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Bloq Maj activat"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Maj desactivat"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Mode de símbols"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Mode de lletres"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Mode de telèfon"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Mode de símbols de telèfon"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"S\'ha amagat el teclat."</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Es mostra el teclat per a <xliff:g id="KEYBOARD_MODE">%s</xliff:g>."</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data i hora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"correu electrònic"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"missatgeria"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"número"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telèfon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"hora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recents"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Persones"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objectes"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natura"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Llocs"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Símbols"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticones"</string> +</resources> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index 0b9ee037e..e946ba78b 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Predeterm. del sist."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggereix noms de contactes"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilitza els noms de contactes per fer suggeriments i correccions"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Suggeriments personalitz."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punt amb doble espai"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Picar dues vegades la barra d\'espai insereix punt i espai blanc"</string> <string name="auto_cap" msgid="1719746674854628252">"Majúscules automàtiques"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostra el recorregut del gest"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Visualitz. prèvia dinàmica flotant"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Consulta la paraula suggerida mentre fas el gest"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Connecta un auricular per escoltar les claus de la contrasenya en veu alta."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"El text actual és %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"No s\'ha introduït cap text"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corregeix <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> per <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> aplica correccions automàtiques"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Clau de codi %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Maj"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Maj activat (pica per desactivar)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Bloq Maj activat (pica per desactivar)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Supr"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Símbols"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Lletres"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Números"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Configuració"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Pestanya"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espai"</string> - <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_search" msgid="1247236163755920808">"Cerca"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Canvia l\'idioma"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Següent"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Maj activat"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Bloq Maj activat"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Maj desactivat"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode de símbols"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode de lletres"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode de telèfon"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode de símbols de telèfon"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Teclat amagat"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Es mostra el teclat <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"data"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"data i hora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"correu electrònic"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"missatgeria"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"número"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telèfon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Formula el gest"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Per afegir espais als gestos, apropa el dit a la tecla d\'espai."</string> <string name="voice_input" msgid="3583258583521397548">"Tecla d\'entrada de veu"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Al teclat principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Al teclat de símbols"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Desactivada"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micròfon al teclat principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro en tecl. símb."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entrada de veu desactivada"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hi ha cap mètode d\'introducció activat. Comprova la configuració d\'Idioma i introducció de text."</string> <string name="configure_input_method" msgid="373356270290742459">"Configura mètodes d\'entrada"</string> <string name="language_selection_title" msgid="1651299598555326750">"Idiomes"</string> <string name="send_feedback" msgid="1780431884109392046">"Envia comentaris"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"Espanyol (EUA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Anglès (Regne Unit) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Anglès (Estats Units) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Espanyol (EUA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Anglès (Regne Unit) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Anglès (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Espanyol (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ciríl·lic)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (llatí)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Cap idioma (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lectura d\'un fitxer de diccionari extern"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"No hi ha cap fitxer de diccionari a la carpeta Baixades"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selecció d\'un fitxer de diccionari per instal·lar"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Realment vols instal·lar aquest fitxer per a <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Realment vols instal·lar aquest fitxer per a <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"S\'ha produït un error"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Genera el diccionari de contactes"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Esborrar el diccionari personal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Esborrar dicc. d\'histor. d\'usuaris"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Esborrar diccionari de personalitz."</string> <string name="button_default" msgid="3988017840431881491">"Predeterminat"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Et donem la benvinguda a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"amb Escriptura gestual"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualitza"</string> <string name="last_update" msgid="730467549913588780">"Última actualització"</string> <string name="message_updating" msgid="4457761393932375219">"S\'està comprovant si hi ha actualitzacions"</string> - <string name="message_loading" msgid="8689096636874758814">"S\'està carregant..."</string> + <string name="message_loading" msgid="5638680861387748936">"S\'està carregant..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Diccionari principal"</string> <string name="cancel" msgid="6830980399865683324">"Cancel·la"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Configuració"</string> <string name="install_dict" msgid="180852772562189365">"Instal·la"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancel·la"</string> <string name="delete_dict" msgid="756853268088330054">"Suprimeix"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Hi ha un diccionari disponible per a l\'idioma seleccionat al teu dispositiu mòbil.<br/> Et recomanem que <b>baixis</b> el diccionari de <xliff:g id="LANGUAGE">%1$s</xliff:g> per millorar la teva experiència d\'escriptura.<br/> <br/> La baixada pot trigar un parell de minuts en xarxes 3G. Si no tens un <b>pla de dades il·limitat</b>.<br/&gt, és possible que s\'apliquin càrrecs. Si no estàs segur de les característiques del teu pla de dades, et recomanem que cerquis una connexió Wi-Fi per iniciar la baixada automàticament.<br/> <br/> Consell: Pots baixar i suprimir diccionaris a la secció <b>Idioma i introducció de text</b> del menú <b>Configuració</b> del dispositiu mòbil."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Hi ha un diccionari disponible per a l\'idioma seleccionat al teu dispositiu mòbil.<br/> Et recomanem que <b>baixis</b> el diccionari per a <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> per millorar la teva experiència d\'escriptura.<br/> <br/> La baixada pot trigar un parell de minuts en xarxes 3G. Si no tens un <b>pla de dades il·limitat</b>,<br/> és possible que s\'apliquin càrrecs. Si no estàs segur de les característiques del teu pla de dades, et recomanem que cerquis una connexió Wi-Fi per iniciar la baixada automàticament.<br/> <br/>Consell: Pots baixar i suprimir diccionaris a la secció <b>Idioma i introducció de text</b> del menú <b>Configuració</b> del dispositiu mòbil."</string> <string name="download_over_metered" msgid="1643065851159409546">"Baixa ara (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Baixa mitjançant Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Hi ha un diccionari disponible per a l\'idioma: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Hi ha disponible un diccionari per a <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Prem per revisar-lo i per baixar-lo"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Baixada: els suggeriments per a <xliff:g id="LANGUAGE">%1$s</xliff:g> estaran disponibles ben aviat."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Baixada: els suggeriments per a <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> estaran disponibles ben aviat."</string> <string name="version_text" msgid="2715354215568469385">"Versió <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Afegeix"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Afegeix al diccionari"</string> diff --git a/java/res/values-cs/strings-config-important-notice.xml b/java/res/values-cs/strings-config-important-notice.xml new file mode 100644 index 000000000..8de51cc58 --- /dev/null +++ b/java/res/values-cs/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Zlepšovat návrhy na základě vaší komunikace a zadaných dat"</string> +</resources> diff --git a/java/res/values-cs/strings-talkback-descriptions.xml b/java/res/values-cs/strings-talkback-descriptions.xml new file mode 100644 index 000000000..7ba691c99 --- /dev/null +++ b/java/res/values-cs/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Chcete-li slyšet, které klávesy jste při zadávání hesla stiskli, připojte sluchátka."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Aktuální text je %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Není zadán žádný text"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Klávesou <xliff:g id="KEY_NAME">%1$s</xliff:g> opravíte <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Klávesou <xliff:g id="KEY_NAME">%1$s</xliff:g> provedete automatickou opravu"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kód klávesy %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Klávesa Shift je zapnutá (vypnete ji klepnutím)."</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Klávesa Caps Lock je zapnutá (vypnete ji klepnutím)."</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Smazat"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboly"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Písmena"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Čísla"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Nastavení"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Karta"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Mezerník"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Hlasový vstup"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emodži"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Vyhledávání"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Tečka"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Přepnout jazyk"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Další"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Předchozí"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Klávesa Shift je aktivní"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Klávesa Caps Lock je aktivní"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Klávesa Shift je neaktivní"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Režim symbolů"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Režim písmen"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Režim telefonu"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Režim telefonních symbolů"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klávesnice je skrytá"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Je zobrazena klávesnice <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum a čas"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"zprávy"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"čísla"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"čas"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"adresy URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Poslední"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Lidé"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Předměty"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Příroda"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Místa"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboly"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikony"</string> +</resources> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index c73e8ab1c..c093d8c50 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Výchozí nastavení"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhovat jména kontaktů"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Použít jména ze seznamu kontaktů k návrhům a opravám"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalizované návrhy"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tečka dvojitým mezerníkem"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvojím klepnutím na mezerník vložíte tečku následovanou mezerou."</string> <string name="auto_cap" msgid="1719746674854628252">"Velká písmena automaticky"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Zobrazovat stopu gesta"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamický plovoucí náhled"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Zobrazení navrhovaného slova při psaní gesty"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Chcete-li slyšet, které klávesy jste při zadávání hesla stiskli, připojte sluchátka."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Aktuální text je %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Není zadán žádný text"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Klávesou <xliff:g id="KEY">%1$s</xliff:g> opravíte <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Klávesa <xliff:g id="KEY">%1$s</xliff:g> provádí automatickou opravu"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kód klávesy %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Klávesa Shift je zapnutá (vypnete ji klepnutím)."</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Klávesa Caps Lock je zapnutá (vypnete ji klepnutím)."</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboly"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Písmena"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Čísla"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Nastavení"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulátor"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Mezerník"</string> - <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_search" msgid="1247236163755920808">"vyhledávací tlačítko"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Tečka"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Přepnout jazyk"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Další"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Předchozí"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Klávesa Shift je aktivní"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Klávesa Caps Lock je aktivní"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Klávesa Shift je neaktivní"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Režim symbolů"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Režim písmen"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Režim telefonu"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Režim telefonních symbolů"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klávesnice je skrytá"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Zobrazení klávesnice: <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum a čas"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"zprávy"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"čísla"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"adresy URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frázové gesto"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Mezery mezi gesty zadáte přejetím po klávese mezerníku."</string> <string name="voice_input" msgid="3583258583521397548">"Klávesa hlasového vstupu"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na hlavní klávesnici"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klávesnici se symboly"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Vypnuto"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon na hlavní klávesnici"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon na klávesnici se symboly"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hlasový vstup vypnut"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nejsou povoleny žádné metody hlasového vstupu. Zkontrolujte nastavení Jazyk a vstup."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurace metod zadávání"</string> <string name="language_selection_title" msgid="1651299598555326750">"Vstupní jazyky"</string> <string name="send_feedback" msgid="1780431884109392046">"Odeslat zpětnou vazbu"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"angličtina (Velká Británie)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angličtina (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"španělština (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angličtina (VB) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"angličtina (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"španělština (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradiční)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"angličtina (VB) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"angličtina (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"španělština (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradiční)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cyrilice)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinka)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Žádný jazyk (latinka)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Latinka (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Latinka (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Číst soubor externího slovníku"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Ve složce Stažené nejsou žádné soubory slovníků."</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Vyberte soubor slovníku k instalaci"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Chcete nainstalovat tento soubor pro jazyk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Chcete nainstalovat tento soubor pro jazyk <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Došlo k chybě"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Vypsat slovník kontaktů"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Vypsat osobní slovník"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Vypsat slovník historie uživatele"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Vypsat slovník přizpůsobení"</string> <string name="button_default" msgid="3988017840431881491">"Výchozí"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Vítá vás <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"s psaním gesty"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Aktualizovat"</string> <string name="last_update" msgid="730467549913588780">"Poslední aktualizace"</string> <string name="message_updating" msgid="4457761393932375219">"Kontrola aktualizací"</string> - <string name="message_loading" msgid="8689096636874758814">"Načítání..."</string> + <string name="message_loading" msgid="5638680861387748936">"Načítání…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Hlavní slovník"</string> <string name="cancel" msgid="6830980399865683324">"Zrušit"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Nastavení"</string> <string name="install_dict" msgid="180852772562189365">"Instalovat"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Zrušit"</string> <string name="delete_dict" msgid="756853268088330054">"Smazat"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Pro vybraný jazyk mobilního zařízení je k dispozici slovník.<br/> Doporučujeme slovník pro jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> <b>stáhnout</b>. Usnadníte si tím zadávání textu.<br/> <br/> V síti 3G bude stahování chvíli trvat. Pokud nemáte <b>neomezený datový tarif</b>, mohou vám být účtovány poplatky.<br/> Jestliže si nejste jisti, jaký datový tarif máte, doporučujeme vám najít připojení Wi-Fi. Stahování se pak zahájí automaticky.<br/> <br/> Tip: Slovníky můžete stahovat a odstraňovat v nabídce mobilního zařízení <b>Jazyk a vstup</b> v <b>Nastavení</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Pro jazyk vybraný na vašem mobilním zařízení je k dispozici slovník.<br/> Doporučujeme slovník pro jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> <b>stáhnout</b>. Usnadníte si tím zadávání textu. <br/> <br/> V síti 3G bude stahování trvat minutu až dvě. Pokud nemáte <b>neomezený datový tarif</b>, mohou vám být účtovány poplatky.<br/> Jestliže si nejste jisti, jaký datový tarif máte, doporučujeme vám najít připojení Wi-Fi. Stahování se pak zahájí automaticky.<br/> <br/> Tip: Slovníky můžete stahovat a odstraňovat v nabídce mobilního zařízení <b>Jazyk a zadávání</b> v <b>Nastavení</b>."</string> <string name="download_over_metered" msgid="1643065851159409546">"Stáhnout ihned (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Stáhnout pouze přes Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Je k dispozici slovník pro jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Je k dispozici slovník pro jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Stisknutím zkontrolujete a stáhnete"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Stahování: návrhy pro jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> budou brzy k dispozici."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Stahování: návrhy pro jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> budou brzy k dispozici."</string> <string name="version_text" msgid="2715354215568469385">"Verze <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Přidat"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Přidat do slovníku"</string> diff --git a/java/res/layout/key_preview_gb.xml b/java/res/values-da/strings-config-important-notice.xml index 2f2a321a3..1c0c63e2c 100644 --- a/java/res/layout/key_preview_gb.xml +++ b/java/res/values-da/strings-config-important-notice.xml @@ -1,8 +1,8 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="UTF-8"?> +<!-- /* ** -** Copyright 2010, The Android Open Source Project +** Copyright 2014, 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. @@ -16,12 +16,9 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ ---> + --> -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@drawable/keyboard_key_feedback_gb" - android:minWidth="32dp" - android:gravity="center" -/> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Giv bedre forslag ud fra tidligere kommunikation og data"</string> +</resources> diff --git a/java/res/values-da/strings-talkback-descriptions.xml b/java/res/values-da/strings-talkback-descriptions.xml new file mode 100644 index 000000000..2d613d6c7 --- /dev/null +++ b/java/res/values-da/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Tilslut et headset for at få læst taster højt, når du indtaster en adgangskode."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Nuværende tekst er %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Der er ingen indtastet tekst"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> retter <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> til <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> udfører automatisk stavekontrol"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Tastekode %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift er aktiveret (tryk for at deaktivere)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock er slået til (tryk for at deaktivere)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Slet"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboler"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Bogstaver"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Tal"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Indstillinger"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Fane"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Mellemrum"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Stemmeinput"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Søgning"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Prik"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Skift sprog"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Næste"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Forrige"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift er aktiveret"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock er aktiveret"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift er deaktiveret"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symboltilstand"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Bogstavtilstand"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefontilstand"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefonsymboltilstand"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastaturet er skjult"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Viser tastatur til <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"dato"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"dato og klokkeslæt"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"beskeder"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"tal"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefonnummer"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"klokkeslæt"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"webadresse"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Seneste"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personer"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objekter"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Steder"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboler"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Humørikoner"</string> +</resources> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 86bdad469..65025b7a8 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -22,8 +22,8 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_input_options" msgid="3909945612939668554">"Indstillinger for input"</string> <string name="english_ime_research_log" msgid="8492602295696577851">"Forskningslogkommandoer"</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="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Anvend kontaktnavne"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruger ord fra dine kontaktpersondata"</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> @@ -35,7 +35,7 @@ <string name="advanced_settings_summary" msgid="4487980456152830271">"Indstillinger for øvede"</string> <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Skift inputmetode"</string> <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Tasten til sprogskift gælder også for andre inputmetoder"</string> - <string name="show_language_switch_key" msgid="5915478828318774384">"Tast til sprogskift"</string> + <string name="show_language_switch_key" msgid="5915478828318774384">"Knap til sprogskift"</string> <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Vis, når der er aktiveret flere inputsprog"</string> <string name="sliding_key_input_preview" msgid="6604262359510068370">"Vis indikator ved glidning"</string> <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Vis et visuelt tip, når du glider fra Shift eller symboltaster"</string> @@ -46,17 +46,18 @@ <string name="settings_system_default" msgid="6268225104743331821">"Systemstandard"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå navne på kontakter"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Brug navne fra Kontaktpersoner til forslag og rettelser"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Tilpassede forslag"</string> <string name="use_double_space_period" msgid="8781529969425082860">"To mellemrum for punktum"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"To tryk på mellemrumstasten indsætter et punktum og et mellemrum"</string> - <string name="auto_cap" msgid="1719746674854628252">"Skriv aut. med stort"</string> + <string name="auto_cap" msgid="1719746674854628252">"Skriv automatisk med stort"</string> <string name="auto_cap_summary" msgid="7934452761022946874">"Skriv det første ord i hver sætning med stort"</string> <string name="edit_personal_dictionary" msgid="3996910038952940420">"Personlig ordbog"</string> - <string name="configure_dictionaries_title" msgid="4238652338556902049">"Tillægsordbøger"</string> + <string name="configure_dictionaries_title" msgid="4238652338556902049">"Ekstra ordbøger"</string> <string name="main_dictionary" msgid="4798763781818361168">"Hovedordbog"</string> <string name="prefs_show_suggestions" msgid="8026799663445531637">"Vis rettelsesforslag"</string> <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Vis ordforslag under indtastning"</string> <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vis altid"</string> - <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Vis i portræt"</string> + <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Vis i oprejst format"</string> <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Skjul altid"</string> <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Bloker stødende ord"</string> <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Foreslå ikke potentielt stødende ord"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Vis glidende trykspor"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamiske ordeksempler"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Se ordforslag ved glidende indtastning"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Tilslut et headset for at høre indtastningen blive læst højt ved angivelse af adgangskode."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Nuværende tekst er %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Der er ingen indtastet tekst"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> retter <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> til <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> udfører automatisk rettelse"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Tastekode %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift-tast"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Skift er slået til (tryk for at deaktivere)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock er slået til (tryk for at deaktivere)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Slet"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboler"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Bogstaver"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Tal"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Indstillinger"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulatortast"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Mellemrum"</string> - <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_search" msgid="1247236163755920808">"Søg"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punktum"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Skift sprog"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Næste"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Forrige"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Skift er aktiveret"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock er aktiveret"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Skift er deaktiveret"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symboltilstand"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Bogstavtilstand"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefontilstand"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefonsymboltilstand"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastaturet er skjult"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Viser tastatur til <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"dato"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"Dato og klokkeslæt"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"beskeder"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"tal"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefonnummer"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"klokkeslæt"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"Webadresse"</string> - <string name="voice_input" msgid="3583258583521397548">"Nøgle til stemmeinput"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"På hovedtastatur"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"På symboltastatur"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Fra"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. på hovedtastatur"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. på symboltastatur"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Stemmeinput deaktiveret"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Bevægelse for udtryk"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Tilføj mellemrum ved at glide til mellemrumstasten"</string> + <string name="voice_input" msgid="3583258583521397548">"Knap til taleinput"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Der er ingen aktiverede stemmeinputmetoder. Kontrollér Indstillinger for sprog og input."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inputmetoder"</string> <string name="language_selection_title" msgid="1651299598555326750">"Inputsprog"</string> <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannien)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spansk (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engelsk (Storbritannien) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engelsk (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spansk (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditionelt)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engelsk (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engelsk (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spansk (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionelt)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kyrillisk)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Intet sprog (Alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Læs ekstern ordbogsfil"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Der er ingen ordbogsfiler i mappen Downloads"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Vælg den ordbog, som du vil installere"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Er du klar til at installere denne fil til <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Vil du virkelig installere denne fil for <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Der opstod en fejl"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Gem ordbog for kontakter"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Gem personlig ordbog"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Gem ordbog for brugerhistorik"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Gem ordbog for tilpasning"</string> <string name="button_default" msgid="3988017840431881491">"Standard"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Velkommen til <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"med glidende indtastning"</string> @@ -193,7 +154,7 @@ <string name="dictionary_provider_name" msgid="3027315045397363079">"Dictionary Provider"</string> <string name="dictionary_service_name" msgid="6237472350693511448">"Ordbogstjeneste"</string> <string name="download_description" msgid="6014835283119198591">"Opdateringsoplysninger for ordbøger"</string> - <string name="dictionary_settings_title" msgid="8091417676045693313">"Tillægsordbøger"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"Ekstra ordbøger"</string> <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Ordbog er tilgængelig"</string> <string name="dictionary_settings_summary" msgid="5305694987799824349">"Indstillinger for ordbøger"</string> <string name="user_dictionaries" msgid="3582332055892252845">"Brugerordbøger"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Opdater"</string> <string name="last_update" msgid="730467549913588780">"Sidst opdateret"</string> <string name="message_updating" msgid="4457761393932375219">"Søger efter opdateringer"</string> - <string name="message_loading" msgid="8689096636874758814">"Indlæser..."</string> + <string name="message_loading" msgid="5638680861387748936">"Indlæser…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Hovedordbog"</string> <string name="cancel" msgid="6830980399865683324">"Annuller"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Indstillinger"</string> <string name="install_dict" msgid="180852772562189365">"Installer"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Annuller"</string> <string name="delete_dict" msgid="756853268088330054">"Slet"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Det valgte sprog på din mobilenhed har en tilgængelig ordbog.<br/> Vi anbefaler, at du <b>downloader</b> <xliff:g id="LANGUAGE">%1$s</xliff:g>-ordbogen for at forbedre din skriveoplevelse.<br/> <br/> Downloaden kan tage 1-2 minutter via 3G. Der bliver muligvis opkrævet et gebyr, hvis du ikke har et <b>ubegrænset dataabonnement</b>.<br/>. Hvis du ikke er sikker på, hvilket dataabonnement du har, anbefaler vi, at du finder en Wi-Fi-forbindelse for at starte automatisk download.<br/> <br/>Tip! Du kan downloade og fjerne ordbøger ved at gå til <b>Sprog og input </b> i menuen <b>Indstillinger</b> på din mobilenhed."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Det valgte sprog på din mobilenhed har en tilgængelig ordbog.<br/> Vi anbefaler, at du <b>downloader</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-ordbogen for at forbedre din skriveoplevelse.<br/> <br/> Downloaden kan tage 1-2 minutter via 3G. Der bliver muligvis opkrævet et gebyr, hvis du ikke har et <b>ubegrænset dataabonnement</b>.<br/>. Hvis du ikke er sikker på, hvilket dataabonnement du har, anbefaler vi, at du finder en Wi-Fi-forbindelse for at starte automatisk download.<br/> <br/>Tip! Du kan downloade og fjerne ordbøger ved at gå til <b>Sprog og input </b> i menuen <b>Indstillinger</b> på din mobilenhed."</string> <string name="download_over_metered" msgid="1643065851159409546">"Download nu (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Download via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Der er en tilgængelig ordbog for <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Der er en ordbog tilgængelig for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Tryk for at gennemgå og downloade"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Downloader: Der vil snart være forslag klar på <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Downloader: Der vil snart være forslag klar på <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Tilføj"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Føj til ordbog"</string> diff --git a/java/res/values-de/strings-config-important-notice.xml b/java/res/values-de/strings-config-important-notice.xml new file mode 100644 index 000000000..a514364f9 --- /dev/null +++ b/java/res/values-de/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Vorschläge anhand bisheriger Nachrichten und Eingaben verbessern"</string> +</resources> diff --git a/java/res/values-de/strings-talkback-descriptions.xml b/java/res/values-de/strings-talkback-descriptions.xml new file mode 100644 index 000000000..9fef63208 --- /dev/null +++ b/java/res/values-de/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Aktueller Text lautet %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Kein Text eingegeben"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Mit <xliff:g id="KEY_NAME">%1$s</xliff:g> wird \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" in \"<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>\" geändert."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Mit <xliff:g id="KEY_NAME">%1$s</xliff:g> erfolgt eine Autokorrektur."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Tastencode %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Umschalttaste"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Umschalttaste aktiviert (zum Deaktivieren berühren)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Feststelltaste aktiviert (zum Deaktivieren berühren)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Löschen"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbole"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Buchstaben"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Zahlen"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Einstellungen"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulatortaste"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Leertaste"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Spracheingabe"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Eingabetaste"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Suchen"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Aufzählungspunkt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Sprache wechseln"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Weiter"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Zurück"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Umschalttaste aktiviert"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Feststelltaste aktiviert"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Umschalttaste deaktiviert"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbolmodus"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Buchstabenmodus"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefonmodus"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefon-Symbolmodus"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastatur ausgeblendet"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Tastatur für <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"Datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"Datum und Uhrzeit"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"E-Mail-Adresse"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"SMS/MMS"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"Zahl"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"Telefonnummer"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"Text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"Zeit"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Neueste"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Kontakte"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objekte"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Orte"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbole"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticons"</string> +</resources> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index b65053465..f2074b762 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -38,7 +38,7 @@ <string name="show_language_switch_key" msgid="5915478828318774384">"Sprachwechsel"</string> <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Anzeigen, wenn mehrere Eingabesprachen aktiviert sind"</string> <string name="sliding_key_input_preview" msgid="6604262359510068370">"Ziehbewegung anzeigen"</string> - <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Ziehen mit gedrückter Shift- oder Symboltaste visuell darstellen"</string> + <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Ziehen mit gedrückter Symboltaste oder Shift visuell darstellen"</string> <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Tasten-Pop-up"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Keine Verzögerung"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string> @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Systemstandardeinstellung"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Kontakte vorschlagen"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen aus \"Kontakte\" als Vorschläge und Korrekturmöglichkeiten anzeigen"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalisierte Vorschläge"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt plus Leerzeichen"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Für Punkt plus Leerzeichen zweimal auf die Leertaste tippen"</string> <string name="auto_cap" msgid="1719746674854628252">"Autom. Groß-/Kleinschreibung"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Spur der Bewegung anzeigen"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dyn. unverankerter Vorschlag"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Vorgeschlagenes Wort bei Bewegung anzeigen"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Aktueller Text lautet %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Kein Text eingegeben"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Mit <xliff:g id="KEY">%1$s</xliff:g> wird <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> zu <xliff:g id="CORRECTED">%3$s</xliff:g> korrigiert."</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Mit <xliff:g id="KEY">%1$s</xliff:g> erfolgt eine Autokorrektur."</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Tastencode %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Umschalttaste"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Umschalttaste aktiviert (zum Deaktivieren berühren)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Feststelltaste aktiviert (zum Deaktivieren berühren)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Entf"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbole"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Buchstaben"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Zahlen"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Einstellungen"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulator"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Leerzeichen"</string> - <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_search" msgid="1247236163755920808">"Suchen"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Aufzählungspunkt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Sprache wechseln"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Nächste"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorherige"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Umschalttaste aktiviert"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Feststelltaste aktiviert"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Umschalttaste deaktiviert"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolmodus"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Buchstabenmodus"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefonmodus"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefon-Symbolmodus"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastatur ausgeblendet"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Tastatur für <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"Datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"Datum & Uhrzeit"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"E-Mail-Adresse"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"SMS/MMS"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"Zahl"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"Telefonnummer"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"Text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"Zeit"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Phrasenbewegung"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Leerzeichen durch Bewegung über die Leertaste einfügen"</string> <string name="voice_input" msgid="3583258583521397548">"Taste für Spracheingabe"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Auf Haupttastatur"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Auf Symboltastatur"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Aus"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikro auf Haupttastatur"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikro auf Symboltastatur"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Spracheingabe deaktiviert"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Keine Spracheingabemethoden aktiviert. Rufen Sie die Einstellungen für \"Sprache & Eingabe\" auf."</string> <string name="configure_input_method" msgid="373356270290742459">"Eingabemethoden konfigurieren"</string> <string name="language_selection_title" msgid="1651299598555326750">"Eingabesprachen"</string> <string name="send_feedback" msgid="1780431884109392046">"Feedback geben"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Englisch (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Englisch (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spanisch (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Englisch (GB) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Englisch (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spanisch (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditionell)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Englisch (GB) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Englisch (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spanisch (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionell)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kyrillisch)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (lateinisch)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Keine Sprache (lat. Alphabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Lat. Alphabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Lat. Alphabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Externe Wörterbuchdatei lesen"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Keine Wörterbuchdateien im Ordner \"Downloads\""</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Wörterbuchdatei zum Installieren auswählen"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Möchten Sie diese Datei für <xliff:g id="LOCALE_NAME">%s</xliff:g> installieren?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Möchten Sie diese Datei für <xliff:g id="LANGUAGE_NAME">%s</xliff:g> installieren?"</string> <string name="error" msgid="8940763624668513648">"Es ist ein Fehler aufgetreten"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Auszug Kontaktwörterbuch"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Auszug persönliches Wörterbuch"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Auszug Nutzerverlaufswörterbuch"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Auszug Personalisierungswörterbuch"</string> <string name="button_default" msgid="3988017840431881491">"Standard"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Willkommen bei <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"mit Bewegungseingabe"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Aktualisieren"</string> <string name="last_update" msgid="730467549913588780">"Zuletzt aktualisiert"</string> <string name="message_updating" msgid="4457761393932375219">"Suche nach Updates..."</string> - <string name="message_loading" msgid="8689096636874758814">"Wird geladen..."</string> + <string name="message_loading" msgid="5638680861387748936">"Wird geladen…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Allgemeines Wörterbuch"</string> <string name="cancel" msgid="6830980399865683324">"Abbrechen"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Einstellungen"</string> <string name="install_dict" msgid="180852772562189365">"Installieren"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Abbrechen"</string> <string name="delete_dict" msgid="756853268088330054">"Löschen"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Für die auf dem Mobilgerät ausgewählte Sprache ist ein Wörterbuch verfügbar.<br/> <b>Laden Sie das <xliff:g id="LANGUAGE">%1$s</xliff:g>-Wörterbuch herunter</b> und verbessern Sie Ihre Eingabeerfahrung.<br/> <br/>Der Download über 3G kann ein bis zwei Minuten dauern. Falls Sie keine <b>Datenflatrate</b> haben, fallen eventuell Gebühren an.<br/> Sollten Sie sich nicht sicher sein, welchen Datentarif Sie haben, suchen Sie eine WLAN-Verbindung, um den Download automatisch zu starten.<br/> <br/>Tipp: Im Menü <b>Einstellungen</b> Ihres Mobilgeräts können Sie unter <b>Sprache & Eingabe</b> Wörterbücher herunterladen und entfernen."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Für die auf dem Mobilgerät ausgewählte Sprache ist ein Wörterbuch verfügbar.<br/> <b>Laden Sie das <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-Wörterbuch herunter</b> und verbessern Sie Ihre Eingabeerfahrung.<br/> <br/> Der Download über 3G kann ein bis zwei Minuten dauern. Falls Sie keine <b>Datenflatrate</b> haben, fallen eventuell Gebühren an.<br/> Sollten Sie sich nicht sicher sein, welchen Datentarif Sie haben, suchen Sie eine WLAN-Verbindung, um den Download automatisch zu starten.<br/> <br/> Tipp: Im Menü <b>Einstellungen</b> Ihres Mobilgeräts können Sie unter <b>Sprache & Eingabe</b> Wörterbücher herunterladen und entfernen."</string> <string name="download_over_metered" msgid="1643065851159409546">"Jetzt herunterladen (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Über WLAN herunterladen"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Es ist ein Wörterbuch für <xliff:g id="LANGUAGE">%1$s</xliff:g> verfügbar."</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Es ist ein Wörterbuch für <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> verfügbar."</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Zum Lesen und Herunterladen drücken"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Download wurde gestartet: Vorschläge für <xliff:g id="LANGUAGE">%1$s</xliff:g> sind in Kürze bereit."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Download wurde gestartet: Vorschläge für <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sind in Kürze bereit."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Hinzufügen"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Zum Wörterbuch hinzufügen"</string> diff --git a/java/res/values-el/strings-config-important-notice.xml b/java/res/values-el/strings-config-important-notice.xml new file mode 100644 index 000000000..926ec9b6b --- /dev/null +++ b/java/res/values-el/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Χρήση επικοινωνιών/δεδομένων πληκτρολόγησης για βελτίωση προτάσεων"</string> +</resources> diff --git a/java/res/values-el/strings-talkback-descriptions.xml b/java/res/values-el/strings-talkback-descriptions.xml new file mode 100644 index 000000000..7393e630e --- /dev/null +++ b/java/res/values-el/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Συνδέστε ένα σετ ακουστικών για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται δυνατά."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Το τρέχον κείμενο είναι %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Δεν υπάρχει κείμενο"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> διορθώνει το <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> σε <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> εκτελεί αυτόματη διόρθωση"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Κωδικός πλήκτρου %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Το Shift είναι ενεργοποιημένο (πατήστε για απενεργοποίηση)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Το Caps lock είναι ενεργοποιημένο (πατήστε για απενεργοποίηση)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Διαγραφή"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Σύμβολα"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Γράμματα"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Αριθμοί"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Ρυθμίσεις"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Πλήκτρο διαστήματος"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Φωνητική είσοδος"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoticon"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Επιστροφή"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Αναζήτηση"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Κουκκίδα"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Εναλλαγή γλώσσας"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Επόμενο"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Προηγούμενο"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Το Shift είναι ενεργοποιημένο"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Το Caps lock είναι ενεργοποιημένο"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Το Shift είναι απενεργοποιημένο"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Λειτουργία συμβόλων"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Λειτουργία γραμμάτων"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Λειτουργία τηλεφώνου"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Λειτουργία συμβόλων τηλεφώνου"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Απόκρυψη πληκτρολογίου"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Εμφάνιση πληκτρολογίου <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ημερομηνία"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ημερομηνία και ώρα"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"διεύθυνση ηλεκτρονικού ταχυδρομείου"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ανταλλαγή μηνυμάτων"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"αριθμός"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"τηλέφωνο"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"κείμενο"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ώρα"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"διεύθυνση URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Πρόσφατα"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Άτομα"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Αντικείμενα"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Φύση"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Μέρη"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Σύμβολα"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticon"</string> +</resources> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 79e83423c..7f0e3f3d7 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Προεπιλογή"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Πρόταση ονομάτων επαφών"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Χρησιμοποιήστε ονόματα από τις Επαφές για προτάσεις και διορθ."</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Εξατομικευμένες προτάσεις"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Τελεία με διπλό πάτημα πλήκτρ.διαστ."</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Το διπλό πάτημα του πλήκτρ.διαστ. εισάγει μια τελεία και ένα κενό"</string> <string name="auto_cap" msgid="1719746674854628252">"Αυτόματη χρήση κεφαλαίων"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Εμφάνιση διαδρομής χειρονομίας"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Προεπισκόπ. δυναμικής κίνησης"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Εμφάνιση της προτεινόμενης λέξης κατά την κίνηση"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Συνδέστε ένα σετ ακουστικών για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται δυνατά."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Το τρέχον κείμενο είναι %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Δεν υπάρχει κείμενο"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> διορθώνει το <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> σε <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> εκτελεί αυτόματη διόρθωση"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Κωδικός πλήκτρου %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Το Shift είναι ενεργοποιημένο (πατήστε για απενεργοποίηση)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Το Caps lock είναι ενεργοποιημένο (πατήστε για απενεργοποίηση)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Πλήκτρο Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Σύμβολα"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Γράμματα:"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Αριθμοί"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Ρυθμίσεις"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Πλήκτρο Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Πλήκτρο διαστήματος"</string> - <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_search" msgid="1247236163755920808">"Αναζήτηση"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Κουκκίδα"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Αλλαγή γλώσσας"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Επόμενο"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Προηγούμενο"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Το Shift ενεργοποιημένο"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Το Caps lock είναι ενεργοποιημένο"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Το Shift είναι απενεργοποιημένο"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Λειτουργία συμβόλων"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Λειτουργία γραμμάτων"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Λειτουργία τηλεφώνου"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Λειτουργία συμβόλων τηλεφώνου"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Πληκτρολόγιο είναι κρυμμένο"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Εμφάνιση πληκτρολογίου <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ημερομηνία"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ημερομηνία και ώρα"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"διεύθυνση ηλεκτρονικού ταχυδρομείου"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ανταλλαγή μηνυμάτων"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"αριθμός"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"τηλέφωνο"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"κείμενο"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ώρα"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"διεύθυνση URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Εισαγωγή φράσεων με κίνηση"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Εισαγάγετε κενά στις κινήσεις με ολίσθηση στο πλήκτρο διαστήματος"</string> <string name="voice_input" msgid="3583258583521397548">"Κλειδί φωνητικής εξόδου"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Στο κύριο πληκτρολ."</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Πληκτρ. συμβ. ενερ."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Απενεργοποίηση"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Μικ. στο κύριο πληκ."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Μικ. στο πληκ. συμβ."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Απεν. φωνητ. είσοδος"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Δεν έχουν ενεργοποιηθεί μέθοδοι φωνητικής εισαγωγής. Ελέγξτε τις Ρυθμίσεις Γλώσσας και εισαγωγής."</string> <string name="configure_input_method" msgid="373356270290742459">"Διαμόρφωση μεθόδων εισαγωγής"</string> <string name="language_selection_title" msgid="1651299598555326750">"Γλώσσες εισόδου"</string> <string name="send_feedback" msgid="1780431884109392046">"Αποστολή σχολίων"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Αγγλικά (Η.Β.)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Αγγλικά (Η.Π.Α)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Ισπανικά (ΗΠΑ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Αγγλικά (ΗΒ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Αγγλικά (ΗΠΑ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Ισπανικά (ΗΠΑ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Παραδοσιακά)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Αγγλικά (Ηνωμένο Βασίλειο) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Αγγλικά (ΗΠΑ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Ισπανικά (ΗΠΑ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Παραδοσιακά)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Κυριλλικά)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Λατινικά)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Καμία γλώσσα (Αλφάβητο)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Αλφάβητο (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Αλφάβητο (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ανάγνωση εξωτερικού αρχείου λεξικού"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Δεν υπάρχουν αρχεία λεξικού στο φάκελο \"Λήψεις\""</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Επιλογή αρχείου λεξικού για εγκατάσταση"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Να εγκατασταθεί όντως αυτό το αρχείο για <xliff:g id="LOCALE_NAME">%s</xliff:g>;"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Εγκατάσταση αυτού του αρχείου για τα <xliff:g id="LANGUAGE_NAME">%s</xliff:g>;"</string> <string name="error" msgid="8940763624668513648">"Παρουσιάστηκε σφάλμα."</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Εξαγωγή λεξικού επαφών"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Αποτύπωση προσωπικού λεξικού"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Αποτύπωση λεξικού ιστορικού χρήστη"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Αποτύπωση λεξικού εξατομίκευσης"</string> <string name="button_default" msgid="3988017840431881491">"Προεπιλογή"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Καλώς ορίσατε στο <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"με Πληκτρολόγηση με κίνηση"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Ανανέωση"</string> <string name="last_update" msgid="730467549913588780">"Τελευταία ενημέρωση"</string> <string name="message_updating" msgid="4457761393932375219">"Έλεγχος για ενημερώσεις"</string> - <string name="message_loading" msgid="8689096636874758814">"Φόρτωση…"</string> + <string name="message_loading" msgid="5638680861387748936">"Φόρτωση…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Κύριο λεξικό"</string> <string name="cancel" msgid="6830980399865683324">"Ακύρωση"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Ρυθμίσεις"</string> <string name="install_dict" msgid="180852772562189365">"Εγκατάσταση"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Ακύρωση"</string> <string name="delete_dict" msgid="756853268088330054">"Διαγραφή"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Η επιλ. γλώσσα στην κιν. συσκευή σας διαθέτει λεξικό.<br/> Προτείνουμε να <b>κάνετε λήψη</b> του λεξικού <xliff:g id="LANGUAGE">%1$s</xliff:g> για να βελτ. την πληκτρολόγηση.<br/> <br/> Για τη λήψη μπορεί να χρειαστούν 1 ή 2 λεπτά μέσω 3G. Ίσως ισχύουν χρεώσεις αν δεν έχετε <b>πρόγρ. απερ. δεδομ.</b>.<br/> Αν δεν γνωρίζετε ποιο πρόγ. δεδ. έχετε, προτείνουμε να βρείτε μια σύνδ. Wi-Fi για να ξεκιν. αυτόμ. η λήψη.<br/> <br/> Συμβουλή: Μπορείτε να λάβετε και να καταργ. λεξικά, από την περιοχή <b>Γλώσσα και εισαγωγή</b>, στο μενού <b>Ρυθμίσεις</b> της κιν. συσκ."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Η επιλεγμένη γλώσσα στην κινητή συσκευή σας διαθέτει λεξικό.<br/> Προτείνουμε να <b>κατεβάσετε</b> το λεξικό <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> για βελτίωση της πληκτρολόγησης.<br/> <br/> Για τη λήψη μπορεί να χρειαστούν 1 ή 2 λεπτά μέσω 3G. Ενδέχεται να ισχύουν χρεώσεις αν δεν έχετε διαθέτετε<b>πρόγραμμα απεριόριστων δεδομένων</b>.<br/> Αν δεν γνωρίζετε ποιο πρόγραμμα δεδομένων διαθέτετε, προτείνουμε να χρησιμοποιήσετε μια σύνδεση Wi-Fi για να ξεκινήσει αυτόματα η λήψη.<br/> <br/> Συμβουλή: Μπορείτε να κατεβάσετε και να καταργήσετε λεξικά, από την περιοχή <b>Γλώσσα και εισαγωγή</b>, στο μενού <b>Ρυθμίσεις</b> της κινητής συσκευής σας."</string> <string name="download_over_metered" msgid="1643065851159409546">"Άμεση λήψη (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Λήψη μέσω Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Υπάρχει διαθέσιμο λεξικό για τα <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Υπάρχει διαθέσιμο λεξικό για τα <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Πατήστε για έλεγχο και λήψη"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Λήψη: Οι προτάσεις για τα <xliff:g id="LANGUAGE">%1$s</xliff:g> θα είναι έτοιμες σύντομα."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Λήψη: οι προτάσεις για τα <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> θα είναι έτοιμες σύντομα."</string> <string name="version_text" msgid="2715354215568469385">"Έκδοση <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Προσθήκη"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Προσθήκη στο λεξικό"</string> diff --git a/java/res/values-en-rGB/strings-config-important-notice.xml b/java/res/values-en-rGB/strings-config-important-notice.xml new file mode 100644 index 000000000..80ddd3e4b --- /dev/null +++ b/java/res/values-en-rGB/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Learn from your communications and typed data to improve suggestions"</string> +</resources> diff --git a/java/res/values-en-rGB/strings-talkback-descriptions.xml b/java/res/values-en-rGB/strings-talkback-descriptions.xml new file mode 100644 index 000000000..c9393ee79 --- /dev/null +++ b/java/res/values-en-rGB/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Plug in a headset to hear password keys spoken aloud."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Current text is %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"No text entered"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrects <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> to <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> performs auto-correction"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Key code %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift on (tap to disable)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock on (tap to disable)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Delete"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbols"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letters"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Numbers"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Settings"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Voice input"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Search"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Full stop"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Switch language"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Next"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Previous"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift enabled"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock enabled"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift disabled"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbols mode"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Letters mode"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Phone mode"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Phone symbols mode"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Keyboard hidden"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Showing <xliff:g id="KEYBOARD_MODE">%s</xliff:g> keyboard"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"date"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"date and time"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"messaging"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"number"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"phone"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"time"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recents"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"People"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objects"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Nature"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Places"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbols"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticons"</string> +</resources> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index 4bc1b15cf..89e978925 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"System default"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalised suggestions"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space full stop"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Double tap on spacebar inserts a full stop followed by a space"</string> <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Show gesture trail"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamic floating preview"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"See the suggested word while gesturing"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Plug in a headset to hear password keys spoken aloud."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Current text is %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"No text entered"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corrects <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> to <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> performs auto-correction"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Key code %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift on (tap to disable)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock on (tap to disable)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbols"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbers"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Settings"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string> - <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_search" msgid="1247236163755920808">"Search"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Switch language"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Next"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Previous"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift enabled"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock enabled"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift disabled"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbols mode"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Letters mode"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Phone mode"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Phone symbols mode"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Keyboard hidden"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Showing <xliff:g id="MODE">%s</xliff:g> keyboard"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"date"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"date and time"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"messaging"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"number"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"phone"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Phrase gesture"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Input spaces during gestures by gliding to the space key"</string> <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"On main keyboard"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"On symbols keyboard"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Off"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic on main keyboard"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic on symbols keyboard"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Voice input is disabled"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language & input settings."</string> <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string> <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string> <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"English (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"English (US)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spanish (US)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"English (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"English (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spanish (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Traditional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"English (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"English (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spanish (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Traditional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyrillic)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"No language (Alphabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alphabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alphabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Read external dictionary file"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"No dictionary files in the Downloads folder"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Select a dictionary file to install"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Really install this file for <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Really install this file for <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"There was an error"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Dump contacts dictionary"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Dump personal dictionary"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Dump user history dictionary"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Dump personalisation dictionary"</string> <string name="button_default" msgid="3988017840431881491">"Default"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Welcome to <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"with Gesture Typing"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Refresh"</string> <string name="last_update" msgid="730467549913588780">"Last updated"</string> <string name="message_updating" msgid="4457761393932375219">"Checking for updates"</string> - <string name="message_loading" msgid="8689096636874758814">"Loading..."</string> + <string name="message_loading" msgid="5638680861387748936">"Loading…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Main dictionary"</string> <string name="cancel" msgid="6830980399865683324">"Cancel"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Settings"</string> <string name="install_dict" msgid="180852772562189365">"Install"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancel"</string> <string name="delete_dict" msgid="756853268088330054">"Delete"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"The selected language on your mobile device has an available dictionary.<br/> We recommend <b>downloading</b> the <xliff:g id="LANGUAGE">%1$s</xliff:g> dictionary to improve your typing experience.<br/> <br/> The download could take a minute or two over 3G. Charges may apply if you don\'t have an <b>unlimited data plan</b>.<br/> If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.<br/> <br/> Tip: You can download and remove dictionaries by going to <b>Language & input</b> in the <b>Settings</b> menu of your mobile device."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"The selected language on your mobile device has an available dictionary.<br/> We recommend <b>downloading</b> the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> dictionary to improve your typing experience.<br/> <br/> The download could take a minute or two over 3G. Charges may apply if you don\'t have an <b>unlimited data plan</b>.<br/> If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.<br/> <br/> Tip: You can download and remove dictionaries by going to <b>Language & input</b> in the <b>Settings</b> menu of your mobile device."</string> <string name="download_over_metered" msgid="1643065851159409546">"Download now (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Download over Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"A dictionary is available for <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"A dictionary is available for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Press to review and download"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Downloading: suggestions for <xliff:g id="LANGUAGE">%1$s</xliff:g> will be ready soon."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Downloading: suggestions for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> will be ready soon."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Add"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Add to dictionary"</string> diff --git a/java/res/values-en-rIN/strings-config-important-notice.xml b/java/res/values-en-rIN/strings-config-important-notice.xml new file mode 100644 index 000000000..80ddd3e4b --- /dev/null +++ b/java/res/values-en-rIN/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Learn from your communications and typed data to improve suggestions"</string> +</resources> diff --git a/java/res/values-en-rIN/strings-talkback-descriptions.xml b/java/res/values-en-rIN/strings-talkback-descriptions.xml new file mode 100644 index 000000000..c9393ee79 --- /dev/null +++ b/java/res/values-en-rIN/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Plug in a headset to hear password keys spoken aloud."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Current text is %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"No text entered"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrects <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> to <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> performs auto-correction"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Key code %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift on (tap to disable)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock on (tap to disable)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Delete"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbols"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letters"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Numbers"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Settings"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Voice input"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Search"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Full stop"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Switch language"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Next"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Previous"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift enabled"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock enabled"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift disabled"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbols mode"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Letters mode"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Phone mode"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Phone symbols mode"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Keyboard hidden"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Showing <xliff:g id="KEYBOARD_MODE">%s</xliff:g> keyboard"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"date"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"date and time"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"messaging"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"number"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"phone"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"time"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recents"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"People"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objects"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Nature"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Places"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbols"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticons"</string> +</resources> diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml index 4bc1b15cf..89e978925 100644 --- a/java/res/values-en-rIN/strings.xml +++ b/java/res/values-en-rIN/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"System default"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalised suggestions"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space full stop"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Double tap on spacebar inserts a full stop followed by a space"</string> <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Show gesture trail"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamic floating preview"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"See the suggested word while gesturing"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Plug in a headset to hear password keys spoken aloud."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Current text is %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"No text entered"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corrects <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> to <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> performs auto-correction"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Key code %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift on (tap to disable)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock on (tap to disable)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbols"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbers"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Settings"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string> - <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_search" msgid="1247236163755920808">"Search"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Switch language"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Next"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Previous"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift enabled"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock enabled"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift disabled"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbols mode"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Letters mode"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Phone mode"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Phone symbols mode"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Keyboard hidden"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Showing <xliff:g id="MODE">%s</xliff:g> keyboard"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"date"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"date and time"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"messaging"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"number"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"phone"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Phrase gesture"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Input spaces during gestures by gliding to the space key"</string> <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"On main keyboard"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"On symbols keyboard"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Off"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic on main keyboard"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic on symbols keyboard"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Voice input is disabled"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language & input settings."</string> <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string> <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string> <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"English (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"English (US)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spanish (US)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"English (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"English (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spanish (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Traditional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"English (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"English (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spanish (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Traditional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyrillic)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"No language (Alphabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alphabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alphabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Read external dictionary file"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"No dictionary files in the Downloads folder"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Select a dictionary file to install"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Really install this file for <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Really install this file for <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"There was an error"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Dump contacts dictionary"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Dump personal dictionary"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Dump user history dictionary"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Dump personalisation dictionary"</string> <string name="button_default" msgid="3988017840431881491">"Default"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Welcome to <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"with Gesture Typing"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Refresh"</string> <string name="last_update" msgid="730467549913588780">"Last updated"</string> <string name="message_updating" msgid="4457761393932375219">"Checking for updates"</string> - <string name="message_loading" msgid="8689096636874758814">"Loading..."</string> + <string name="message_loading" msgid="5638680861387748936">"Loading…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Main dictionary"</string> <string name="cancel" msgid="6830980399865683324">"Cancel"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Settings"</string> <string name="install_dict" msgid="180852772562189365">"Install"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancel"</string> <string name="delete_dict" msgid="756853268088330054">"Delete"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"The selected language on your mobile device has an available dictionary.<br/> We recommend <b>downloading</b> the <xliff:g id="LANGUAGE">%1$s</xliff:g> dictionary to improve your typing experience.<br/> <br/> The download could take a minute or two over 3G. Charges may apply if you don\'t have an <b>unlimited data plan</b>.<br/> If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.<br/> <br/> Tip: You can download and remove dictionaries by going to <b>Language & input</b> in the <b>Settings</b> menu of your mobile device."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"The selected language on your mobile device has an available dictionary.<br/> We recommend <b>downloading</b> the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> dictionary to improve your typing experience.<br/> <br/> The download could take a minute or two over 3G. Charges may apply if you don\'t have an <b>unlimited data plan</b>.<br/> If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.<br/> <br/> Tip: You can download and remove dictionaries by going to <b>Language & input</b> in the <b>Settings</b> menu of your mobile device."</string> <string name="download_over_metered" msgid="1643065851159409546">"Download now (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Download over Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"A dictionary is available for <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"A dictionary is available for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Press to review and download"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Downloading: suggestions for <xliff:g id="LANGUAGE">%1$s</xliff:g> will be ready soon."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Downloading: suggestions for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> will be ready soon."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Add"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Add to dictionary"</string> diff --git a/java/res/values-es-rUS/strings-config-important-notice.xml b/java/res/values-es-rUS/strings-config-important-notice.xml new file mode 100644 index 000000000..5b895fb4a --- /dev/null +++ b/java/res/values-es-rUS/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Aprende de mensajes y datos ingresados para mejorar las sugerencias."</string> +</resources> diff --git a/java/res/values-es-rUS/strings-talkback-descriptions.xml b/java/res/values-es-rUS/strings-talkback-descriptions.xml new file mode 100644 index 000000000..ab4979fc7 --- /dev/null +++ b/java/res/values-es-rUS/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Enchufa tus auriculares para escuchar en voz alta qué teclas presionas al ingresar una contraseña."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"El texto actual es %s."</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"No se ingresó texto."</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> por <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrige automáticamente."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Clave de código %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Mayúsculas"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Mayúsculas activado (presiona para desactivarlo)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Bloqueo de mayúsculas activado (presiona para desactivarlo)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Eliminar"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Símbolos"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letras"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Números"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Configuración"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Pestaña"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espacio"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrada de voz"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Volver"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Búsqueda"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punto"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Cambiar idioma"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Siguiente"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Anterior"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Mayúsculas activado"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Bloqueo de mayúsculas activado"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Mayúsculas desactivado"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modo Símbolos"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modo Letras"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modo Teléfono"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modo Símbolos del teléfono"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Teclado oculto"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Mostrando teclado de <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"fecha"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"fecha y hora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"correo electrónico"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mensaje de texto"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"número"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"teléfono"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"texto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"hora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recientes"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Contactos"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objetos"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Naturaleza"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Lugares"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Símbolos"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticones"</string> +</resources> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 1fd9cf8f0..d440c0ce6 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Valor predet. sist."</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="use_personalized_dicts" msgid="5167396352105467626">"Sugerenc. personalizadas"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y doble espacio"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocar dos veces la barra espaciadora inserta un punto y espacio."</string> <string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar recorrido de gesto"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Vista previa dinámica flotante"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Mira la palabra sugerida mientras haces gestos"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Enchufa tus auriculares para escuchar en voz alta qué teclas presionas al ingresar una contraseña."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"El texto actual es %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"No se ingresó texto."</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"La tecla <xliff:g id="KEY">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> por <xliff:g id="CORRECTED">%3$s</xliff:g>."</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"La tecla <xliff:g id="KEY">%1$s</xliff:g> corrige automáticamente."</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Clave de código %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Mayús"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Se activó el modo Mayúscula (toca para desactivarlo)."</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Se activó el bloqueo de mayúsculas (toca para desactivarlo)."</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Borrar"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Símbolos"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letras"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Números"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Configuración"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Pestaña"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espacio"</string> - <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_search" msgid="1247236163755920808">"Buscar"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambiar idioma"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Siguiente"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Se activó el modo Mayúscula."</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Se activó el bloqueo de mayúsculas."</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Se desactivó el modo Mayúscula"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modo Símbolos"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modo Letras"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modo Teléfono"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modo Símbolos del teléfono"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Teclado oculto"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Mostrando teclado para <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"fecha"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"fecha y hora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"correo"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mensaje de texto"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"número"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"teléfono"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"texto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frase gestual"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Desliza el dedo hasta la tecla de espacio para ingresar espacios."</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> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micrófono en el teclado principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micrófono en el teclado de símbolos"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"La entrada por voz está inhabilitada"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hay métodos de entrada de voz habilitados. Comprueba la configuración de Teclado e idioma."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string> <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string> <string name="send_feedback" msgid="1780431884109392046">"Enviar comentarios"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"Español (EE.UU.)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglés (Reino Unido) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglés (EE.UU.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Español (EE.UU.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglés, Reino Unido (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglés, EE. UU. (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Español, EE. UU. (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cirílico)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latinoamérica)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Ningún idioma (alfabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leer archivo de diccionario externo"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"No hay archivos de diccionario en la carpeta de descargas."</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Seleccionar archivo de diccionario para instalar"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"¿Realmente quieres instalar este archivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"¿Realmente quieres instalar este archivo para <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Se produjo un error."</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Generar diccionario de contactos"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Volcar diccionario personal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Volcar diccionario hist. usuario"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Volcar diccionario personalización"</string> <string name="button_default" msgid="3988017840431881491">"Predeterminado"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Te damos la bienvenida a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"con escritura gestual"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualizar"</string> <string name="last_update" msgid="730467549913588780">"Última actualización"</string> <string name="message_updating" msgid="4457761393932375219">"Buscando actualizaciones"</string> - <string name="message_loading" msgid="8689096636874758814">"Cargando..."</string> + <string name="message_loading" msgid="5638680861387748936">"Cargando…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Diccionario principal"</string> <string name="cancel" msgid="6830980399865683324">"Cancelar"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Configuración"</string> <string name="install_dict" msgid="180852772562189365">"Instalar"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancelar"</string> <string name="delete_dict" msgid="756853268088330054">"Eliminar"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Hay un diccionario disponible para el idioma seleccionado en tu dispositivo móvil.<br/> Te recomendamos que <b>descargues</b> el diccionario de <xliff:g id="LANGUAGE">%1$s</xliff:g> para mejorar tu experiencia de escritura.<br/> <br/> La descarga puede tardar unos minutos en redes 3G. Si no tienes un <b>plan de datos ilimitado</b>, es posible que se apliquen cargos.<br/> Si no conoces las características de tu plan de datos, te recomendamos que uses una conexión Wi-Fi para iniciar la descarga automáticamente.<br/> <br/> Sugerencia: Puedes descargar y eliminar diccionarios en la sección <b>Teclado e idioma</b> del menú <b>Configuración</b> del dispositivo móvil."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Hay un diccionario disponible para el idioma seleccionado en tu dispositivo móvil.<br/> Te recomendamos que <b>descargues</b> el diccionario de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para mejorar tu experiencia de escritura.<br/> <br/> La descarga puede tardar unos minutos en redes 3G. Si no tienes un <b>plan de datos ilimitado</b>, es posible que se apliquen cargos.<br/> Si no sabes qué plan de datos tienes, te recomendamos que uses una conexión Wi-Fi para iniciar la descarga automáticamente.<br/> <br/> Sugerencia: Puedes descargar y eliminar diccionarios desde <b>Teclado e idioma</b> en el menú <b>Configuración</b> del dispositivo móvil."</string> <string name="download_over_metered" msgid="1643065851159409546">"Descargar ahora (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Descargar por Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Hay un diccionario disponible de <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Hay un diccionario disponible de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pulsar para opinar y descargar"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Descargando: las sugerencias de <xliff:g id="LANGUAGE">%1$s</xliff:g> estarán disponibles en breve."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"La descarga de sugerencias para <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> estará lista en breve."</string> <string name="version_text" msgid="2715354215568469385">"Versión <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Agregar"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Agregar al diccionario"</string> diff --git a/java/res/values-es/strings-config-important-notice.xml b/java/res/values-es/strings-config-important-notice.xml new file mode 100644 index 000000000..6771265c5 --- /dev/null +++ b/java/res/values-es/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Aprende de mensajes y datos escritos para mejorar sugerencias"</string> +</resources> diff --git a/java/res/values-es/strings-talkback-descriptions.xml b/java/res/values-es/strings-talkback-descriptions.xml new file mode 100644 index 000000000..72bb6f104 --- /dev/null +++ b/java/res/values-es/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Conecta un auricular para escuchar las contraseñas en voz alta."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"El texto actual es %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"No se ha introducido texto"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> a <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corregirá la palabra automáticamente"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Código del teclado: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Mayús"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Mayúsculas activadas (tocar para inhabilitar)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Bloqueo de mayúsculas activado (tocar para inhabilitar)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Eliminar"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Símbolos"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letras"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Números"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Ajustes"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Pestaña"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espacio"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrada de voz"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emojis"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Intro"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Buscar"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punto"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Cambiar idioma"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Siguiente"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Anterior"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Mayúsculas habilitadas"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Bloq Mayús habilitado"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Mayúsculas inhabilitadas"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modo de símbolos"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modo de letras"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modo de teléfono"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modo de símbolos de teléfono"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Teclado oculto"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Mostrando teclado de <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"fecha"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"fecha y hora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"correo electrónico"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mensajes"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"número"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"teléfono"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"texto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"hora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recientes"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personas"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objetos"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Naturaleza"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Sitios"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Símbolos"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticonos"</string> +</resources> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index 39b45e0c4..3476ac5dd 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Predeterminado"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nombres de contactos para sugerencias y correcciones"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Sugerencias personalizadas"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punto y espacio"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Si tocas dos veces el espacio, se inserta un punto seguido de un espacio"</string> <string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar recorrido del gesto"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Vista previa dinámica flotante"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Ver palabra sugerida al hacer gestos"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Conecta un auricular para escuchar las contraseñas en voz alta."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"El texto actual es %s."</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"No se ha introducido texto."</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"La tecla <xliff:g id="KEY">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> a <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"La tecla <xliff:g id="KEY">%1$s</xliff:g> corrige automáticamente"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Código del teclado: %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Mayús"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Mayúsculas activadas (tocar para inhabilitar)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Bloqueo de mayúsculas activado (tocar para inhabilitar)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Eliminar"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Símbolos"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letras"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Números"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Ajustes"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulador"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Barra espaciadora"</string> - <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_search" msgid="1247236163755920808">"Buscar"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambiar idioma"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Siguiente"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Mayúsculas habilitadas"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Bloqueo de mayúsculas habilitado"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Mayúsculas inhabilitadas"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modo de símbolos"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modo de letras"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modo de teléfono"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modo de símbolos de teléfono"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Teclado oculto"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Mostrando teclado <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"fecha"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"fecha y hora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"correo electrónico"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mensajes"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"número"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"teléfono"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"texto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gestos con tecla Espacio"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Desliza el dedo a Espacio para introducir espacios durante gestos"</string> <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada de voz"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"En teclado principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"En teclado de símbolos"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"No"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micrófono en teclado principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micrófono en teclado de símbolos"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entrada de voz inhabilitada"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Sin métodos de introducción de voz habilitados. Comprueba ajustes de Idioma e introducción de texto."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string> <string name="language_selection_title" msgid="1651299598555326750">"Idiomas"</string> <string name="send_feedback" msgid="1780431884109392046">"Danos tu opinión"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"Español (EE.UU.)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglés (Reino Unido) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglés (EE.UU.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Español (EE.UU.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglés (Reino Unido) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglés (EE.UU.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Español (EE.UU.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cirílico)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latinoamérica)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Ningún idioma (alfabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leer archivo de diccionario externo"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"No hay archivos de diccionario en la carpeta de descargas."</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selecciona un archivo de diccionario para instalar"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"¿Seguro que quieres instalar este archivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"¿Seguro que quieres instalar este archivo para <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Se ha producido un error"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Generar diccionario de contactos"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Volcar diccionario personal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Volcar diccionario historial usuario"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Volcar diccionario personalización"</string> <string name="button_default" msgid="3988017840431881491">"Predeterminado"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Te damos la bienvenida a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"con escritura gestual"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualizar"</string> <string name="last_update" msgid="730467549913588780">"Última actualización"</string> <string name="message_updating" msgid="4457761393932375219">"Buscando actualizaciones"</string> - <string name="message_loading" msgid="8689096636874758814">"Cargando..."</string> + <string name="message_loading" msgid="5638680861387748936">"Cargando…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Diccionario principal"</string> <string name="cancel" msgid="6830980399865683324">"Cancelar"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Ajustes"</string> <string name="install_dict" msgid="180852772562189365">"Instalar"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancelar"</string> <string name="delete_dict" msgid="756853268088330054">"Eliminar"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Hay un diccionario disponible para el idioma seleccionado en tu dispositivo móvil.<br/> Te recomendamos que <b>descargues</b> el diccionario de <xliff:g id="LANGUAGE">%1$s</xliff:g> para mejorar tu experiencia de escritura.<br/> <br/> La descarga puede tardar unos minutos en redes 3G. Si no tienes un <b>plan de datos ilimitado</b>, se pueden aplicar cargos.<br/> Si no conoces las características de tu plan de datos, te recomendamos que uses una conexión Wi-Fi para iniciar la descarga automáticamente.<br/> <br/> Sugerencia: puedes descargar y eliminar diccionarios en la sección <b>Idioma e introducción de texto</b> del menú <b>Ajustes</b> del dispositivo móvil."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Hay un diccionario disponible para el idioma seleccionado en tu dispositivo móvil.<br/> Te recomendamos que <b>descargues</b> el diccionario de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para mejorar la experiencia de escritura.<br/> <br/> La descarga puede tardar unos minutos en redes 3G. Es posible que se apliquen cargos si no tienes un <b>plan de datos ilimitado</b>.<br/> Si no sabes con certeza cuál es tu plan de datos, te recomendamos que te conectes a una red Wi-Fi para que la descarga empiece automáticamente.<br/> <br/> Consejo: Puedes descargar y eliminar diccionarios en la sección <b>Idioma e introducción de texto</b> en el menú <b>Ajustes</b> de tu dispositivo móvil."</string> <string name="download_over_metered" msgid="1643065851159409546">"Descargar ahora (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Descargar mediante Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Hay un diccionario disponible de <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Hay disponible un diccionario de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pulsa para comprobar y descargar"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Descargando: las sugerencias de <xliff:g id="LANGUAGE">%1$s</xliff:g> estarán disponibles en breve."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"La descarga de sugerencias para <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> estará disponible próximamente."</string> <string name="version_text" msgid="2715354215568469385">"Versión <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Añadir"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Añadir al diccionario"</string> diff --git a/java/res/values-et-rEE/strings-config-important-notice.xml b/java/res/values-et-rEE/strings-config-important-notice.xml new file mode 100644 index 000000000..1c363d697 --- /dev/null +++ b/java/res/values-et-rEE/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Kommunikats. ja sisestatud andmetest õppimine soovit. täiustamiseks"</string> +</resources> diff --git a/java/res/values-et-rEE/strings-talkback-descriptions.xml b/java/res/values-et-rEE/strings-talkback-descriptions.xml new file mode 100644 index 000000000..5a359c1a3 --- /dev/null +++ b/java/res/values-et-rEE/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Parooliklahvide kuulamiseks ühendage peakomplekt."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Praegune tekst on %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Teksti ei ole sisestatud"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> parandab sõna <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> järgmiselt: <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> teeb automaatse paranduse"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Klahvi kood: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Tõstuklahv"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Tõstuklahv sees (puudutage keelamiseks)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Suurtähelukk on sees (puudutage keelamiseks)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Kustutamine"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Sümbolid"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Tähed"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Numbrid"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Seaded"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulaator"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Tühik"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Häälsisend"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emotikon"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Tagasi"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Otsing"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punkt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Keele vahetamine"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Järgmine"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Eelmine"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Tõstuklahv on lubatud"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Suurtähelukk on lubatud"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Tõstuklahv on keelatud"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Sümbolite režiim"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Tähtede režiim"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefonirežiim"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefoni sümbolite režiim"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klaviatuur on peidetud"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Näitab klaviatuuri režiimil <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"kuupäev"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"kuupäev ja kellaaeg"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-post"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"sõnumiside"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"number"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"aeg"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Hiljutised"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Inimesed"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objektid"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Loodus"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Kohad"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Sümbolid"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikonid"</string> +</resources> diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml index e0f992c0d..6fbc4b40c 100644 --- a/java/res/values-et-rEE/strings.xml +++ b/java/res/values-et-rEE/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Süsteemi vaikeväärt."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Soovita kontaktkirjeid"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Kasuta soovitusteks ja parandusteks nimesid kontaktiloendist"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Isikupärast. soovitused"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punkt tühikuklahviga"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tühikuklahvi kaks korda puudutades sisestatakse punkt ja tühik"</string> <string name="auto_cap" msgid="1719746674854628252">"Automaatne suurtähtede kasutamine"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Näita liigutuse jälge"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dünaamiline ujuv eelvaade"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Soovitatud sõna vaatamine joonistusega sisestamise ajal"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : salvestatud"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Ühendage peakomplekt, et kuulata paroole."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Praegune tekst on %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Teksti ei ole sisestatud"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Klahvi <xliff:g id="KEY">%1$s</xliff:g> vajutamisel parandatakse sõna <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> sõnaks <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Klahvi <xliff:g id="KEY">%1$s</xliff:g> vajutamisel tehakse automaatne parandus"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Klahvi kood: %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Tõstuklahv"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Tõstuklahv sees (puudutage keelamiseks)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Suurtähelukk on sees (puudutage keelamiseks)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Kustuta"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Sümbolid"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Tähed"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbrid"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Seaded"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulaator"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Tühik"</string> - <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_search" msgid="1247236163755920808">"Otsing"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Keele vahetamine"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Järgmine"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Eelmine"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Tõstuklahv on lubatud"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Suurtähelukk on lubatud"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Tõstuklahv on keelatud"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Sümbolite režiim"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Tähtede režiim"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefonirežiim"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefoni sümbolite režiim"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klaviatuur on peidetud"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Näitab klaviatuuri režiimil <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"kuupäev"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"kuupäev ja kellaaeg"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-post"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"sõnumiside"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"number"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"aeg"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Fraasi liigutus"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Sisestage liigutuste kasutamisel tühikuid, libistades tühikuklahvile"</string> <string name="voice_input" msgid="3583258583521397548">"Häälesisendi klahv"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Peamisel klaviatuuril"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sümbolite klaviatuuril"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Väljas"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon peamisel klaviatuuril"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. sümb. klaviat."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Kõnesisend on keelatud"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ühtegi häälsisendmeetodit pole lubatud. Kontrollige keele- ja sisendiseadeid."</string> <string name="configure_input_method" msgid="373356270290742459">"Sisestusmeetodite seadistamine"</string> <string name="language_selection_title" msgid="1651299598555326750">"Sisestuskeeled"</string> <string name="send_feedback" msgid="1780431884109392046">"Saatke tagasisidet"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Inglise (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglise (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"hispaania (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglise (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglise (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"hispaania (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditsiooniline)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglise (Ühendk.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglise (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Hispaania (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditsiooniline)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kirillitsa)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ladina)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Keel puudub (tähestik)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Tähestik (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Tähestik (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Välise sõnastikufaili lugemine"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Kaustas Allalaadimised pole ühtegi sõnastikufaili"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Installitava sõnastikufaili valimine"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Kas soovite tõesti installida faili lokaadile <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Kas soovite tõesti installida faili <xliff:g id="LANGUAGE_NAME">%s</xliff:g> keele jaoks?"</string> <string name="error" msgid="8940763624668513648">"Ilmnes viga"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Kontaktisõnastiku tõmmistamine"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Isikliku sõnastiku tõmmistamine"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Kasutaja ajaloo sõnastiku tõmmist."</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Isikupärast. sõnastiku tõmmistamine"</string> <string name="button_default" msgid="3988017840431881491">"Vaikeväärtus"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Tere tulemast rakendusse <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"joonistusega sisestamisega"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Värskenda"</string> <string name="last_update" msgid="730467549913588780">"Viimati värskendatud"</string> <string name="message_updating" msgid="4457761393932375219">"Värskenduste otsimine"</string> - <string name="message_loading" msgid="8689096636874758814">"Laadimine ..."</string> + <string name="message_loading" msgid="5638680861387748936">"Laadimine …"</string> <string name="main_dict_description" msgid="3072821352793492143">"Peamine sõnastik"</string> <string name="cancel" msgid="6830980399865683324">"Tühista"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Seaded"</string> <string name="install_dict" msgid="180852772562189365">"Installi"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Tühista"</string> <string name="delete_dict" msgid="756853268088330054">"Kustuta"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Mobiilseadmes valitud keelele on saadaval sõnastik.<br/> Teksti mugavamaks sisestamiseks soovitame <b>alla laadida</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> keele sõnastiku.<br/> <br/> 3G kaudu allalaadimisele võib kuluda minut või paar. Kehtida võivad tasud, kui te ei kasuta <b>piiramatut andmepaketti</b>.<br/> Kui te ei tea, millist andmepaketti kasutate, soovitame allalaadimise automaatseks käivitamiseks leida WiFi-ühenduse.<br/> <br/> Nõuanne: sõnastikke saate alla laadida ja eemaldada, tehes valiku <b>Keel ja sisestamine</b> mobiilseadme menüüs <b>Seaded</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobiilseadmes valitud keelele on saadaval sõnastik.<br/> Teksti mugavamaks sisestamiseks soovitame <b>alla laadida</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> keele sõnastiku.<br/> <br/> 3G kaudu allalaadimisele võib kuluda minut või paar. Kui te ei kasuta <b>piiramatut andmepaketti</b>, võivad rakenduda tasud.<br/> Kui te ei tea, millist andmepaketti kasutate, soovitame allalaadimise automaatseks käivitamiseks leida WiFi-ühenduse.<br/> <br/> Nõuanne: sõnastikke saate alla laadida ja eemaldada, tehes mobiilseadme menüüs <b>Seaded</b> valiku <b>Keel ja sisend</b>."</string> <string name="download_over_metered" msgid="1643065851159409546">"Laadi kohe alla (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Laadi alla WiFi kaudu"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Sõnastik on <xliff:g id="LANGUAGE">%1$s</xliff:g> keele jaoks saadaval"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Sõnastik on saadaval <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> keeles"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Vajutage ülevaatamiseks ja allalaadimiseks"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Allalaadimine: <xliff:g id="LANGUAGE">%1$s</xliff:g> keele soovitused on varsti saadaval."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Allalaadimine: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> keele soovitused on peagi saadaval."</string> <string name="version_text" msgid="2715354215568469385">"Versioon <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Lisa"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Sõnaraamatusse lisamine"</string> diff --git a/java/res/values-fa-sw600dp/donottranslate-config-spacing-and-punctuations.xml b/java/res/values-fa-sw600dp/donottranslate-config-spacing-and-punctuations.xml new file mode 100644 index 000000000..d7aca6fb4 --- /dev/null +++ b/java/res/values-fa-sw600dp/donottranslate-config-spacing-and-punctuations.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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 --> + <!-- U+061F: "؟" ARABIC QUESTION MARK + U+061B: "؛" ARABIC SEMICOLON --> + <string name="suggested_punctuations">!,؟,:,؛,\",\',(|),)|(,-,/,@,_</string> +</resources> diff --git a/java/res/values-fa/donottranslate-config-spacing-and-punctuations.xml b/java/res/values-fa/donottranslate-config-spacing-and-punctuations.xml new file mode 100644 index 000000000..21bb3318f --- /dev/null +++ b/java/res/values-fa/donottranslate-config-spacing-and-punctuations.xml @@ -0,0 +1,28 @@ +<?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 --> + <!-- U+061F: "؟" ARABIC QUESTION MARK + U+060C: "،" ARABIC COMMA + U+061B: "؛" ARABIC SEMICOLON --> + <string name="suggested_punctuations">!,؟,،,:,؛,\",(|),)|(,\',-,/,@,_</string> +</resources> diff --git a/java/res/values-fa/strings-config-important-notice.xml b/java/res/values-fa/strings-config-important-notice.xml new file mode 100644 index 000000000..22a50cd4a --- /dev/null +++ b/java/res/values-fa/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"یادگیری از ارتباطات و اطلاعات تایپ شده شما برای بهبود پیشنهادات"</string> +</resources> diff --git a/java/res/values-fa/strings-talkback-descriptions.xml b/java/res/values-fa/strings-talkback-descriptions.xml new file mode 100644 index 000000000..26e99cb7b --- /dev/null +++ b/java/res/values-fa/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"برای شنیدن کلیدهای گذرواژه که با صدای بلند خوانده میشوند، از هدست استفاده کنید."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"نوشتار کنونی %s است"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"نوشتاری وارد نشده است"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g>، <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> را به <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> تصحیح میکند"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> تصحیح خودکار را انجام میدهد"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"کد کلید %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift روشن است (برای غیرفعال کردن ضربه بزنید)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock روشن است (برای غیرفعال کردن ضربه بزنید)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"حذف"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"نمادها"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"حروف"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"اعداد"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"تنظیمات"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"فاصله"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"ورودی صدا"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"شکلک Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"بازگشت"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"جستجو"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"نقطه"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"تغییر زبان"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"بعدی"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"قبلی"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift فعال شد"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock فعال شد"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift غیرفعال شد"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"حالت نمادها"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"حالت حروف"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"حالت تلفن"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"حالت نمادهای تلفن"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"صفحهکلید پنهان است"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"در حال نمایش صفحهکلید <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"تاریخ"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"تاریخ و زمان"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ایمیل"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"پیامرسانی"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"عدد"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"تلفن"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"نوشتار"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"زمان"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"نشانی اینترنتی"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"موارد اخیر"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"افراد"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"اشیاء"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"طبیعت"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"مکانها"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"نمادها"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"شکلکها"</string> +</resources> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index af886ef8c..04c6a5aca 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"پیشفرض سیستم"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"پیشنهاد نامهای مخاطب"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"پیشنهادات شخصی شده"</string> <string name="use_double_space_period" msgid="8781529969425082860">"نقطه با دو فاصله"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"با دوبار ضربه روی دکمه فاصله نقطه با یک فاصله بعد آن درج میشود"</string> <string name="auto_cap" msgid="1719746674854628252">"بزرگکردن خودکار حروف"</string> @@ -73,60 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"نمایش نسخه آزمایشی حرکت"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"پیشنمایش متحرک پویا"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"مشاهده کلمه پیشنهادی در حین انجام حرکات"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"برای شنیدن کلیدهای گذرواژه که با صدای بلند خوانده میشوند، از هدست استفاده کنید."</string> - <!-- String.format failed for translation --> - <!-- no translation found for spoken_current_text_is (2485723011272583845) --> - <skip /> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"متنی وارد نشده است"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g>، <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> را به <xliff:g id="CORRECTED">%3$s</xliff:g> تصحیح میکند"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> تصحیح خودکار را انجام میدهد"</string> - <!-- String.format failed for translation --> - <!-- no translation found for spoken_description_unknown (3197434010402179157) --> - <skip /> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift فعال است (برای غیرفعال کردن ضربه بزنید)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock روشن است (برای غیرفعال کردن ضربه بزنید)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"نمادها"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"حروف"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"اعداد"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"تنظیمات"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"فاصله"</string> - <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_search" msgid="1247236163755920808">"جستجو"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"نقطه"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"تغییر زبان"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"بعدی"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"قبلی"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift فعال است"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock فعال شد"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift غیرفعال است"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"حالت نمادها"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"حالت حروف"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"حالت تلفن"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"حالت نمادهای تلفن"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"صفحه کلید پنهان شد"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"نمایش صفحه کلید <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"تاریخ"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"تاریخ و زمان"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"ایمیل"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"پیامرسانی"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"عدد"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"تلفن"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"نوشتار"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"زمان"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"نشانی اینترنتی"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"ورود عبارت با حرکت اشارهای"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"با سراندن انگشت به کلید فاصله در زمان اشارهها، فاصله را وارد کنید"</string> <string name="voice_input" msgid="3583258583521397548">"کلید ورودی صدا"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"در صفحهکلید اصلی"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"در صفحهکلید نمادها"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"خاموش"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"میکروفن در صفحهکلید اصلی"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"میکروفن در صفحهکلید نمادها"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ورودی صدا غیرفعال است"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"هیچ روش ورودی صوتی فعال نشده است. تنظیمات زبان و ورودی را بررسی کنید."</string> <string name="configure_input_method" msgid="373356270290742459">"پیکربندی روشهای ورودی"</string> <string name="language_selection_title" msgid="1651299598555326750">"زبانهای ورودی"</string> <string name="send_feedback" msgid="1780431884109392046">"ارسال بازخورد"</string> @@ -139,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"انگلیسی (بریتانیا)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"انگلیسی (امریکا)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"اسپانیایی (آمریکا)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"انگلیسی (انگلستان) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"انگلیسی (ایالات متحده) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"اسپانیایی (آمریکا) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (سنتی)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"انگلیسی (بریتانیا) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"انگلیسی (آمریکا) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"اسپانیایی (آمریکا) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (سنتی)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (سیریلیک)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (لاتین)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"بدون زبان (حروف الفبا)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"حروف الفبا (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"حروف الفبا (QWERTZ)"</string> @@ -172,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"خواندن فایل فرهنگ لغت خارجی"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"فایل فرهنگ لغتی در پوشه دانلودها وجود ندارد"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"یک فایل فرهنگ لغت برای نصب انتخاب کنید"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"این فایل واقعاً برای <xliff:g id="LOCALE_NAME">%s</xliff:g> نصب شود؟"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"این فایل واقعاً برای <xliff:g id="LANGUAGE_NAME">%s</xliff:g> نصب شود؟"</string> <string name="error" msgid="8940763624668513648">"خطایی روی داد"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ایجاد فهرست کلی واژهنامه مخاطبین"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"ایجاد فهرست کلی واژهنامه شخصی"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ایجاد فهرست کلی واژهنامه سابقه کاربر"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"ایجاد فهرست کلی واژهنامه شخصیسازی"</string> <string name="button_default" msgid="3988017840431881491">"پیشفرض"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"به <xliff:g id="APPLICATION_NAME">%s</xliff:g> خوش آمدید"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"با ورودی اشارهای"</string> @@ -211,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"بازخوانی"</string> <string name="last_update" msgid="730467549913588780">"آخرین بهروزرسانی"</string> <string name="message_updating" msgid="4457761393932375219">"در حال بررسی بهروزرسانیها"</string> - <string name="message_loading" msgid="8689096636874758814">"در حال بارگیری…"</string> + <string name="message_loading" msgid="5638680861387748936">"در حال بارگیری…"</string> <string name="main_dict_description" msgid="3072821352793492143">"فرهنگ لغت اصلی"</string> <string name="cancel" msgid="6830980399865683324">"لغو"</string> + <string name="go_to_settings" msgid="3876892339342569259">"تنظیمات"</string> <string name="install_dict" msgid="180852772562189365">"نصب"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"لغو"</string> <string name="delete_dict" msgid="756853268088330054">"حذف"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"برای زبان انتخاب شده در دستگاه همراه شما فرهنگ لغتی موجود است.<br/> توصیه میکنیم فرهنگ لغت <xliff:g id="LANGUAGE">%1$s</xliff:g> را <b>دانلود کنید</b> تا بهتر تایپ کنید.<br/> <br/> دانلود از طریق 3G ممکن است چند لحظه طول بکشد. اگر <b>طرح داده نامحدود</b> نداشته باشید ممکن است برایتان هزینه داشته باشد.<br/> اگر مطمئن نیستید طرح داده شما چیست٬ توصیه میکنیم یک اتصال Wi-Fi پیدا کنید تا دانلود بطور خودکار شروع شود.<br/> <br/> نکته: میتوانید فرهنگ لغت را با رفتن به منوی <b>زبان و ورودی</b> در <b>تنظیمات</b> در دستگاه همراه خود دانلود و حذف کنید."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"برای زبان انتخاب شده در دستگاه همراه شما فرهنگ لغتی در دسترس است.<br/> توصیه میکنیم برای بهبود بخشیدن به تجربه تایپ کردنتان، فرهنگ لغت <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> را <b>دانلود کنید</b>.<br/> <br/> دانلود از طریق 3G ممکن است یک یا دو دقیقه طول بکشد. اگر <b>طرح داده نامحدود</b> نداشته باشید، ممکن است هزینههایی برای شما اعمال شوند.<br/> اگر مطمئن نیستید چه طرح دادهای دارید٬ توصیه میکنیم یک اتصال Wi-Fi بیابید تا دانلود به طور خودکار شروع شود.<br/> <br/> نکته: با رفتن به بخش <b>زبان و ورودی</b> در منوی <b>تنظیمات</b> دستگاهتان، فرهنگهای لغت را دانلود یا حذف کنید."</string> <string name="download_over_metered" msgid="1643065851159409546">"هماکنون بارگیری شود (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> مگابایت)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"دانلود ازطریق Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"یک فرهنگ لغت برای <xliff:g id="LANGUAGE">%1$s</xliff:g> موجود است"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"یک فرهنگ لغت برای <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> در دسترس است"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"برای مرور و دانلود فشار دهید"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"دانلود لغات پیشنهادی برای <xliff:g id="LANGUAGE">%1$s</xliff:g> به زودی شروع میشود."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"دانلود کردن پیشنهادات برای <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> به زودی شروع میشود."</string> <string name="version_text" msgid="2715354215568469385">"نسخه <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"افرودن"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"افزودن به فرهنگ لغت"</string> diff --git a/java/res/values-fi/strings-config-important-notice.xml b/java/res/values-fi/strings-config-important-notice.xml new file mode 100644 index 000000000..ad064c0a7 --- /dev/null +++ b/java/res/values-fi/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Ehdotusten parannus viestinnän ja kirjoitettujen tietojen avulla"</string> +</resources> diff --git a/java/res/values-fi/strings-talkback-descriptions.xml b/java/res/values-fi/strings-talkback-descriptions.xml new file mode 100644 index 000000000..2d0d7a782 --- /dev/null +++ b/java/res/values-fi/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Liitä kuulokkeet, niin kuulet mitä näppäimiä painat kirjoittaessasi salasanaa."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Nykyinen teksti on %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Ei kirjoitettua tekstiä"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> korjaa sanan <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> sanaksi <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> suorittaa automaattisen korjauksen"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Näppäimen koodi %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Vaihto"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Vaihto päällä (poista käytöstä napauttamalla)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock päällä (poista käytöstä napauttamalla)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Delete"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbolit"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Kirjaimet"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Numerot"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Asetukset"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Sarkain"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Välilyönti"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Äänisyöte"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Haku"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Piste"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Vaihda kieli"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Seuraava"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Edellinen"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Vaihto päällä"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock päällä"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Vaihto pois päältä"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbolit-tila"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Näppäimistötila"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Puhelintila"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Puhelinsymbolit-tila"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Näppäimistö on piilotettu"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Näytetään näppäimistö <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"päivämäärä"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"päivämäärä ja aika"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"sähköposti"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"viestit"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"numero"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"puhelin"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teksti"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"aika"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL-osoite"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Viimeisimmät"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Ihmiset"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Esineet"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Luonto"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Paikat"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbolit"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Hymiöt"</string> +</resources> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index a58bfac3e..756684ae0 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Järjestelmän oletusarvo"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yht.tietojen nimiä"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Käytä yhteystietojen nimiä ehdotuksissa ja korjauksissa"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Räätälöidyt ehdotukset"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kaksoisvälilyönti = piste"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Välilyönnin kaksoisnapautus lisää tekstiin pisteen ja välilyönnin"</string> <string name="auto_cap" msgid="1719746674854628252">"Automaattiset isot kirjaimet"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Näytä eleen jälki"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynaaminen kelluva esikatselu"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Näytä ehdotettu sana piirron aikana"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: tallennettu"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Liitä kuulokkeet, niin kuulet mitä näppäimiä painat kirjoittaessasi salasanaa."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Nykyinen teksti on %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Ei kirjoitettua tekstiä"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> korjaa sanan <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> sanaksi <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> suorittaa automaattisen korjauksen"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Näppäimen koodi %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Vaihto"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Vaihto päällä (poista käytöstä napauttamalla)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock päällä (poista käytöstä napauttamalla)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Poista"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbolit"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Kirjaimet"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numerot"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Asetukset"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Sarkain"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Välilyönti"</string> - <string name="spoken_description_mic" msgid="615536748882611950">"Äänisyöte"</string> - <string name="spoken_description_smiley" msgid="2256309826200113918">"Hymiö"</string> - <string name="spoken_description_return" msgid="8178083177238315647">"Takaisin"</string> - <string name="spoken_description_search" msgid="1247236163755920808">"Haku"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Piste"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Vaihda kieli"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Seuraava"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Edellinen"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Vaihto päällä"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock päällä"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Vaihto pois käytöstä"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolit-tila"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Näppäimistötila"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Puhelintila"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Puhelinsymbolit-tila"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Näppäimistö on piilotettu"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Näytetään <xliff:g id="MODE">%s</xliff:g>-näppäimistö"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"päivämäärä"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"päivämäärä ja aika"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"sähköposti"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"viestit"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"numero"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"puhelin"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teksti"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"aika"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL-osoite"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Ilmausele"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Lisää välilyöntejä eleiden aikana liukumalla välilyöntinäppäim."</string> <string name="voice_input" msgid="3583258583521397548">"Äänisyöteavain"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Päänäppäimistössä"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Symbolinäppäim."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Ei käytössä"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr. päänäppäim."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. symbolinäpp."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Äänisyöte ei käyt."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Äänen syöttötapoja ei ole otettu käyttöön. Tarkista Kieli ja syöttötapa -asetukset."</string> <string name="configure_input_method" msgid="373356270290742459">"Määritä syöttötavat"</string> <string name="language_selection_title" msgid="1651299598555326750">"Syöttökielet"</string> <string name="send_feedback" msgid="1780431884109392046">"Lähetä palautetta"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"englanti (Iso-Britannia)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"englanti (Yhdysvallat)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"espanja (Yhdysvallat)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"englanti (Iso-Br.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"englanti (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"espanja (Yhdysvallat) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (perinteinen)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"englanti (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"englanti (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"espanja (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (perinteinen)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kyrillinen)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinalainen)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Ei kieltä (aakkoset)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Aakkoset (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Aakkoset (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lue ulkoista sanakirjatiedostoa"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Lataukset-kansiossa ei ole sanakirjatiedostoja"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Valitse asennettava sanakirjatiedosto"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Haluatko asentaa tämä tiedoston kielelle <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Haluatko asentaa tämän tiedoston kielelle <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Tapahtui virhe"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Vedosta yhteystietosanakirja"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Vedosta oma sanakirja"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Vedosta käyttäjähistorian sanakirja"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Vedosta muokkaussanakirja"</string> <string name="button_default" msgid="3988017840431881491">"Oletusarvot"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Tervetuloa käyttämään sovellusta <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"ja piirtokirjoitus"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Päivitä"</string> <string name="last_update" msgid="730467549913588780">"Päivitetty viimeksi"</string> <string name="message_updating" msgid="4457761393932375219">"Tarkistetaan päivityksiä"</string> - <string name="message_loading" msgid="8689096636874758814">"Ladataan…"</string> + <string name="message_loading" msgid="5638680861387748936">"Ladataan…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Pääsanakirja"</string> <string name="cancel" msgid="6830980399865683324">"Peruuta"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Asetukset"</string> <string name="install_dict" msgid="180852772562189365">"Asenna"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Peruuta"</string> <string name="delete_dict" msgid="756853268088330054">"Poista"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Laitteesi käyttökielelle on saatavilla sanakirja.<br/> Suosittelemme <xliff:g id="LANGUAGE">%1$s</xliff:g>-sanakirjan <b>lataamista</b>, sillä se helpottaa laitteella kirjoittamista.<br/> <br/> Lataus kestää useimmiten muutaman minuutin 3G-yhteydellä. Latauksesta saatetaan periä maksu, ellei käytössäsi ole <b>rajoittamatonta tiedonsiirtopakettia</b>.<br/> Jos et ole varma tiedonsiirtosopimuksesi tyypistä, etsi käyttöösi wifi-yhteys, niin lataus alkaa automaattisesti.<br/> <br/> Vinkki: voit ladata ja poistaa sanakirjoja mobiililaitteesi <b>Asetukset</b>-valikon <b>Kieli ja syöttötapa</b> -osiossa."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Laitteesi käyttökielelle on saatavilla sanakirja.<br/> Suosittelemme <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-sanakirjan <b>lataamista</b>, sillä se helpottaa laitteella kirjoittamista.<br/> <br/> Lataus kestää useimmiten muutaman minuutin 3G-yhteydellä. Latauksesta saatetaan periä maksu, ellei käytössäsi ole <b>rajoittamatonta tiedonsiirtopakettia</b>.<br/> Jos et ole varma tiedonsiirtosopimuksesi tyypistä, etsi käyttöösi wifi-yhteys, niin lataus alkaa automaattisesti.<br/> <br/> Vinkki: voit ladata ja poistaa sanakirjoja mobiililaitteesi <b>Asetukset</b>-valikon <b>Kieli ja syöttötapa</b> -osiossa."</string> <string name="download_over_metered" msgid="1643065851159409546">"Lataa nyt (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> Mt)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Lataa wifi-yhteydellä"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Kielen <xliff:g id="LANGUAGE">%1$s</xliff:g> sanakirja on saatavilla"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Sanakirja on saatavilla kielelle <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Paina tätä, jos haluat tarkastella kohdetta ja ladata sen"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Ladataan: ehdotuksia näytetään pian kielellä <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Ladataan: kielen <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ehdotukset ovat pian käytettävissä."</string> <string name="version_text" msgid="2715354215568469385">"Versio <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Lisää"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Lisää sanakirjaan"</string> diff --git a/java/res/values-fr-rCA/donottranslate.xml b/java/res/values-fr-rCA/donottranslate-config-spacing-and-punctuations.xml index 21f18d852..e4c30c4d7 100644 --- a/java/res/values-fr-rCA/donottranslate.xml +++ b/java/res/values-fr-rCA/donottranslate-config-spacing-and-punctuations.xml @@ -25,7 +25,7 @@ <string name="symbols_followed_by_space">.,;:!?)]}&</string> <!-- Symbols that separate words --> <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> - <string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string> + <string name="symbols_word_separators">"	 
 "()[]{}*&<>+=|.,;:!?/_\"</string> <!-- Word connectors --> <string name="symbols_word_connectors">\'-</string> </resources> diff --git a/java/res/values-fr-rCA/strings-config-important-notice.xml b/java/res/values-fr-rCA/strings-config-important-notice.xml new file mode 100644 index 000000000..2247ec6cc --- /dev/null +++ b/java/res/values-fr-rCA/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Apprendre de vos communic. et données entrées pour amél. suggestions"</string> +</resources> diff --git a/java/res/values-fr-rCA/strings-talkback-descriptions.xml b/java/res/values-fr-rCA/strings-talkback-descriptions.xml new file mode 100644 index 000000000..b632edca3 --- /dev/null +++ b/java/res/values-fr-rCA/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Branchez des écouteurs pour entendre l\'énoncé à haute voix des touches lors de l\'entrée du mot de passe."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Le texte actuel est %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Aucun texte entré"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet de remplacer <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> par <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet d\'effectuer une correction automatique"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Code touche %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Majuscule"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Touche Majuscule activée (toucher pour désactiver)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Verrouillage des majuscules activé (toucher pour désactiver)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Supprimer"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboles"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Lettres"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Chiffres"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Paramètres"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulation"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espace"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrée vocale"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Retour"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Recherche"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Point"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Changer de langue"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Suivante"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Précédente"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Touche Maj activée"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Verrouillage des majuscules activé"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Touche Majuscule désactivée"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Mode Symboles"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Mode Lettres"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Mode Téléphone"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Mode Symboles du téléphone"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Clavier masqué"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Affichage du clavier <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"date"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"date et heure"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"courriel"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"messagerie"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"numérique"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"téléphone"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"texte"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"heure"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Récents"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personnes"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objets"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Nature"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Lieux"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboles"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Émoticônes"</string> +</resources> diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml index 2551ce9f8..5b1308166 100644 --- a/java/res/values-fr-rCA/strings.xml +++ b/java/res/values-fr-rCA/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Paramètres par défaut"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Suggestions personnalisées"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Appuyez deux fois sur la barre d\'espace pour insérer un point et une espace"</string> <string name="auto_cap" msgid="1719746674854628252">"Majuscules automatiques"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Afficher le tracé du geste"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Aperçu flottant dynamique"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Afficher le mot suggéré lors des gestes"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Branchez des écouteurs pour entendre l\'énoncé à haute voix des touches lors de la saisie du mot de passe."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Le texte actuel est %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Aucun texte saisi"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"La touche <xliff:g id="KEY">%1$s</xliff:g> permet de corriger « <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> » par « <xliff:g id="CORRECTED">%3$s</xliff:g> »"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"La touche <xliff:g id="KEY">%1$s</xliff:g> permet d\'activer la correction automatique"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Code touche %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Maj"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Touche Maj activée (appuyer pour désactiver)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Verrouillage des majuscules activé (appuyer pour désactiver)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Supprimer"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboles"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Lettres"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Nombres"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Paramètres"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Onglet"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espace"</string> - <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">"Renvoyer"</string> - <string name="spoken_description_search" msgid="1247236163755920808">"Rechercher"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Point"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Changer de langue"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Suivant"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Précédent"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Touche Maj activée"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Verrouillage des majuscules activé"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Touche Maj désactivée"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode Symboles"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode Lettres"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode Téléphone"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode Symboles du téléphone"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Clavier masqué"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Affichage du clavier <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"Date"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"Date et heure"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"Courriel"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"SMS/MMS"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"Nombre"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"Numéro de téléphone"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"Texte"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Geste multiterme"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Insérer une espace avec barre d\'espace lors de l\'entrée gestuelle"</string> <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sur le clavier principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sur clavier symboles"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Désactiver"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro sur le clavier principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro sur le clavier des symboles"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Saisie vocale désactivée"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode d\'entrée vocale n\'a été activé. Vérifiez les paramètres de langues et d\'entrée de texte."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string> <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string> <string name="send_feedback" msgid="1780431884109392046">"Envoyer des commentaires"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Anglais (britannique)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglais (États-Unis)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Espagnol (États-Unis)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Anglais (Royaume-Uni) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Anglais (États-Unis) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Espagnol, États-Unis (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditionnel)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"anglais (Royaume-Uni) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"anglais (États-Unis) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"espagnol (États-Unis) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionnel)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cyrillique)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Aucune langue (alphabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alphabet latin (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alphabet latin (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lire un fichier de dictionnaire externe"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Aucun fichier de dictionnaire dans le dossier \"Téléchargements\""</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Sélectionner un fichier de dictionnaire à installer"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Installer ce fichier pour la langue \"<xliff:g id="LOCALE_NAME">%s</xliff:g>\" ?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Installer ce fichier pour la langue « <xliff:g id="LANGUAGE_NAME">%s</xliff:g> »?"</string> <string name="error" msgid="8940763624668513648">"Une erreur s\'est produite"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Extraire dictionnaire des contacts"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Vider le dictionnaire personnel"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Vider dictionnaire hist. utilisateur"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Vider dictionnaire personnalisation"</string> <string name="button_default" msgid="3988017840431881491">"Par défaut"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Bienvenue dans <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"avec la saisie gestuelle"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualiser"</string> <string name="last_update" msgid="730467549913588780">"Dernière mise à jour"</string> <string name="message_updating" msgid="4457761393932375219">"Recherche de mises à jour en cours…"</string> - <string name="message_loading" msgid="8689096636874758814">"Chargement en cours..."</string> + <string name="message_loading" msgid="5638680861387748936">"Chargement en cours…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Dictionnaire principal"</string> <string name="cancel" msgid="6830980399865683324">"Annuler"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Paramètres"</string> <string name="install_dict" msgid="180852772562189365">"Installer"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Annuler"</string> <string name="delete_dict" msgid="756853268088330054">"Supprimer"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Un dictionnaire est disponible pour la langue sélectionnée sur votre appareil mobile.<br/> Nous vous invitons à <b>télécharger</b> le dictionnaire <xliff:g id="LANGUAGE">%1$s</xliff:g> pour faciliter votre saisie.<br/> <br/> Le téléchargement peut prendre une à deux minutes via une connexion 3G. Des frais peuvent s\'appliquer si vous ne disposez pas d\'un <b>forfait Internet illimité</b>.<br/> Si vous n\'êtes pas sûr de votre forfait, nous vous conseillons d\'utiliser une connexion Wi-Fi pour lancer automatiquement le téléchargement.<br/> <br/> Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section <b>Langue et saisie</b> du menu <b>Paramètres</b> de votre appareil mobile."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Un dictionnaire est offert pour la langue sélectionnée sur votre appareil mobile.<br/> Nous vous invitons à <b>télécharger</b> le dictionnaire pour la langue <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> pour faciliter votre réaction de texte.<br/> <br/> Le téléchargement peut prendre une à deux minutes par connexion 3G. Des frais peuvent s\'appliquer si vous ne disposez pas d\'un <b>forfait Internet illimité</b>.<br/> Si vous n\'êtes pas sûr de votre forfait, nous vous conseillons d\'utiliser une connexion Wi-Fi pour lancer automatiquement le téléchargement.<br/> <br/> Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section <b>Langue et entrée</b> du menu <b>Paramètres</b> de votre appareil mobile."</string> <string name="download_over_metered" msgid="1643065851159409546">"Télécharger (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> Mo)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Télécharger via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Un dictionnaire est disponible en <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Un dictionnaire est offert pour la langue suivante : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Appuyez ici pour consulter et télécharger le dictionnaire."</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"En cours de téléchargement. Des suggestions pour la langue suivante seront bientôt disponibles : <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Téléchargement en cours… Les suggestions seront bientôt offertes pour la langue suivante : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Ajouter"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Ajouter au dictionnaire"</string> diff --git a/java/res/values-fr/donottranslate.xml b/java/res/values-fr/donottranslate-config-spacing-and-punctuations.xml index f0644118a..d72f72b92 100644 --- a/java/res/values-fr/donottranslate.xml +++ b/java/res/values-fr/donottranslate-config-spacing-and-punctuations.xml @@ -24,7 +24,7 @@ <string name="symbols_followed_by_space">.,;:!?)]}&</string> <!-- Symbols that separate words --> <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> - <string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string> + <string name="symbols_word_separators">"	 
 "()[]{}*&<>+=|.,;:!?/_\"</string> <!-- Word connectors --> <string name="symbols_word_connectors">\'-</string> </resources> diff --git a/java/res/values-fr/strings-config-important-notice.xml b/java/res/values-fr/strings-config-important-notice.xml new file mode 100644 index 000000000..82bdcf5b0 --- /dev/null +++ b/java/res/values-fr/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Améliorer suggestions en fonction des messages et données saisies"</string> +</resources> diff --git a/java/res/values-fr/strings-talkback-descriptions.xml b/java/res/values-fr/strings-talkback-descriptions.xml new file mode 100644 index 000000000..efa140b49 --- /dev/null +++ b/java/res/values-fr/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Branchez des écouteurs pour entendre l\'énoncé à haute voix des touches lors de la saisie du mot de passe."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Le texte actuel est \"%s\"."</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Aucun texte saisi"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet de remplacer \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" par \"<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>\"."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet d\'effectuer une correction automatique."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Code touche %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Maj"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Touche Maj activée (appuyer pour désactiver)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Verrouillage des majuscules activé (appuyer pour désactiver)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Supprimer"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboles"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Lettres"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Chiffres"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Paramètres"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulation"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espace"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Saisie vocale"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Entrée"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Recherche"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Point"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Changer de langue"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Suivant"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Précédent"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"La touche Maj a bien été activée."</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Le verrouillage des majuscules a bien été activé."</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"La touche Maj a bien été désactivée."</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Mode Symboles"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Mode Lettres"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Mode Téléphone"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Mode Symboles du téléphone"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Clavier masqué"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Affichage du clavier <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"Date"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"Date et heure"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"Adresse e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"SMS/MMS"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"Chiffre"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"Numéro de téléphone"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"Texte"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"Heure"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Récents"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personnes"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objets"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Nature"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Lieux"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboles"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Émoticônes"</string> +</resources> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index b877db014..1bb856783 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Paramètres par défaut"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Suggestions personnalisées"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Appuyez deux fois sur la barre d\'espace pour insérer un point et un espace."</string> <string name="auto_cap" msgid="1719746674854628252">"Majuscules auto"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Afficher le tracé du geste"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Aperçu flottant dynamique"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Afficher le mot suggéré lors des gestes"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Branchez des écouteurs pour entendre l\'énoncé à haute voix des touches lors de la saisie du mot de passe."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Le texte actuel est %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Aucun texte saisi"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"La touche <xliff:g id="KEY">%1$s</xliff:g> permet de remplacer \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" par \"<xliff:g id="CORRECTED">%3$s</xliff:g>\"."</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"La touche <xliff:g id="KEY">%1$s</xliff:g> permet d\'activer la correction automatique."</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Code touche %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Maj"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Touche Maj activée (appuyer pour désactiver)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Verrouillage des majuscules activé (appuyer pour désactiver)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Supprimer"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboles"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Lettres"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Chiffres"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Paramètres"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulation"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espace"</string> - <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_search" msgid="1247236163755920808">"Rechercher"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Point"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Changer de langue"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Touche suivante"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Touche précédente"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Touche Maj activée"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Verrouillage des majuscules activé"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Touche Maj désactivée"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode Symboles"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode Lettres"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode Téléphone"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode Symboles du téléphone"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Clavier masqué"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Affichage du clavier <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"Date"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"Date et heure"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"Adresse e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"SMS/MMS"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"Chiffre"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"Numéro de téléphone"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"Texte"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Geste multiterme"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Insérer un espace avec barre d\'espace lors de la saisie gestuelle"</string> <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sur clavier principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sur clavier symboles"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Désactiver"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro sur le clavier principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro sur clavier symboles"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Saisie vocale désactivée"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode de saisie vocale activé. Vérifiez les paramètres de langue et de saisie."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string> <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string> <string name="send_feedback" msgid="1780431884109392046">"Envoyer des commentaires"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Anglais (Royaume-Uni)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglais (États-Unis)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Espagnol (États-Unis)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Anglais (Royaume-Uni) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Anglais (États-Unis) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Espagnol (États-Unis) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditionnel)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"anglais (Royaume-Uni) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"anglais (États-Unis) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"espagnol (États-Unis) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionnel)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cyrillique)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Aucune langue (latin)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alphabet latin (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alphabet latin (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Lire un fichier de dictionnaire externe"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Aucun fichier de dictionnaire dans le dossier \"Téléchargements\""</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Sélectionner un fichier de dictionnaire à installer"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Installer ce fichier pour la langue \"<xliff:g id="LOCALE_NAME">%s</xliff:g>\" ?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Installer ce fichier pour la langue \"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>\" ?"</string> <string name="error" msgid="8940763624668513648">"Une erreur s\'est produite"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Extraire dictionnaire des contacts"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Extraire le dictionnaire personnel"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Extraire dict. de l\'histor. util."</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Extraire dict. de personnalisation"</string> <string name="button_default" msgid="3988017840431881491">"Par défaut"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Bienvenue dans <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"avec la saisie gestuelle"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualiser"</string> <string name="last_update" msgid="730467549913588780">"Dernière mise à jour"</string> <string name="message_updating" msgid="4457761393932375219">"Recherche de mises à jour en cours…"</string> - <string name="message_loading" msgid="8689096636874758814">"Chargement en cours..."</string> + <string name="message_loading" msgid="5638680861387748936">"Chargement en cours…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Dictionnaire principal"</string> <string name="cancel" msgid="6830980399865683324">"Annuler"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Paramètres"</string> <string name="install_dict" msgid="180852772562189365">"Installer"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Annuler"</string> <string name="delete_dict" msgid="756853268088330054">"Supprimer"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Un dictionnaire est disponible pour la langue sélectionnée sur votre appareil mobile.<br/> Nous vous invitons à <b>télécharger</b> le dictionnaire <xliff:g id="LANGUAGE">%1$s</xliff:g> pour faciliter votre saisie.<br/> <br/> Le téléchargement peut prendre une à deux minutes via une connexion 3G. Des frais peuvent s\'appliquer si vous ne disposez pas d\'un <b>forfait Internet illimité</b>.<br/> Si vous n\'êtes pas sûr de votre forfait, nous vous conseillons d\'utiliser une connexion Wi-Fi pour lancer automatiquement le téléchargement.<br/> <br/> Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section <b>Langue et saisie</b> du menu <b>Paramètres</b> de votre appareil mobile."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Un dictionnaire est disponible pour la langue sélectionnée sur votre appareil mobile.<br/> Nous vous invitons à <b>télécharger</b> le dictionnaire pour cette langue : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Cela facilitera votre saisie.<br/> <br/> Le téléchargement peut prendre une à deux minutes via une connexion 3G. Des frais peuvent s\'appliquer si vous n\'avez pas un <b>forfait Internet illimité</b>.<br/> Si vous avez un doute concernant le type de forfait dont vous disposez, nous vous conseillons d\'utiliser le Wi-Fi pour lancer automatiquement le téléchargement.<br/> <br/> Astuce : Vous pouvez télécharger et supprimer des dictionnaires sous <b>Langue et saisie</b>, dans le menu <b>Paramètres</b> de votre appareil mobile."</string> <string name="download_over_metered" msgid="1643065851159409546">"Télécharger (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> Mo)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Télécharger via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Un dictionnaire est disponible en <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Un dictionnaire est disponible pour la langue suivante : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Appuyez ici pour consulter et télécharger le dictionnaire."</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"En cours de téléchargement. Des suggestions pour la langue suivante seront bientôt disponibles : <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Téléchargement en cours… Les suggestions seront bientôt disponibles pour la langue suivante : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Ajouter"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Ajouter au dictionnaire"</string> diff --git a/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml b/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml index bc7928d6a..adc3e35a9 100644 --- a/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml +++ b/java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">38sp</dimen> <dimen name="setup_step_bullet_text_size">24sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">24sp</dimen> <dimen name="setup_step_instruction_text_size">18sp</dimen> <dimen name="setup_step_action_text_size">20sp</dimen> diff --git a/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml b/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml index aebf6d2f3..1ff43ff9f 100644 --- a/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml +++ b/java/res/values-h330dp-land/setup-dimens-large-phone-land.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">22sp</dimen> <dimen name="setup_step_bullet_text_size">22sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">20sp</dimen> <dimen name="setup_step_instruction_text_size">16sp</dimen> <dimen name="setup_step_action_text_size">18sp</dimen> diff --git a/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml b/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml index aedf79fb2..a0e30cd37 100644 --- a/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml +++ b/java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">32sp</dimen> <dimen name="setup_step_bullet_text_size">24sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">24sp</dimen> <dimen name="setup_step_instruction_text_size">18sp</dimen> <dimen name="setup_step_action_text_size">20sp</dimen> diff --git a/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml b/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml index 6d66f46eb..cf2a10a9e 100644 --- a/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml +++ b/java/res/values-h540dp-port/setup-dimens-large-phone-port.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">26sp</dimen> <dimen name="setup_step_bullet_text_size">22sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">20sp</dimen> <dimen name="setup_step_instruction_text_size">16sp</dimen> <dimen name="setup_step_action_text_size">18sp</dimen> diff --git a/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml b/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml index e22b741fb..a782ef8f4 100644 --- a/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml +++ b/java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">38sp</dimen> <dimen name="setup_step_bullet_text_size">24sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">24sp</dimen> <dimen name="setup_step_instruction_text_size">18sp</dimen> <dimen name="setup_step_action_text_size">20sp</dimen> diff --git a/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml b/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml index 86cf3a04a..9ac0f115f 100644 --- a/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml +++ b/java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">36sp</dimen> <dimen name="setup_step_bullet_text_size">24sp</dimen> <dimen name="setup_step_triangle_indicator_height">24dp</dimen> - <dimen name="setup_step_indicator_height">24dp</dimen> <dimen name="setup_step_title_text_size">24sp</dimen> <dimen name="setup_step_instruction_text_size">18sp</dimen> <dimen name="setup_step_action_text_size">20sp</dimen> diff --git a/java/res/values-hi/strings-config-important-notice.xml b/java/res/values-hi/strings-config-important-notice.xml new file mode 100644 index 000000000..3f22541eb --- /dev/null +++ b/java/res/values-hi/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"सुझावों में सुधार हेतु अपने संचार और लिखे गए डेटा से जानकारी पाएं"</string> +</resources> diff --git a/java/res/values-hi/strings-talkback-descriptions.xml b/java/res/values-hi/strings-talkback-descriptions.xml new file mode 100644 index 000000000..df9511905 --- /dev/null +++ b/java/res/values-hi/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"जोर से बोली जाने वाली पासवर्ड कुंजियां सुनने के लिए हैडसेट प्लग करें."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"वर्तमान पाठ %s है"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"कोई पाठ नहीं डाला गया"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> को सुधार कर <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> करता है"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> स्वत: सुधार करता है"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"कुंजी कोड %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"शिफ़्ट"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"शिफ़्ट चालू (अक्षम करने के लिए टैप करें)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"कैप्स लॉक चालू (अक्षम करने के लिए टैप करें)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"डिलीट"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"प्रतीक"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"अक्षर"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"संख्याएं"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"सेटिंग"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"टैब"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"स्पेस"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"ध्वनि इनपुट"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"ईमोजी"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"रिटर्न"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"खोजें"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"डॉट"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"भाषा स्विच करें"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"अगला"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"पिछला"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"शिफ़्ट सक्षम किया गया"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"कैप्स लॉक सक्षम किया गया"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"शिफ़्ट अक्षम किया गया"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"प्रतीक मोड"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"अक्षर मोड"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"फ़ोन मोड"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"फ़ोन प्रतीक मोड"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"कीबोर्ड छिपा हुआ है"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> कीबोर्ड दिखाया जा रहा है"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"दिनांक"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"दिनांक और समय"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ईमेल"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"संदेश सेवा"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"संख्या"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"फ़ोन"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"पाठ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"समय"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"हाल ही के"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"लोग"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"ऑब्जेक्ट"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"प्रकृति"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"स्थान"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"प्रतीक"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"इमोटिकॉन्स"</string> +</resources> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index d7735433d..3129d86cc 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"सिस्टम डिफ़ॉल्ट"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"वैयक्तिकृत सुझाव"</string> <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"स्पेसबार पर डबल टैप करने से पीरियड शामिल हो जाता है जिसके बाद एक रिक्ति होती है"</string> <string name="auto_cap" msgid="1719746674854628252">"स्वत: अक्षर बड़े करना"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"जेस्चर ट्रेल दिखाएं"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"गतिशील फ़्लोटिंग पूर्वावलोकन"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"जेस्चर बनाते समय सुझाया गया शब्द देखें"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: सहेजा गया"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"ज़ोर से बोली गई पासवर्ड कुंजियां सुनने के लिए हेडसेट प्लग इन करें."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"वर्तमान पाठ %s है"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"कोई पाठ दर्ज नहीं किया गया"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> को सुधार कर <xliff:g id="CORRECTED">%3$s</xliff:g> करता है"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> स्वत: सुधार करता है"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"कुंजी कोड %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"शिफ़्ट"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift चालू (अक्षम करने के लिए टैप करें)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock चालू (अक्षम करने के लिए टैप करें)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"डिलीट"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"प्रतीक"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"अक्षर"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"संख्याएं"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"सेटिंग"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"टैब"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"स्पेस"</string> - <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_search" msgid="1247236163755920808">"खोजें"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"बिंदु"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"भाषा स्विच करें"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"अगला"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"पिछला"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift सक्षम किया गया"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock सक्षम किया गया"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift अक्षम किया गया"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"प्रतीक मोड"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"अक्षर मोड"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"फ़ोन मोड"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"फ़ोन प्रतीक मोड"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"कीबोर्ड छिपा हुआ है"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> कीबोर्ड दिखाया जा रहा है"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"दिनांक"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"दिनांक और समय"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"ईमेल"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"संदेश सेवा"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"संख्या"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"फ़ोन"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"पाठ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"समय"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"वाक्यांश जेस्चर"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"स्पेस कुंजी तक ग्लाइड करके जेस्चर के दौरान रिक्तियां इनपुट करें"</string> <string name="voice_input" msgid="3583258583521397548">"ध्वनि इनपुट कुंजी"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"मुख्य कीबोर्ड पर"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"प्रतीक कीबोर्ड पर"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"बंद"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"मुख्य कीबोर्ड पर माइक"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"प्रतीक कीबोर्ड पर माइक"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ध्वनि इनपुट अक्षम है"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कोई ध्वनि इनपुट पद्धति सक्षम नहीं है. भाषा और इनपुट सेटिंग जांचें."</string> <string name="configure_input_method" msgid="373356270290742459">"इनपुट पद्धति कॉन्फ़िगर करें"</string> <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string> <string name="send_feedback" msgid="1780431884109392046">"सुझाव भेजें"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"अंग्रेज़ी (यूके)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"अंग्रेज़ी (यूएस)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"स्पेनिश (यूएस)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"अंग्रेज़ी (यूके) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"अंग्रेज़ी (यूएस) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"स्पेनिश (यूएस) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (पारंपरिक)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"अंग्रेज़ी (यूके) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"अंग्रेज़ी (यूएस) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"स्पेनिश (यूएस) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (पारंपरिक)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (सिरिलिक)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (लैटिन)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"भाषा उपलब्ध नहीं है (लैटिन वर्णाक्षर)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"वर्णाक्षर (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"वर्णाक्षर (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"बाहरी शब्दकोश फ़ाइल पढ़ें"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"डाउनलोड फ़ोल्डर में कोई शब्दकोश फ़ाइल नहीं है"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"इंस्टॉल करने के लिए कोई शब्दकोश फ़ाइल चुनें"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"<xliff:g id="LOCALE_NAME">%s</xliff:g> के लिए वास्तव में यह फ़ाइल इंस्टॉल करें?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"क्या वाकई <xliff:g id="LANGUAGE_NAME">%s</xliff:g> के लिए यह फ़ाइल इंस्टॉल करें?"</string> <string name="error" msgid="8940763624668513648">"कोई त्रुटि हुई थी"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"संपर्क शब्दकोश सूचीबद्ध करें"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"व्यक्तिगत शब्दकोश डंप करें"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"उपयोगकर्ता इतिहास शब्दकोश डंप करें"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"वैयक्तिकरण शब्दकोश डंप करें"</string> <string name="button_default" msgid="3988017840431881491">"सामान्य"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> में आपका स्वागत है"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"हावभाव लेखन के साथ"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"रीफ़्रेश करें"</string> <string name="last_update" msgid="730467549913588780">"अंतिम बार का नई जानकारी"</string> <string name="message_updating" msgid="4457761393932375219">"नई जानकारी देखा जा रहा हैं"</string> - <string name="message_loading" msgid="8689096636874758814">"लोड हो रही है..."</string> + <string name="message_loading" msgid="5638680861387748936">"लोड हो रहा है…"</string> <string name="main_dict_description" msgid="3072821352793492143">"मुख्य डिक्शनरी"</string> <string name="cancel" msgid="6830980399865683324">"रद्द करें"</string> + <string name="go_to_settings" msgid="3876892339342569259">"सेटिंग"</string> <string name="install_dict" msgid="180852772562189365">"इंस्टॉल करें"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"रद्द करें"</string> <string name="delete_dict" msgid="756853268088330054">"हटाएं"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"आपके मोबाइल उपकरण पर चयनित भाषा में डिक्शनरी उपलब्ध है.<br/> आपके लेखन अनुभव को बेहतर बनाने के लिए हम <xliff:g id="LANGUAGE">%1$s</xliff:g> डिक्शनरी को <b>डाउनलोड करने</b> की अनुशंसा करते हैं.<br/> <br/> 3G पर डाउनलोड होने में एक या दो मिनट लग सकते हैं. यदि आपके पास <b>असीमित डेटा प्लान</b> नहीं है, तो शुल्क लग सकते हैं.<br/> यदि आप अपने डेटा प्लान के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए Wi-Fi कनेक्शन ढूंढने की अनुशंसा करते हैं.<br/> <br/> युक्ति: आप अपने मोबाइल उपकरण पर <b>सेटिंग</b> मेनू में <b>भाषा और अक्षर</b> पर जाकर डिक्शनरी डाउनलोड कर सकते हैं और निकाल सकते हैं."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"आपके मोबाइल पर चयनित भाषा के लिए शब्दकोश उपलब्ध है.<br/> हम आपके लेखन अनुभव को बेहतर बनाने के लिए <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> शब्दकोश <b>डाउनलोड करने</b> की अनुशंसा करते हैं.<br/> <br/> 3G में डाउनलोड करने पर एक या दो मिनट लगेंगे. यदि आपके पास <b>असीमित डेटा योजना</b> नहीं है, तो शुल्क लागू हो सकते हैं.<br/> यदि आप अपनी डेटा योजना के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए Wi-Fi कनेक्शन ढूंढने की अनुशंसा करते हैं.<br/> <br/> युक्ति: आप अपने मोबाइल उपकरण के <b>सेटिंग</b> मेनू में <b>भाषा और इनपुट</b> पर जाकर शब्दकोशों को डाउनलोड कर सकते हैं और निकाल सकते हैं."</string> <string name="download_over_metered" msgid="1643065851159409546">"अभी डाउनलोड करें (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi से डाउनलोड करें"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> के लिए डिक्शनरी उपलब्ध है"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> के लिए एक शब्दकोश उपलब्ध है"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"समीक्षा करने और डाउनलोड करने के लिए दबाएं"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"डाउनलोड हो रहा है: <xliff:g id="LANGUAGE">%1$s</xliff:g> के लिए सुझाव जल्दी ही तैयार हो जाएंगे."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"डाउनलोड प्रारंभ हो रहा है: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> के लिए सुझाव जल्दी ही उपलब्ध होंगे."</string> <string name="version_text" msgid="2715354215568469385">"संस्करण <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"जोड़ें"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"शब्दकोश में जोड़ें"</string> diff --git a/java/res/values-hr/strings-config-important-notice.xml b/java/res/values-hr/strings-config-important-notice.xml new file mode 100644 index 000000000..9d4b18db1 --- /dev/null +++ b/java/res/values-hr/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Upotrijebi poruke i upisane podatke za poboljšanje prijedloga"</string> +</resources> diff --git a/java/res/values-hr/strings-talkback-descriptions.xml b/java/res/values-hr/strings-talkback-descriptions.xml new file mode 100644 index 000000000..31c7eb5f8 --- /dev/null +++ b/java/res/values-hr/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Priključite slušalice da biste čuli naglas izgovorene tipke dok upisujete zaporku."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Trenutačni tekst glasi %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nije unesen tekst"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ispravlja <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> u <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> vrši samoispravljanje"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kôd tipke %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Uključena je tipka Shift (dodirnite za onemogućivanje)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Uključeno je pisanje velikim slovima (Caps Lock) (dodirnite za onemogućivanje)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Brisanje"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simboli"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Slova"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Brojevi"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Postavke"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulator"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Razmaknica"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Glasovni ulaz"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Pretraživanje"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Točka"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Promjena jezika"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Sljedeća"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Prethodna"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Omogućena je tipka Shift"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Omogućen je Caps Lock"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Tipka Shift onemogućena je"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Način unosa simbola"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Način unosa slova"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefonski način rada"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Način unosa telefonskih simbola"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tipkovnica je skrivena"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Prikaz tipkovnice: <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum i vrijeme"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-pošta"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"slanje poruka"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"brojevi"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"vrijeme"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Najnoviji"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Osobe"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objekti"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Priroda"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Mjesta"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboli"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikoni"</string> +</resources> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index b9cfef384..0882faad4 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Zadano sustavom"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Upotreba imena iz Kontakata za prijedloge i ispravke"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Prilagođeni prijedlozi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Točka s dva razmaka"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvostrukim dodirivanjem razmaknice umeću se točka i razmak"</string> <string name="auto_cap" msgid="1719746674854628252">"Automatsko pisanje velikih slova"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Prikaži trag pokreta"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamički plutajući pregled"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Vidi predloženu riječ tijekom pokreta"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Priključite slušalice da biste čuli tipke zaporke izgovorene naglas."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Trenutačni tekst je %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nije unesen tekst"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> ispravlja <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> u <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> vrši samoispravljanje"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kôd tipke %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Uključena tipka Shift (dotaknite da onemogućite)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Uključeno je pisanje velikim slovima (Caps Lock) (dotaknite da onemogućite)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboli"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Slova"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Brojevi"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Postavke"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Kartica"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Razmaknica"</string> - <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_search" msgid="1247236163755920808">"Pretraživanje"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Točka"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Promijeni jezik"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Sljedeće"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Prethodno"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Omogućena tipka Shift"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Omogućeno pisanje velikih slova"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Onemogućena tipka Shift"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Način unosa simbola"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Način pisanja slova"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefonski način rada"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Način unosa telefonskih simbola"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tipkovnica je skrivena"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Način prikazane tipkovnice: <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum i vrijeme"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-pošta"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"slanje poruka"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"brojevi"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"vrijeme"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Pokret fraze"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Umećite razmake tijekom izvođenja pokreta klizeći do razmaknice"</string> <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni unos"</string> - <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">"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="voice_input_disabled_summary" msgid="8141750303464726129">"Nije omogućen nijedan način glasovnog unosa. Provjerite postavke jezika i unosa."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfiguriraj načine ulaza"</string> <string name="language_selection_title" msgid="1651299598555326750">"Jezici unosa"</string> <string name="send_feedback" msgid="1780431884109392046">"Slanje povratnih informacija"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engleski (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engleski (SAD)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"španjolski (SAD)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"engleski (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"engleski (SAD) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"španjolski (SAD) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicionalni)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"engleska (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"engleska (SAD) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"španjolska (SAD) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionalni)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ćirilica)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinica)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nema jezika (abeceda)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Abeceda (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Abeceda (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Čitanje datoteke vanjskog rječnika"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"U mapi Preuzimanja nema datoteka rječnika"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Odabir datoteke rječnika za instaliranje"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Želite li doista instalirati ovu datoteku za <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Želite li zaista instalirati tu datoteku za <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Došlo je do pogreške"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Ispis rječnika kontakata"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Kopiranje osobnog rječnika"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Kopiranje rječ. povijesti korisnika"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Kopiranje rječnika za prilagodbu"</string> <string name="button_default" msgid="3988017840431881491">"Zadano"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Dobro došli u aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"s Pisanjem kretnjama"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Osvježavanje"</string> <string name="last_update" msgid="730467549913588780">"Zadnje ažuriranje"</string> <string name="message_updating" msgid="4457761393932375219">"Provjera ažuriranja"</string> - <string name="message_loading" msgid="8689096636874758814">"Učitavanje..."</string> + <string name="message_loading" msgid="5638680861387748936">"Učitavanje…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Glavni rječnik"</string> <string name="cancel" msgid="6830980399865683324">"Odustani"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Postavke"</string> <string name="install_dict" msgid="180852772562189365">"Instaliraj"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Odustani"</string> <string name="delete_dict" msgid="756853268088330054">"Izbriši"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Dostupan je rječnik za odabrani jezik na vašem uređaju.<br/> Preporučujemo <b>preuzimanje</b> rječnika za <xliff:g id="LANGUAGE">%1$s</xliff:g> radi boljeg doživljaja unosa teksta.<br/> <br/> Na 3G mreži preuzimanje može potrajati minutu ili dvije. Može podlijegati naplati ako nemate <b>neograničenu podatkovnu tarifu</b>.<br/> Ako niste sigurni koju tarifu imate, preporučujemo da pronađete Wi-Fi mrežu i pokrenete automatsko preuzimanje.<br/> <br/> Savjet: rječnike možete preuzeti i ukloniti u odjeljku <b>Jezik i unos</b> na izborniku <b>Postavke</b> na mobilnom uređaju."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Dostupan je rječnik za odabrani jezik na vašem mobilnom uređaju.<br/> Preporučujemo da <b>preuzmete</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> rječnik radi lakšeg unosa teksta.<br/> <br/> Preuzimanje može potrajati jednu do dvije minute putem 3G-a. Možda se naplaćuje dodatna naknada ako nemate <b>neograničenu podatkovnu tarifu</b>.<br/> Ako niste sigurni koju tarifu imate, preporučujemo da pronađete Wi-Fi vezu kako bi se automatski pokrenulo preuzimanje.<br/> <br/> Savjet: rječnike možete preuzeti i ukloniti u odjeljku <b>Jezik i unos</b> u izborniku <b>Postavke</b> na mobilnom uređaju."</string> <string name="download_over_metered" msgid="1643065851159409546">"Preuzmi sada (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Preuzmi putem Wi-Fi mreže"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Dostupan je rječnik za <xliff:g id="LANGUAGE">%1$s</xliff:g> jezik"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Dostupan je rječnik za <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> jezik"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pritisnite za pregled i preuzimanje"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Preuzimanje: prijedlozi za <xliff:g id="LANGUAGE">%1$s</xliff:g> bit će spremni uskoro."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Preuzimanje: prijedlozi za <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> bit će spremni uskoro."</string> <string name="version_text" msgid="2715354215568469385">"Verzija <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Dodavanje"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Dodaj u rječnik"</string> diff --git a/java/res/values-hu/strings-config-important-notice.xml b/java/res/values-hu/strings-config-important-notice.xml new file mode 100644 index 000000000..c023293e0 --- /dev/null +++ b/java/res/values-hu/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Javaslatok javítása a kommunikáció és begépelt adatok alapján"</string> +</resources> diff --git a/java/res/values-hu/strings-talkback-descriptions.xml b/java/res/values-hu/strings-talkback-descriptions.xml new file mode 100644 index 000000000..ec2c353ab --- /dev/null +++ b/java/res/values-hu/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Csatlakoztasson egy headsetet, ha hallani szeretné a jelszót felolvasva."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"A jelenlegi szöveg: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nincs szöveg megadva"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> billentyű – <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> szóra javítja a következőt: <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> billentyű automatikus javítást végez"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Billentyűkód: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"A Shift be van kapcsolva (érintse meg a kikapcsoláshoz)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"A Caps lock be van kapcsolva (érintse meg a kikapcsoláshoz)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Törlés"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Szimbólumok"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Betűk"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Számok"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Beállítások"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Szóköz"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Hangbevitel"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Hangulatjel"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Keresés"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Pont"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Nyelvváltás"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Következő"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Előző"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift bekapcsolva"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock bekapcsolva"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift kikapcsolva"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"„Szimbólumok” mód"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"„Betű” mód"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"„Telefon” mód"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"„Telefonos szimbólumok” mód"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Billentyűzet elrejtve"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> billentyűzet megjelenítve"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"dátum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"dátum és idő"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"üzenetváltás"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"szám"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"szöveg"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"idő"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Legutóbbiak"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Emberek"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objektumok"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Természet"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Helyek"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Szimbólumok"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Hangulatjelek"</string> +</resources> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index a61378fca..8a953ab9d 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Alapértelmezett"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Javasolt névjegyek"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"A névjegyek használata a javaslatokhoz és javításokhoz"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Testreszabott javaslatok"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dupla szóköz: pont"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"A szóköz kétszeri megérintése beszúr egy pontot, majd egy szóközt"</string> <string name="auto_cap" msgid="1719746674854628252">"Automatikusan nagy kezdőbetű"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mozdulat irányának mutatása"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamikus lebegő előnézet"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"A javasolt szó megtekintése kézmozdulat közben"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Csatlakoztasson egy headsetet, ha hallani szeretné a jelszót felolvasva."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"A jelenlegi szöveg: %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Szöveg nincs megadva"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> billentyű: <xliff:g id="CORRECTED">%3$s</xliff:g> szóra javítja a következőt: <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> billentyű automatikus javítást végez"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Billentyűkód: %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift be van kapcsolva (érintse meg a kikapcsoláshoz)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock be van kapcsolva (érintse meg a kikapcsoláshoz)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Törlés"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Szimbólumok"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Betűk"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Számok"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Beállítások"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Szóköz"</string> - <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_search" msgid="1247236163755920808">"Keresés"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Pont"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Nyelvek felcserélése"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Következő"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Előző"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift bekapcsolva"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock bekapcsolva"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift kikapcsolva"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"\"Szimbólumok\" mód"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"\"Betű\" mód"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"\"Telefon\" mód"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"\"Telefonos szimbólumok\" mód"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Billentyűzet elrejtve"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> billentyűzet megjelenítve"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"dátum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"dátum és idő"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"üzenetváltás"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"szám"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"szöveg"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"idő"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Kifejezés-kézmozdulat"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Szóköz írása kézmozdulatok során: húzza el ujját a szóköz felett"</string> <string name="voice_input" msgid="3583258583521397548">"Hangbeviteli gomb"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"A fő billentyűzeten"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Szimbólumoknál"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Ki"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon a billentyűzeten"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. a szimbólumoknál"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hangbevivel KI"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nincs engedélyezett hangbeviteli módszer. Nézze meg a Nyelvi és beviteli beállításokat."</string> <string name="configure_input_method" msgid="373356270290742459">"Beviteli módok beállítása"</string> <string name="language_selection_title" msgid="1651299598555326750">"Beviteli nyelvek"</string> <string name="send_feedback" msgid="1780431884109392046">"Visszajelzés küldése"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"angol (brit)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angol (amerikai)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"spanyol (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angol (brit) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"angol (amerikai) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"spanyol (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (hagyományos)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"angol (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"angol (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"spanyol (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (hagyományos)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cirill)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nincs nyelv (ábécé)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Ábécé (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Ábécé (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Külső szótárfájl olvasása"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Nincs szótárfájl a Letöltések mappában."</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Válasszon ki egy szótárfájlt a telepítéshez."</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Valóban telepíti ezt a fájlt <xliff:g id="LOCALE_NAME">%s</xliff:g> nyelvhez?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Valóban telepíti ezt a fájlt <xliff:g id="LANGUAGE_NAME">%s</xliff:g> nyelvhez?"</string> <string name="error" msgid="8940763624668513648">"Hiba történt."</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Névjegytár kiírása"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Személyes szótár törlése"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Felhasználóielőzmény-szótár törlése"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Testreszabási szótár törlése"</string> <string name="button_default" msgid="3988017840431881491">"Alapértelmezett"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Üdvözli a(z) <xliff:g id="APPLICATION_NAME">%s</xliff:g>!"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"kézmozdulatokkal történő bevitellel"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Frissítés"</string> <string name="last_update" msgid="730467549913588780">"Legutóbb frissítve"</string> <string name="message_updating" msgid="4457761393932375219">"Frissítések keresése"</string> - <string name="message_loading" msgid="8689096636874758814">"Betöltés..."</string> + <string name="message_loading" msgid="5638680861387748936">"Betöltés…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Fő szótár"</string> <string name="cancel" msgid="6830980399865683324">"Mégse"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Beállítások"</string> <string name="install_dict" msgid="180852772562189365">"Telepítés"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Mégse"</string> <string name="delete_dict" msgid="756853268088330054">"Törlés"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"A mobileszközön kiválasztott nyelvhez szótár érhető el.<br/> A gépelési élmény javításához javasoljuk a(z) <xliff:g id="LANGUAGE">%1$s</xliff:g> szótár <b>letöltését.<br/> <br/> A letöltés 3G hálózaton keresztül néhány percig tart. Ha <b>előfizetése nem korlátlan</b>, a letöltés költségekkel járhat.<br/> Ha nem biztos abban, hogy milyen adatcsomagot használ, javasoljuk, hogy keressen egy Wi-Fi kapcsolatot a letöltés automatikus elindításához.<br/> <br/> Tipp: a szótárakat a mobileszköz <b>Beállítások</b> menüjében a <b>Nyelv és bevitel</b> részben töltheti le és távolíthatja el."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"A mobileszközön kiválasztott nyelvhez szótár érhető el.<br/> A gépelési élmény javításához javasoljuk a(z) <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> szótár <b>letöltését.<br/> <br/> A letöltés 3G hálózaton keresztül néhány percig tart. Ha <b>előfizetése nem korlátlan</b>, a letöltés költségekkel járhat.<br/> Ha nem biztos abban, hogy milyen adatcsomagot használ, javasoljuk, hogy keressen egy Wi-Fi-kapcsolatot a letöltés automatikus elindításához.<br/> <br/> Tipp: szótárakat a mobileszköz a <b>Beállítások</b> menü <b>Nyelv és bevitel</b> részében tölthet le és távolíthat el."</string> <string name="download_over_metered" msgid="1643065851159409546">"Töltse le most (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Letöltés Wi-Fivel"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> nyelvhez van rendelkezésre álló szótár"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> nyelvhez van rendelkezésre álló szótár"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Nyomja meg az áttekintéshez és letöltéshez"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Letöltés: a(z) <xliff:g id="LANGUAGE">%1$s</xliff:g> nyelvvel kapcsolatos javaslatok hamarosan elérhetők lesznek."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Letöltés: a(z) <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> nyelvvel kapcsolatos javaslatok hamarosan elérhetők lesznek."</string> <string name="version_text" msgid="2715354215568469385">"Verzió: <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Hozzáadás"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Hozzáadás a szótárhoz"</string> diff --git a/java/res/values-hy-rAM/donottranslate.xml b/java/res/values-hy-rAM/donottranslate-config-spacing-and-punctuations.xml index 7b0c56655..ed35365a2 100644 --- a/java/res/values-hy-rAM/donottranslate.xml +++ b/java/res/values-hy-rAM/donottranslate-config-spacing-and-punctuations.xml @@ -25,7 +25,7 @@ <string name="symbols_followed_by_space">.,;:!?)]}&։՝</string> <!-- Symbols that separate words. Adding armenian period and comma. --> <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> - <string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"։՝</string> + <string name="symbols_word_separators">"	 
 "()[]{}*&<>+=|.,;:!?/_\"։՝</string> <!-- The sentence separator code point, for capitalization --> <!-- U+0589: "։" ARMENIAN FULL STOP ; 589h = 1417d --> <integer name="sentence_separator">1417</integer> diff --git a/java/res/values-hy-rAM/strings-config-important-notice.xml b/java/res/values-hy-rAM/strings-config-important-notice.xml new file mode 100644 index 000000000..9fac63197 --- /dev/null +++ b/java/res/values-hy-rAM/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Բարելավեք առաջարկները` ձեր նամակագրությունից և մուտքագրած տվյալներից"</string> +</resources> diff --git a/java/res/values-hy-rAM/strings-talkback-descriptions.xml b/java/res/values-hy-rAM/strings-talkback-descriptions.xml new file mode 100644 index 000000000..e5b1ce6d9 --- /dev/null +++ b/java/res/values-hy-rAM/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Միացրեք ականջակալը՝ բարձրաձայն արտասանվող գաղտնաբառը լսելու համար:"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Տվյալ տեքստը %s է"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Տեքստ չի մուտքագրվել"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g>-ը շտկում է <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-ը՝ դարձնելով <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ստեղնը ինքնաշտկում է կատարում"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Բանալու կոդը՝ %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift-ը միացված է (հպել անջատելու համար)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock-ը միացված է (հպել՝ անջատելու համար)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Ջնջել"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Նշաններ"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Տառեր"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Թվեր"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Կարգավորումներ"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Բացատ"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Ձայնային մուտքագրում"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Զմայլիկներ"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Վերադառնալ"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Որոնել"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Կետ"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Փոխել լեզուն"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Հաջորդը"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Նախորդը"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift-ը միացված է"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock-ը միացված է"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift-ն անջատված է"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Նշանների ռեժիմ"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Տառերի ռեժիմ"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Հեռախոսային ռեժիմ"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Հեռախոսի նշանների ռեժիմ"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Ստեղնաշարը թաքցված է"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Ցուցադրվում է <xliff:g id="KEYBOARD_MODE">%s</xliff:g> ստեղնաշարը"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ամսաթիվ"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ամսաթիվ և ժամ"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"էլփոստ"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"նամակագրություն"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"թվեր"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"հեռախոսահամար"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"տեքստ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ժամանակ"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Վերջինները"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Մարդիկ"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Օբյեկտներ"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Բնություն"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Վայրեր"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Նշաններ"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Զմայլիկներ"</string> +</resources> diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml index 0b8e19a76..03d56a626 100644 --- a/java/res/values-hy-rAM/strings.xml +++ b/java/res/values-hy-rAM/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Համակարգի լռելյայնները"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Առաջարկել կոնտակտների անունները"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Օգտագործել կոնտակտների անունները՝ առաջարկների և ուղղումների համար"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Անհատականացված առաջարկներ"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Կրկնաբացակի վերջակետ"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Բացակի ստեղնի կրկնակի հպումը բացակից հետո վերջակետ է դնում"</string> <string name="auto_cap" msgid="1719746674854628252">"Ավտոմատ գլխատառացում"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Ցույց տալ ժեստի հետագիծը"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Դինամիկ սահող նախատեսք"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Տեսեք առաջարկված բառը՝ ժեստի միջոցով"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>` պահված է"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Միացրեք ականջակալը՝ բարձրաձայն արտասանվող գաղտնաբառը լսելու համար:"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Տվյալ տեքստը %s է"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Տեքստ չի մուտքագրվել"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g>-ը շտկում է <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-ը և դարձնում <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> ստեղնը ինքնաշտկում է կատարում"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Բանալու կոդը՝ %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift-ը միացված է (հպել անջատելու համար)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock-ը միացված է (հպել՝ անջատելու համար)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Ջնջել"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Նշաններ"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Տառեր"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Թվեր"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Կարգավորումներ"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Բացակ"</string> - <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_search" msgid="1247236163755920808">"Որոնել"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Կետ"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Փոխել լեզուն"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Հաջորդը"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Նախորդը"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift-ը միացված է"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock-ը միացված է"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift-ն անջատված է"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Նշանների ռեժիմ"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Տառերի ռեժիմ"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Հեռախոսային ռեժիմ"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Հեռախոսի նշանների ռեժիմ"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Ստեղնաշարը թաքցված է"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Ցուցադրված է <xliff:g id="MODE">%s</xliff:g> ստեղնաշարը"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ամսաթիվ"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ամսաթիվ և ժամ"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"էլփոստ"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"նամակագրություն"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"թվեր"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"հեռախոսահամար"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"տեքստ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ժամանակ"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Բառակապակցային ժեստ"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Ներմուծեք բացատներ ժեստերի ընթացքում՝ սահելով բացատ ստեղնի վրայով"</string> <string name="voice_input" msgid="3583258583521397548">"Ձայնային մուտքագրման ստեղն"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Հիմնական ստեղնաշարի վրա"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Նշանների ստեղնաշարի վրա"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Անջատված"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Բարձրախոս հիմնական ստեղնաշարի վրա"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Բարձրախոս նշանների ստեղնաշարի վրա"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Ձայնային մուտքագրումն անջատված է"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ձայնային ներածման որևէ եղանակ միացված չէ։ Ստուգեք Լեզվի և ներածման կարգավորումները։"</string> <string name="configure_input_method" msgid="373356270290742459">"Կարգավորել մուտքագրման մեթոդները"</string> <string name="language_selection_title" msgid="1651299598555326750">"Մուտքագրման լեզուներ"</string> <string name="send_feedback" msgid="1780431884109392046">"Արձագանքել"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Անգլերեն (ՄԹ)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Անգլերեն (ԱՄՆ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Իսպաներեն (ԱՄՆ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Անգլերեն (ՄԹ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Անգլերեն (ԱՄՆ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Իսպաներեն (ԱՄՆ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (ավանդական)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Անգլերեն (ՄԹ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Անգլերեն (ԱՄՆ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Իսպաներեն (ԱՄՆ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ավանդական)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (կյուրեղյան)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (լատինական)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Ոչ մի լեզվով (Այբուբեն)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Այբուբեն (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Այբուբեն (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Կարդալ արտաքին բառարանի ֆայլը"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Ներբեռնումների թղթապանակում բառարանային ֆայլեր չկան"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Ընտրեք բառարանային ֆայլը տեղադրման համար"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Իրո՞ք ուզում եք տեղադրել այս ֆայլը <xliff:g id="LOCALE_NAME">%s</xliff:g>-ում:"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Տեղադրե՞լ այս ֆայլը <xliff:g id="LANGUAGE_NAME">%s</xliff:g> լեզվի համար:"</string> <string name="error" msgid="8940763624668513648">"Տեղի է ունեցել սխալ"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Բեռնել կոնտակտների բառարանը"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Բեռնել անձնական բառարանը"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Բեռնել օգտվողի պատմության բառարանը"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Բեռնել անհատականացման բառարանը"</string> <string name="button_default" msgid="3988017840431881491">"Լռելյայնը"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Բարի գալուստ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"Ժեստային մուտքագրմամբ"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Թարմացնել"</string> <string name="last_update" msgid="730467549913588780">"Վերջին անգամ թարմացվել է"</string> <string name="message_updating" msgid="4457761393932375219">"Ստուգվում է թարմացումների առկայությունը"</string> - <string name="message_loading" msgid="8689096636874758814">"Բեռնվում է..."</string> + <string name="message_loading" msgid="5638680861387748936">"Բեռնում..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Հիմնական բառարան"</string> <string name="cancel" msgid="6830980399865683324">"Չեղարկել"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Կարգավորումներ"</string> <string name="install_dict" msgid="180852772562189365">"Տեղադրել"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Չեղարկել"</string> <string name="delete_dict" msgid="756853268088330054">"Ջնջել"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Ձեր բջջային սարքում ընտրված լեզվով առկա է բառարան:<br/> Խորհուրդ ենք տալիս <b>ներբեռնել</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> բառարանը ձեր մուտքագրման հմտությունների բարելավման համար:<br/> <br/> Ներբեռնումը կարող է խլել մեկ կամ երկու րոպե 3G-ի դեպքում: Հնարավոր է գանձում կատարվի, եթե դուք չունեք <b>տվյալների անսահմանափակ փաթեթ</b>.<br/> Եթե դուք վստահ չեք, թե տվյալների որ փաթեթն ունեք, խորհուրդ ենք տալիս գտնել Wi-Fi կապ՝ ներբեռնումն ավտոմատ սկսելու համար:<br/> <br/> Հուշում. դուք կարող եք ներբեռնել և հեռացնել բառարաններ՝ գնալով ձեր բջջային սարքի <b>Կարգավորումներ ցանկի Լեզու & մուտքագրման</b> բաժինը:"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Ձեր բջջային սարքում ընտրված լեզվով առկա է բառարան:<br/> Խորհուրդ ենք տալիս <b>ներբեռնել</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> բառարանը՝ ձեր մուտքագրման հմտությունների բարելավման համար:<br/> <br/> Ներբեռնումը կարող է խլել մեկ կամ երկու րոպե 3G-ի դեպքում: Հնարավոր է գանձում կատարվի, եթե դուք չունեք <b>տվյալների անսահմանափակ փաթեթ</b>.<br/> Եթե դուք վստահ չեք, թե տվյալների որ փաթեթն ունեք, խորհուրդ ենք տալիս գտնել Wi-Fi կապ՝ ներբեռնումն ավտոմատ սկսելու համար:<br/> <br/> Հուշում. դուք կարող եք ներբեռնել և հեռացնել բառարաններ՝ անցնելով ձեր բջջային սարքի <b>Կարգավորումներ ցանկի Լեզու և մուտքագրում</b> բաժինը:"</string> <string name="download_over_metered" msgid="1643065851159409546">"Ներբեռնել հիմա (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>Մբ)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Ներբեռնել Wi-Fi-ով"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g>-ով առկա է մի բառարան"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> լեզվի համար առկա է բառարան"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Սեղմեք՝ վերանայելու և ներբեռնելու համար"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Ներբեռնվում է. <xliff:g id="LANGUAGE">%1$s</xliff:g>-ի համար առաջարկները շուտով պատրաստ կլինեն:"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Ներբեռնում. <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> լեզվի համար առաջարկները պատրաստ կլինեն շուտով:"</string> <string name="version_text" msgid="2715354215568469385">"Տարբերակ <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Ավելացնել"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Ավելացնել բառարանում"</string> diff --git a/java/res/values-in/strings-config-important-notice.xml b/java/res/values-in/strings-config-important-notice.xml new file mode 100644 index 000000000..d5df91306 --- /dev/null +++ b/java/res/values-in/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Belajar dari komunikasi & data terketik untuk meningkatkan saran"</string> +</resources> diff --git a/java/res/values-in/strings-talkback-descriptions.xml b/java/res/values-in/strings-talkback-descriptions.xml new file mode 100644 index 000000000..73bf712f3 --- /dev/null +++ b/java/res/values-in/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Pasang headset untuk mendengar tombol sandi yang diucapkan dengan lantang."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Teks saat ini adalah %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Tidak ada teks yang dimasukkan"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> mengoreksi <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> menjadi <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> melakukan koreksi otomatis"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kode tombol %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift aktif (ketuk untuk menonaktifkan)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock aktif (ketuk untuk menonaktifkan)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Hapus"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simbol"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Huruf"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Angka"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Setelan"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Spasi"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Masukan suara"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Kembali"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Telusuri"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Titik"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Beralih bahasa"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Berikutnya"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Sebelumnya"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift diaktifkan"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock diaktifkan"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift dinonaktifkan"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Mode simbol"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Mode huruf"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Mode telepon"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Mode simbol telepon"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Keyboard disembunyikan"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Menampilkan keyboard <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"tanggal"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"tanggal dan waktu"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"pesan"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"angka"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telepon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teks"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"waktu"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Terbaru"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Orang"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objek"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Alam"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Tempat"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simbol"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikon"</string> +</resources> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index d83a22c6c..e3c551629 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Default sistem"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sarankan nama Kontak"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama dari Kontak untuk saran dan koreksi"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Saran hasil personalisasi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik spasi ganda"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Mengetuk tombol spasi dua kali akan memasukkan titik diikuti satu spasi"</string> <string name="auto_cap" msgid="1719746674854628252">"Kapitalisasi otomatis"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Tampilkan jalur isyarat"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Pratinjau mengambang dinamis"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Lihat kata yang disarankan saat melakukan isyarat"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Pasang headset untuk mendengar tombol sandi yang diucapkan dengan keras."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Teks saat ini adalah %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Tidak ada teks yang dimasukkan"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> mengoreksi <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> menjadi <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> melakukan koreksi otomatis"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kode tombol %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift hidup (ketuk untuk mematikan)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock hidup (ketuk untuk mematikan)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Hapus"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simbol"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Huruf"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Angka"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Setelan"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spasi"</string> - <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_search" msgid="1247236163755920808">"Telusuri"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Ganti bahasa"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Berikutnya"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Sebelumnya"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift diaktifkan"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock diaktifkan"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift dinonaktifkan"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode simbol"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode huruf"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode telepon"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode simbol telepon"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Keyboard disembunyikan"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Menampilkan keyboard <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"tanggal"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"tanggal dan waktu"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"pesan"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"angka"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telepon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teks"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"waktu"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Isyarat frasa"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Masukkan spasi dalam isyarat dengan meluncur ke tombol spasi"</string> <string name="voice_input" msgid="3583258583521397548">"Tombol masukan suara"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pada keyboard utama"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Pada keyboard simbol"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Mati"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik pada keyboard utama"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik pada keyboard simbol"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Masukan suara dinonaktifkan"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tidak ada metode masukan suara yang diaktifkan. Periksa setelan Bahasan & masukan."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan metode masukan"</string> <string name="language_selection_title" msgid="1651299598555326750">"Bahasa masukan"</string> <string name="send_feedback" msgid="1780431884109392046">"Kirim masukan"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Inggris (Inggris)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inggris (AS)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spanyol (AS)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inggris (Inggris) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inggris (AS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spanyol (AS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Tradisional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>) Inggris (Inggris)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>) Inggris (AS)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>) Spanyol (AS)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Sirilik)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Tidak ada bahasa (Abjad)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Abjad (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Abjad (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Membaca file kamus eksternal"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Tidak ada file kamus di folder Unduhan"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Pilih file kamus untuk dipasang"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Yakin ingin memasang file ini untuk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Yakin ingin memasang file ini untuk <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Terjadi kesalahan"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Buat daftar kamus kontak"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Buat daftar kamus pribadi"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Buat daftar kamus riwayat pengguna"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Buat daftar kamus personalisasi"</string> <string name="button_default" msgid="3988017840431881491">"Default"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Selamat datang di <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"dengan Ketikan Isyarat"</string> @@ -193,7 +154,7 @@ <string name="dictionary_provider_name" msgid="3027315045397363079">"Penyedia Kamus"</string> <string name="dictionary_service_name" msgid="6237472350693511448">"Layanan Kamus"</string> <string name="download_description" msgid="6014835283119198591">"Informasi pembaruan kamus"</string> - <string name="dictionary_settings_title" msgid="8091417676045693313">"Kamus add-on"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"Kamus pengaya"</string> <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Kamus yang tersedia"</string> <string name="dictionary_settings_summary" msgid="5305694987799824349">"Setelan untuk kamus"</string> <string name="user_dictionaries" msgid="3582332055892252845">"Kamus pengguna"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Segarkan"</string> <string name="last_update" msgid="730467549913588780">"Terakhir diperbarui"</string> <string name="message_updating" msgid="4457761393932375219">"Memeriksa pembaruan"</string> - <string name="message_loading" msgid="8689096636874758814">"Memuat..."</string> + <string name="message_loading" msgid="5638680861387748936">"Memuat…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Kamus utama"</string> <string name="cancel" msgid="6830980399865683324">"Batal"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Setelan"</string> <string name="install_dict" msgid="180852772562189365">"Pasang"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Batal"</string> <string name="delete_dict" msgid="756853268088330054">"Hapus"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Bahasa pilihan pada perangkat seluler Anda memiliki kamus yang tersedia.<br/> Silakan <b>mengunduh</b> kamus <xliff:g id="LANGUAGE">%1$s</xliff:g> untuk meningkatkan pengalaman pengetikan.<br/> <br/> Unduhan dapat berlangsung selama satu atau dua menit melalui 3G. Mungkin dikenakan tagihan data jika Anda tidak memiliki <b>paket data tak terbatas</b>.<br/> Jika tidak yakin paket data mana yang Anda miliki, sebaiknya Anda mencari sambungan Wi-Fi untuk memulai unduhan secara otomatis.<br/> <br/> Kiat: Anda dapat mengunduh atau menghapus kamus dengan membuka <b>Bahasa & masukan</b> di menu <b>Setelan</b> perangkat seluler Anda."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Tersedia kamus untuk bahasa pilihan pada perangkat seluler Anda.<br/> Sebaiknya <b>unduh</b> kamus <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> untuk meningkatkan pengalaman pengetikan.<br/> <br/> Unduhan dapat berlangsung selama satu atau dua menit melalui 3G. Mungkin dikenakan biaya data jika tidak memiliki <b>paket data tak terbatas</b>.<br/> Jika tidak yakin dengan jenis paket data Anda, sebaiknya cari koneksi Wi-Fi untuk memulai unduhan secara otomatis.<br/> <br/> Kiat: Anda dapat mengunduh dan menghapus kamus dengan membuka <b>Bahasa & masukan</b> di menu <b>Setelan</b> perangkat seluler Anda."</string> <string name="download_over_metered" msgid="1643065851159409546">"Unduh sekarang (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Unduh melalui Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Kamus tersedia untuk bahasa <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Kamus tersedia untuk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Tekan untuk meninjau dan mengunduh"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Mengunduh: saran untuk bahasa <xliff:g id="LANGUAGE">%1$s</xliff:g> akan segera tersedia."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Mengunduh: saran untuk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> akan segera tersedia."</string> <string name="version_text" msgid="2715354215568469385">"Versi <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Tambahkan"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Tambahkan ke kamus"</string> diff --git a/java/res/values-is/strings-talkback-descriptions.xml b/java/res/values-is/strings-talkback-descriptions.xml new file mode 100644 index 000000000..05b816ab7 --- /dev/null +++ b/java/res/values-is/strings-talkback-descriptions.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for spoken_use_headphones (896961781287283493) --> + <skip /> + <!-- no translation found for spoken_current_text_is (2485723011272583845) --> + <skip /> + <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> + <skip /> + <!-- no translation found for spoken_auto_correct (8005997889020109763) --> + <skip /> + <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> + <skip /> + <!-- no translation found for spoken_description_unknown (3197434010402179157) --> + <skip /> + <!-- no translation found for spoken_description_shift (244197883292549308) --> + <skip /> + <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> + <skip /> + <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> + <skip /> + <!-- no translation found for spoken_description_delete (8740376944276199801) --> + <skip /> + <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> + <skip /> + <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> + <skip /> + <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> + <skip /> + <!-- no translation found for spoken_description_settings (4627462689603838099) --> + <skip /> + <!-- no translation found for spoken_description_tab (2667716002663482248) --> + <skip /> + <!-- no translation found for spoken_description_space (2582521050049860859) --> + <skip /> + <!-- no translation found for spoken_description_mic (615536748882611950) --> + <skip /> + <!-- no translation found for spoken_description_smiley (2256309826200113918) --> + <skip /> + <!-- no translation found for spoken_description_return (8178083177238315647) --> + <skip /> + <!-- no translation found for spoken_description_search (1247236163755920808) --> + <skip /> + <!-- no translation found for spoken_description_dot (40711082435231673) --> + <skip /> + <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> + <skip /> + <!-- no translation found for spoken_description_action_next (8636078276664150324) --> + <skip /> + <!-- no translation found for spoken_description_action_previous (800872415009336208) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> + <skip /> + <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> + <skip /> + <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> + <skip /> + <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> + <skip /> + <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> + <skip /> + <!-- no translation found for keyboard_mode_date (3137520166817128102) --> + <skip /> + <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> + <skip /> + <!-- no translation found for keyboard_mode_email (6216248078128294262) --> + <skip /> + <!-- no translation found for keyboard_mode_im (1137405089766557048) --> + <skip /> + <!-- no translation found for keyboard_mode_number (7991623440699957069) --> + <skip /> + <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> + <skip /> + <!-- no translation found for keyboard_mode_text (6479436687899701619) --> + <skip /> + <!-- no translation found for keyboard_mode_time (4381856885582143277) --> + <skip /> + <!-- no translation found for keyboard_mode_url (1519819835514911218) --> + <skip /> +</resources> diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml index 6f685d395..1588534c9 100644 --- a/java/res/values-is/strings.xml +++ b/java/res/values-is/strings.xml @@ -126,106 +126,8 @@ <skip /> <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) --> <skip /> - <!-- no translation found for added_word (8993883354622484372) --> - <skip /> - <!-- no translation found for spoken_use_headphones (896961781287283493) --> - <skip /> - <!-- no translation found for spoken_current_text_is (2485723011272583845) --> - <skip /> - <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> - <skip /> - <!-- no translation found for spoken_auto_correct (8005997889020109763) --> - <skip /> - <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> - <skip /> - <!-- no translation found for spoken_description_unknown (3197434010402179157) --> - <skip /> - <!-- no translation found for spoken_description_shift (244197883292549308) --> - <skip /> - <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> - <skip /> - <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> - <skip /> - <!-- no translation found for spoken_description_delete (8740376944276199801) --> - <skip /> - <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> - <skip /> - <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> - <skip /> - <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> - <skip /> - <!-- no translation found for spoken_description_settings (4627462689603838099) --> - <skip /> - <!-- no translation found for spoken_description_tab (2667716002663482248) --> - <skip /> - <!-- no translation found for spoken_description_space (2582521050049860859) --> - <skip /> - <!-- no translation found for spoken_description_mic (615536748882611950) --> - <skip /> - <!-- no translation found for spoken_description_smiley (2256309826200113918) --> - <skip /> - <!-- no translation found for spoken_description_return (8178083177238315647) --> - <skip /> - <!-- no translation found for spoken_description_search (1247236163755920808) --> - <skip /> - <!-- no translation found for spoken_description_dot (40711082435231673) --> - <skip /> - <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> - <skip /> - <!-- no translation found for spoken_description_action_next (8636078276664150324) --> - <skip /> - <!-- no translation found for spoken_description_action_previous (800872415009336208) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> - <skip /> - <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> - <skip /> - <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> - <skip /> - <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> - <skip /> - <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> - <skip /> - <!-- no translation found for keyboard_mode_date (3137520166817128102) --> - <skip /> - <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> - <skip /> - <!-- no translation found for keyboard_mode_email (6216248078128294262) --> - <skip /> - <!-- no translation found for keyboard_mode_im (1137405089766557048) --> - <skip /> - <!-- no translation found for keyboard_mode_number (7991623440699957069) --> - <skip /> - <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> - <skip /> - <!-- no translation found for keyboard_mode_text (6479436687899701619) --> - <skip /> - <!-- no translation found for keyboard_mode_time (4381856885582143277) --> - <skip /> - <!-- no translation found for keyboard_mode_url (1519819835514911218) --> - <skip /> <!-- 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) --> - <skip /> - <!-- no translation found for voice_input_modes_off (3745699748218082014) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_off (63875609591897607) --> - <skip /> <!-- no translation found for configure_input_method (373356270290742459) --> <skip /> <!-- no translation found for language_selection_title (1651299598555326750) --> diff --git a/java/res/values-it/strings-config-important-notice.xml b/java/res/values-it/strings-config-important-notice.xml new file mode 100644 index 000000000..3690fac39 --- /dev/null +++ b/java/res/values-it/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Usa comunicazioni e dati digitati per migliorare i suggerimenti"</string> +</resources> diff --git a/java/res/values-it/strings-talkback-descriptions.xml b/java/res/values-it/strings-talkback-descriptions.xml new file mode 100644 index 000000000..760db696c --- /dev/null +++ b/java/res/values-it/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Collega gli auricolari per ascoltare la pronuncia dei tasti premuti per la password."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Il testo attuale è %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nessun testo inserito"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corregge <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> con <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> esegue la correzione automatica"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Codice tasto %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Maiusc"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Maiusc attivo (tocca per disattivare)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Blocco maiuscole attivo (tocca per disattivare)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Elimina"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simboli"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Lettere"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Numeri"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Impostazioni"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"TAB"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Spazio"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Input vocale"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Invio"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Cerca"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Pallino"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Cambia lingua"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Successivo"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Precedente"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Maiusc attivo"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Bloc Maiusc attivo"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Maiusc disattivato"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modalità simboli"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modalità lettere"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modalità telefono"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modalità simboli telefono"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastiera nascosta"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Ecco la tastiera <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data e ora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"messaggi"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"numero"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefono"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"testo"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recenti"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Persone"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Oggetti"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natura"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Luoghi"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboli"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticon"</string> +</resources> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 1111c4901..6685095be 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Predefinito sistema"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Suggerisci nomi di contatti"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizza nomi di Contatti per suggerimenti e correzioni"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Suggerimenti personalizz."</string> <string name="use_double_space_period" msgid="8781529969425082860">"Doppio spazio per punto"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocca due volte barra spaziatr. per inserire punto seguito da spazio"</string> <string name="auto_cap" msgid="1719746674854628252">"Maiuscole automatiche"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostra traccia con gesto"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Anteprima mobile dinamica"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Visualizza la parola suggerita durante il gesto"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Collega gli auricolari per ascoltare la pronuncia dei tasti premuti per la password."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Il testo attuale è %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nessun testo inserito"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corregge <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> con <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> esegue correzione automatica"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Codice tasto %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Maiuscolo"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Maiuscolo attivo (tocca per disattivare)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Blocco maiuscole attivo (tocca per disattivare)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Cancella"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboli"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Lettere"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numeri"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Impostazioni"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulazione"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spazio"</string> - <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_search" msgid="1247236163755920808">"Cerca"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Pallino"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Cambia lingua"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Successivo"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Precedente"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Maiuscolo attivo"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Blocco maiuscole attivo"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Maiuscolo disattivato"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modalità simboli"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modalità lettere"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modalità telefono"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modalità simboli telefono"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastiera nascosta"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Visualizzazione tastiera <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"data"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"data e ora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"messaggi"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"numero"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefono"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"testo"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gesto frase"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Inserisci spazi durante gesti facendo scivolare dito su spazio"</string> <string name="voice_input" msgid="3583258583521397548">"Tasto input vocale"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Su tastiera principale"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Su tastiera simboli"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"OFF"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Microfono su tastiera principale"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Microfono su tastiera simboli"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Input vocale disatt."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nessun metodo di immissione vocale abilitato. Controlla le impostazioni Lingua e input."</string> <string name="configure_input_method" msgid="373356270290742459">"Configura metodi di immissione"</string> <string name="language_selection_title" msgid="1651299598555326750">"Lingue comandi"</string> <string name="send_feedback" msgid="1780431884109392046">"Invia feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Inglese (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglese (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spagnolo (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglese (Regno Unito) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglese (Stati Uniti) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spagnolo (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradizionale)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglese (Regno Unito) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglese (Stati Uniti) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spagnolo (Stati Uniti) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradizionale)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cirillico)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latino)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nessuna lingua (alfabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Leggi file dizionario esterno"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Nessun file di dizionario nella cartella Download"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Seleziona un file di dizionario da installare"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Installare questo file per <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Vuoi davvero installare questo file per <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Si è verificato un errore"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Estrai dizionario contatti"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Estrai dizionario personale"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Estrai dizion. cronologia utente"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Estrai dizionario di personalizz."</string> <string name="button_default" msgid="3988017840431881491">"Predefinito"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Benvenuto in <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"con la Digitazione gestuale"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Aggiorna"</string> <string name="last_update" msgid="730467549913588780">"Ultimo aggiornamento"</string> <string name="message_updating" msgid="4457761393932375219">"Verifica disponibilità aggiornamenti"</string> - <string name="message_loading" msgid="8689096636874758814">"Caricamento in corso..."</string> + <string name="message_loading" msgid="5638680861387748936">"Caricamento..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Dizionario principale"</string> <string name="cancel" msgid="6830980399865683324">"Annulla"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Impostazioni"</string> <string name="install_dict" msgid="180852772562189365">"Installa"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Annulla"</string> <string name="delete_dict" msgid="756853268088330054">"Elimina"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Per la lingua selezionata sul dispositivo mobile è disponibile un dizionario.<br/> Ti consigliamo di <b>scaricare</b> il dizionario in <xliff:g id="LANGUAGE">%1$s</xliff:g> per migliorare l\'esperienza di digitazione.<br/> <br/> Il download potrebbe richiedere un paio di minuti su 3G. Potrebbero essere applicati costi se non disponi di un <b>piano dati illimitato</b>.<br/> Se non sei sicuro di quale sia il tuo piano dati, dovresti trovare una connessione Wi-Fi per avviare il download automaticamente.<br/> <br/> Suggerimento. Puoi scaricare e rimuovere dizionari passando a <b>Lingue e immissione</b> nel menu <b>Impostazioni</b> del dispositivo mobile."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Per la lingua selezionata sul dispositivo mobile è disponibile un dizionario.<br/> Ti consigliamo di <b>scaricare</b> il dizionario in <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> per migliorare la digitazione.<br/> <br/> Il download potrebbe richiedere un paio di minuti su 3G. Potrebbero essere applicati costi se non disponi di un <b>piano dati illimitato</b>.<br/> Se non sei sicuro di quale sia il tuo piano dati, dovresti trovare una connessione Wi-Fi per avviare il download automaticamente.<br/> <br/> Suggerimento. Puoi scaricare e rimuovere dizionari selezionando <b>Lingua e immissione</b> nel menu <b>Impostazioni</b> del dispositivo mobile."</string> <string name="download_over_metered" msgid="1643065851159409546">"Scarica ora (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Scarica tramite Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"È disponibile un dizionario per <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"È disponibile un dizionario per: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Premi per esaminare e scaricare"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Download: i suggerimenti per <xliff:g id="LANGUAGE">%1$s</xliff:g> saranno pronti a breve."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Download: i suggerimenti per <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> saranno pronti a breve."</string> <string name="version_text" msgid="2715354215568469385">"Versione <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Aggiungi"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Aggiungi al dizionario"</string> diff --git a/java/res/values-fa/donottranslate.xml b/java/res/values-iw-sw600dp/donottranslate-config-spacing-and-punctuations.xml index 57de2538b..22f0353ff 100644 --- a/java/res/values-fa/donottranslate.xml +++ b/java/res/values-iw-sw600dp/donottranslate-config-spacing-and-punctuations.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2014, 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. @@ -21,5 +21,5 @@ <!-- 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">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string> + <string name="suggested_punctuations">:,;,\",(|),)|(,\',-,/,@,_</string> </resources> diff --git a/java/res/values-ar/donottranslate.xml b/java/res/values-iw/donottranslate-config-spacing-and-punctuations.xml index 57de2538b..d30720811 100644 --- a/java/res/values-ar/donottranslate.xml +++ b/java/res/values-iw/donottranslate-config-spacing-and-punctuations.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2014, 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. diff --git a/java/res/values-iw/strings-config-important-notice.xml b/java/res/values-iw/strings-config-important-notice.xml new file mode 100644 index 000000000..34ef4cab5 --- /dev/null +++ b/java/res/values-iw/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"למד מהתכתבויות ומנתונים שהקלדת כדי לשפר את ההצעות"</string> +</resources> diff --git a/java/res/values-iw/strings-talkback-descriptions.xml b/java/res/values-iw/strings-talkback-descriptions.xml new file mode 100644 index 000000000..e6344fb04 --- /dev/null +++ b/java/res/values-iw/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"חבר אוזניות כדי לשמוע הקראה של מפתחות סיסמה."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"הטקסט הנוכחי הוא %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"לא הוזן טקסט"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> מתקן את <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ל-<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> מבצע תיקון אוטומטי"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"קוד מקש %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift פועל (הקש כדי להשבית)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock פועל (הקש כדי להשבית)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"מחק"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"סמלים"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"אותיות"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"מספרים"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"הגדרות"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"רווח"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"קלט הקול"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"אמוג\'י"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"חפש"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"נקודה"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"החלף שפה"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"הבא"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"הקודם"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift פועל"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock פועל"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift מושבת"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"מצב סמלים"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"מצב אותיות"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"מצב טלפון"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"מצב סמלי טלפון"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"המקלדת מוסתרת"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"מציג מקלדת <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"תאריך"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"תאריך ושעה"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"דוא\"ל"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"העברת הודעות"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"מספרים"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"מספרי טלפון"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"טקסט"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"זמן"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"כתובות אתרים"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"אחרונים"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"אנשים"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"אובייקטים"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"טבע"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"מקומות"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"סמלים"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"רגשונים"</string> +</resources> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 8d02e685b..dab2d8ed8 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"ברירת מחדל של המערכת"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"הצע שמות של אנשי קשר"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"השתמש בשמות מרשימת אנשי הקשר עבור הצעות ותיקונים"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"הצעות מותאמות אישית"</string> <string name="use_double_space_period" msgid="8781529969425082860">"רווח כפול לנקודה"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"הקשה פעמיים על מקש הרווח מזינה נקודה ואחריה רווח"</string> <string name="auto_cap" msgid="1719746674854628252">"הפיכת אותיות לרישיות באופן אוטומטי"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"הצג שובל תנועות"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"תצוגה צפה דינמית"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ראה את המילה המוצעת תוך כדי הזזת האצבע"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"חבר אוזניות כדי לשמוע הקראה של מפתחות סיסמה."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"הטקסט הנוכחי הוא %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"לא הוזן טקסט"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> מתקן את <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ל-<xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> מבצע תיקון אוטומטי"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"קוד מקש %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift פועל (הקש כדי להשבית)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock פועל (הקש כדי להשבית)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"מחק"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"סמלים"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"אותיות"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"מספרים"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"הגדרות"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"כרטיסייה"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"רווח"</string> - <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_search" msgid="1247236163755920808">"חפש"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"נקודה"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"החלף שפה"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"הבא"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"הקודם"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift פועל"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock פועל"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift מושבת"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"מצב סמלים"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"מצב אותיות"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"מצב טלפון"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"מצב סמלי טלפון"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"המקלדת מוסתרת"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"מציג מקלדת <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"תאריך"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"תאריך ושעה"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"דוא\"ל"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"העברת הודעות"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"מספרים"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"מספרי טלפון"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"טקסט"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"זמן"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"כתובות אתרים"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"הקלדת משפט בהחלקה"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"הזן רווחים במהלך התנועה על ידי החלקה אל מקש הרווח"</string> <string name="voice_input" msgid="3583258583521397548">"מקש קלט קולי"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"במקלדת הראשית"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"במקלדת סמלים"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"כבוי"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"מיקרופון במקלדת הראשית"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"מיקרופון במקלדת סמלים"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"הקלט הקולי מושבת"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"לא הופעלו שיטות של קלט קולי. בדוק את הגדרות השפה והקלט."</string> <string name="configure_input_method" msgid="373356270290742459">"הגדרת שיטות קלט"</string> <string name="language_selection_title" msgid="1651299598555326750">"שפות קלט"</string> <string name="send_feedback" msgid="1780431884109392046">"שלח משוב"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"אנגלית (בריטניה)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"אנגלית (ארה\"ב)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"ספרדית (ארצות הברית)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"אנגלית (בריטניה) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"אנגלית (ארה\"ב) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"ספרדית (ארצות הברית) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (מסורתית)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"אנגלית (בריטניה) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"אנגלית (ארה\"ב) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"ספרדית (ארה\"ב) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (מסורתית)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (קירילית)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (לטינית)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"ללא שפה (אלף-בית)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"אלף-בית (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"אלף-בית (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"קריאה של קובץ מילון חיצוני"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"אין קובצי מילונים בתיקיית ההורדות"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"בחירת קובץ מילון להתקנה"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"האם באמת להתקין את הקובץ הזה עבור <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"האם אתה באמת רוצה להתקין את הקובץ הזה עבור <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"אירעה שגיאה"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"צור מילון אנשי קשר"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"מחק מילון אישי"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"מחק את המילון של היסטוריית המשתמשים"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"מחק את מילון ההתאמה האישית"</string> <string name="button_default" msgid="3988017840431881491">"ברירת מחדל"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"ברוך הבא אל <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"עם הקלדת החלקה"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"רענן"</string> <string name="last_update" msgid="730467549913588780">"עודכן לאחרונה"</string> <string name="message_updating" msgid="4457761393932375219">"מחפש עדכונים"</string> - <string name="message_loading" msgid="8689096636874758814">"טוען..."</string> + <string name="message_loading" msgid="5638680861387748936">"טוען…"</string> <string name="main_dict_description" msgid="3072821352793492143">"מילון ראשי"</string> <string name="cancel" msgid="6830980399865683324">"בטל"</string> + <string name="go_to_settings" msgid="3876892339342569259">"הגדרות"</string> <string name="install_dict" msgid="180852772562189365">"התקן"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"בטל"</string> <string name="delete_dict" msgid="756853268088330054">"מחק"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"לשפה הנבחרת במכשיר הנייד שלך יש מילון זמין.<br/> אנו ממליצים <b>להוריד</b> את המילון ב<xliff:g id="LANGUAGE">%1$s</xliff:g> כדי לשפר את חוויית ההקלדה.<br/> <br/> ההורדה עשויה לארוך דקה או שתיים ב-3G. ייתכן שתחויב אם אין לך <b>תכנית נתונים בלתי מוגבלת</b>.<br/> אם אינך בטוח איזו תכנית נתונים יש לך, אנו ממליצים לחפש חיבור Wi-Fi כדי להתחיל בהורדה באופן אוטומטי.<br/> <br/> טיפ: ניתן להוריד ולהסיר מילונים ב<b>שפה וקלט</b> בתפריט <b>הגדרות</b> של המכשיר הנייד שלך."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"יש מילון זמין עבור השפה הנבחרת במכשיר הנייד שלך.<br/> אנחנו ממליצים <b>להוריד</b> את המילון ב<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> לשיפור חוויית ההקלדה.<br/> <br/> ייתכן שההורדה תארך דקה או שתיים ברשת דור שלישי. ייתכנו חיובים אם אין לך <b>תכנית נתונים ללא הגבלה</b>.<br/> אם אינך בטוח איזו תכנית נתונים יש לך, אנחנו ממליצים למצוא חיבור Wi-Fi כדי להתחיל את ההורדה באופן אוטומטי.<br/> <br/> טיפ: ניתן להוריד ולהסיר מילונים על ידי מעבר אל <b>שפה וקלט</b> בתפריט <b>הגדרות</b> של המכשיר הנייד."</string> <string name="download_over_metered" msgid="1643065851159409546">"הורד עכשיו (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"הורד באמצעות Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"יש מילון זמין עבור <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"יש מילון זמין עבור <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"לחץ כדי לעיין ולהוריד"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"מוריד: הצעות ב<xliff:g id="LANGUAGE">%1$s</xliff:g> יהיו מוכנות בקרוב."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"מוריד: הצעות עבור <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> יהיו מוכנות בקרוב."</string> <string name="version_text" msgid="2715354215568469385">"גרסה <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"הוסף"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"הוסף למילון"</string> diff --git a/java/res/values-ja/strings-config-important-notice.xml b/java/res/values-ja/strings-config-important-notice.xml new file mode 100644 index 000000000..03c1f48e9 --- /dev/null +++ b/java/res/values-ja/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"メッセージなどのやり取りや入力したデータから入力候補を予測します"</string> +</resources> diff --git a/java/res/values-ja/strings-talkback-descriptions.xml b/java/res/values-ja/strings-talkback-descriptions.xml new file mode 100644 index 000000000..990774e16 --- /dev/null +++ b/java/res/values-ja/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"パスワードのキーが音声出力されるのでヘッドセットを接続してください。"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"現在のテキスト: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"テキストが入力されていません"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g>は<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>を<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>に修正します"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g>で自動修正が実行されます"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"キーコード: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift有効(タップして解除)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"CapsLock有効(タップして解除)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"削除"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"記号"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"英字"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"数字"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"設定"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"タブ"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"音声入力"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"絵文字"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"検索"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"ドット"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"言語を切り替え"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"次へ"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"前へ"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift有効"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"CapsLock有効"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift解除"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"記号モード"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"英数モード"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"電話モード"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"電話記号モード"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"キーボードは非表示です"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g>のキーボードを表示しています"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"日付"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"日時"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"メールアドレス"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"メッセージ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"数値"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"電話番号"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"テキスト"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"時刻"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"最近"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"人"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"物"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"自然"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"場所"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"記号"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"絵文字"</string> +</resources> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index fbfd3b7f7..7d749a6a2 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"システムのデフォルト"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"連絡先の名前を候補に表示"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"連絡先の名前を使用して候補表示や自動修正を行います"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"入力候補のカスタマイズ"</string> <string name="use_double_space_period" msgid="8781529969425082860">"ダブルスペースピリオド"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"スペースバーをダブルタップするとピリオドとスペースを挿入できます"</string> <string name="auto_cap" msgid="1719746674854628252">"自動大文字変換"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"ジェスチャートレイルを表示"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"動的フローティングプレビュー"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ジェスチャーで入力候補を表示できます"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"パスワードのキーが音声出力されるのでヘッドセットを接続してください。"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"現在のテキスト:%s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"テキストが入力されていません"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g>は<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>を<xliff:g id="CORRECTED">%3$s</xliff:g>に修正します"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g>で自動修正が実行されます"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"キーコード:%d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift有効(タップして解除)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock有効(タップして解除)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"DEL"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"記号"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"英字"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"数字"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"設定"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string> - <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_search" msgid="1247236163755920808">"検索"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"中点"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"言語を切り替え"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"次へ"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"前へ"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift有効"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock有効"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift解除"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"記号モード"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"英数モード"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"電話モード"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"電話記号モード"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"キーボードは非表示です"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g>のキーボードを表示しています"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"日付"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"日時"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"メールアドレス"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"メッセージ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"数値"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"電話番号"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"テキスト"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"時刻"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"フレーズジェスチャー"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Spaceキーに指を滑らせると、ジェスチャー中にスペースを入力できます"</string> <string name="voice_input" msgid="3583258583521397548">"音声入力キー"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"メインキーボード上"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"記号キーボード上"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"OFF"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"メインキーボードのマイク"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"記号キーボードのマイク"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"音声入力は無効です"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"有効になっている音声入力方法がありません。[言語と入力]設定をご確認ください。"</string> <string name="configure_input_method" msgid="373356270290742459">"入力方法を設定"</string> <string name="language_selection_title" msgid="1651299598555326750">"入力言語"</string> <string name="send_feedback" msgid="1780431884109392046">"フィードバックを送信"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"英語 (英国)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英語 (米国)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"スペイン語 (米国)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"英語 (英国) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"英語 (米国) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"スペイン語 (米国) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g>(伝統言語)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"英語(英国)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"英語(米国)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"スペイン語(米国)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(伝統言語)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(キリル文字)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(ラテン文字)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"言語なし(アルファベット)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"アルファベット(QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"アルファベット(QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"外部辞書ファイルの読み取り"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"ダウンロードフォルダに辞書ファイルはありません"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"インストールする辞書ファイルの選択"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"この<xliff:g id="LOCALE_NAME">%s</xliff:g>のファイルをインストールしてもよろしいですか?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"この<xliff:g id="LANGUAGE_NAME">%s</xliff:g>のファイルをインストールしますか?"</string> <string name="error" msgid="8940763624668513648">"エラーが発生しました"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"連絡先辞書のダンプ"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"単語リストのダンプ"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ユーザー履歴辞書のダンプ"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"カスタマイズ辞書のダンプ"</string> <string name="button_default" msgid="3988017840431881491">"デフォルト"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>へようこそ"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"新しいジェスチャー入力をお試しください"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"更新"</string> <string name="last_update" msgid="730467549913588780">"最終更新"</string> <string name="message_updating" msgid="4457761393932375219">"アップデートを確認しています"</string> - <string name="message_loading" msgid="8689096636874758814">"読み込んでいます..."</string> + <string name="message_loading" msgid="5638680861387748936">"読み込んでいます…"</string> <string name="main_dict_description" msgid="3072821352793492143">"メイン辞書"</string> <string name="cancel" msgid="6830980399865683324">"キャンセル"</string> + <string name="go_to_settings" msgid="3876892339342569259">"設定"</string> <string name="install_dict" msgid="180852772562189365">"インストール"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"キャンセル"</string> <string name="delete_dict" msgid="756853268088330054">"削除"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"お使いの携帯端末で選択した言語に対応する辞書があります。<br/>入力機能をより快適にご利用いただくため、<xliff:g id="LANGUAGE">%1$s</xliff:g>の辞書の<b>ダウンロード</b>をおすすめします。<br/> <br/>3G経由の場合、ダウンロードに要する時間は1~2分です。<b>定額制のデータプラン</b>をご利用でない場合は通信料が発生する可能性があります。<br/>ご利用のデータプランが不明な場合は、自動的にダウンロードが開始されるWi-Fi接続を探すことをおすすめします。<br/> <br/>ヒント: 辞書のダウンロードや削除は、お使いの携帯端末の[<b>設定</b>]メニューの[<b>言語と入力</b>]で行えます。"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"お使いの携帯端末で選択した言語に対応する辞書があります。<br/>入力機能をより快適にご利用いただくため、<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>の辞書の<b>ダウンロード</b>をおすすめします。<br/> <br/>3G経由の場合、ダウンロードに要する時間は1~2分です。<b>定額制のデータプラン</b>をご利用でない場合は通信料が発生する可能性があります。<br/>ご利用のデータプランが不明な場合は、自動的にダウンロードが開始されるWi-Fi接続を探すことをおすすめします。<br/> <br/>ヒント: 辞書のダウンロードや削除は、お使いの携帯端末の[<b>設定</b>]メニューの[<b>言語と入力</b>]で行えます。"</string> <string name="download_over_metered" msgid="1643065851159409546">"今すぐダウンロード(<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi経由でダウンロード"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g>の辞書を利用できます"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>の辞書を利用できます"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"押すと確認/ダウンロードできます"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"ダウンロード中: <xliff:g id="LANGUAGE">%1$s</xliff:g>の入力候補をまもなく利用できます。"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"ダウンロード中: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>の入力候補をまもなく利用できます。"</string> <string name="version_text" msgid="2715354215568469385">"バージョン<xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"追加"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"辞書に追加"</string> diff --git a/java/res/values-ka-rGE/strings-config-important-notice.xml b/java/res/values-ka-rGE/strings-config-important-notice.xml new file mode 100644 index 000000000..188ac871c --- /dev/null +++ b/java/res/values-ka-rGE/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"უკეთესი შეთავაზებისთვის თქვენი კომუნიკაციიდან და ტექსტიდან სწავლა"</string> +</resources> diff --git a/java/res/values-ka-rGE/strings-talkback-descriptions.xml b/java/res/values-ka-rGE/strings-talkback-descriptions.xml new file mode 100644 index 000000000..c4fd65939 --- /dev/null +++ b/java/res/values-ka-rGE/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"შეაერთეთ ყურსასმენი, რათა მოისმინოთ აკრეფილი პაროლის კლავიშების სახელები."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"მიმდინარე ტექსტი არის %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"ტექსტი შეყვანილი არ არის"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> შეასწორებს <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-ს <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>-ად"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ასრულებს ავტოკორექციას"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"კლავიატურის კოდი %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift ჩართულია (შეეხეთ გამოსართავად)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"ჩართულია Caps (შეეხეთ გამოსართავად)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"წაშლა"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"სიმბოლოები"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"ასოები"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"ნომრები"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"პარამეტრები"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab კლავიში"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"შორისი"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"ხმოვანი შეყვანა"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"სიცილაკები"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"დაბრუნება"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"ძიება"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"წერტილი"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"ენის გადართვა"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"შემდ."</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"წინა"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift ჩართულია"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"ჩართულია Caps"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift გამორთულია"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"სიმბოლოების რეჟიმი"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"ასოების რეჟიმი"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"ტელეფონის რეჟიმი"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"ტელეფონის სიმბოლოების რეჟიმი"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"კლავიატურა დამალულია"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"ნაჩვენებია <xliff:g id="KEYBOARD_MODE">%s</xliff:g> კლავიატურა"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"თარიღი"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"თარიღი და დრო"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ელფოსტა"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"შეტყობინებები"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"რიცხვები"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"ტელეფონი"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"ტექსტი"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"დრო"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"ბოლოს გამოყენებული"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"ხალხი"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"ობიექტები"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"ბუნება"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"ადგილები"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"სიმბოლოები"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"სიცილაკები"</string> +</resources> diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml index dec6b3a6b..547bf29ca 100644 --- a/java/res/values-ka-rGE/strings.xml +++ b/java/res/values-ka-rGE/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"სისტემის ნაგულისხმევი"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"კონტაქტის სახელების შეთავაზება"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"კონტაქტებიდან სახელების გამოყენება შეთავაზებებისთვის და კორექციისთვის"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"პერსონალიზებული შეთავაზებები"</string> <string name="use_double_space_period" msgid="8781529969425082860">"წერტილი ორმაგი შორისით"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"შორისზე ორჯერ შეხება დაწერს წერტილს და შორისის სიმბოლოს"</string> <string name="auto_cap" msgid="1719746674854628252">"ავტო-კაპიტალიზაცია"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"ჟესტიკულაციის კუდის ჩვენება"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"დინამიურად მოლივლივე გადახედვა"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ჟესტიკულაციისას შეთავაზებული სიტყვის ნახვა"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : შეინახა"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"შეაერთეთ ყურსაცვამი, რათა მოისმინოთ აკრეფილი პაროლის კლავიშების სახელები."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"მიმდინარე ტექსტი არის %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"ტექსტი არ შეყვანილა"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> შეასწორებს <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-ს <xliff:g id="CORRECTED">%3$s</xliff:g>-ად"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> ასრულებს ავტოკორექციას"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"კლავიატურის კოდი %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ჩართულია (შეეხეთ გამოსართავად)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"ჩართულია Caps (შეეხეთ გამოსართავად)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"სიმბოლოები"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"ასოები"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"ნომრები"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"პარამეტრები"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"შორისი"</string> - <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_search" msgid="1247236163755920808">"ძიება"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"წერტილი"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"ენის გადართვა"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"შემდეგი"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"წინა"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ჩართულია"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"ჩართულია Caps"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift გამორთულია"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"სიმბოლოების რეჟიმი"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"ასოების რეჟიმი"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"ტელეფონის რეჟიმი"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"ტელეფონის სიმბოლოების რეჟიმი"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"კლავიატურა დამალულია"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"ნაჩვენებია <xliff:g id="MODE">%s</xliff:g> კლავიატურა"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"თარიღი"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"თარიღი და დრო"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"ელფოსტა"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"შეტყობინებები"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"რიცხვები"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"ტელეფონი"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"ტექსტი"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"დრო"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"ფრაზის ჟესტი"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"შეიყვანეთ შორისები ჟესტიკულაციისას შორისის კლავიშზე გასრიალებით"</string> <string name="voice_input" msgid="3583258583521397548">"ხმოვანი შეყვანის კლავიში"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"მთავარ კლავიატურაზე"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"სიმბოლოთა კლავიატურაზე"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"გამორთვა"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"მიკროფონი მთავარ კლავიატურაზე"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"მიკროფონი სიმბოლოთა კლავიატურაზე"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ხმოვანი შეყვანა გამორთულია"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ხმოვანი შეყვანის მეთოდები ჩართული არ არის. შეამოწმეთ ენის & შეყვანის პარამეტრები."</string> <string name="configure_input_method" msgid="373356270290742459">"შეყვანის მეთოდების კონფიგურაცია"</string> <string name="language_selection_title" msgid="1651299598555326750">"შეყვანის ენები"</string> <string name="send_feedback" msgid="1780431884109392046">"უკუკავშირის გაგზავნა"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"ინგლისური (გართ. სამ.)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"ინგლისური (აშშ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"ესპანური (აშშ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"ინგლისური (გაერთ. სამ.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"ინგლისური (აშშ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"ესპანური (აშშ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (ტრადიციული)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"ინგლისური (გაერთ.სამ.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"ინგლისური (აშშ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"ესპანური (აშშ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ტრადიციული)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (კირილიცა)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ლათინური)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"ენის გარეშე (ანბანი)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"ანბანი (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"ანბანი (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"გარე ლექსიკონის ფაილის წაკითხვა"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"ჩამოტვირთვების საქაღალდეში ლექსიკონის ფაილები არ არის"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ინსტალაციისათვის აირჩიეთ ლექსიკონის ფაილი"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"ნამდვილად გსურთ ამ ფაილის <xliff:g id="LOCALE_NAME">%s</xliff:g>-ისთვის ინსტალაცია?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ნამდვილად გსურთ ამ ფაილის <xliff:g id="LANGUAGE_NAME">%s</xliff:g>-ისთვის ინსტალაცია?"</string> <string name="error" msgid="8940763624668513648">"წარმოიშვა შეცდომა"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"კონტაქტების საქაღალდის ამონაწერი"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"პერსონალური საქაღალდის ჩამოწერა"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"მომხმ. ისტორიის საქაღალდის ჩამოწერა"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"პერსონალიზაციის საქაღალდის ჩამოწერა"</string> <string name="button_default" msgid="3988017840431881491">"ნაგულისხმევი"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"კეთილი იყოს თქვენი მობრძანება <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ში"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"ჟესტებით წერით"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"განახლება"</string> <string name="last_update" msgid="730467549913588780">"ბოლო განახლება"</string> <string name="message_updating" msgid="4457761393932375219">"მიმდინარეობს განახლებების შემოწმება"</string> - <string name="message_loading" msgid="8689096636874758814">"იტვირთება…"</string> + <string name="message_loading" msgid="5638680861387748936">"იტვირთება..."</string> <string name="main_dict_description" msgid="3072821352793492143">"მთავარი ლექსიკონი"</string> <string name="cancel" msgid="6830980399865683324">"გაუქმება"</string> + <string name="go_to_settings" msgid="3876892339342569259">"პარამეტრები"</string> <string name="install_dict" msgid="180852772562189365">"ინსტალაცია"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"გაუქმება"</string> <string name="delete_dict" msgid="756853268088330054">"წაშლა"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"თქვენ მიერ მობილურ მოწყობილობაზე არჩეული ენისათვის ხელმისაწვდომია ლექსიკონი.<br/> გირჩევთ, <b>ჩამოტვირთოთ</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> ლექსიკონი, რათა გაიმარტივოთ ტექსტის შეყვანა.<br/> <br/> ჩამოტვირთვას შესაძლოა დაჭირდეს ერთი ან ორი წუთი 3G სისწრაფეზე. თუ ულიმიტო არ გაქვთ <b> მობილური ინტერნეტის ტარიფი</b>.<br/&gt, შესაძლოა ჩამოტვირთვა დამატებით გადასახადებთან იყოს დაკავშირებული; თუ არ ხართ დარწმუნებული მობილური ინტერნეტის აქტიური ტარიფის შესახებ, გირჩევთ იპოვოთ Wi-Fi კავშირი და ავტომატურად დაიწყოთ ჩამოტვირთვა.<br/> <br/> რჩევა: ლექსიკონების ჩამოტვირთვა და ამოშლა შესაძლებელია სექციიდან <b>ენა და შეყვანა</b> სექციიდან, თქვენი მობილური მოწყობილობის <b>პარამეტრების</b> მენიუში."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"თქვენ მიერ მობილურ მოწყობილობაზე არჩეული ენისთვის ხელმისაწვდომია ლექსიკონი.<br/> გირჩევთ, <b>ჩამოტვირთოთ</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ლექსიკონი, რათა გაიმარტივოთ ტექსტის შეყვანა.<br/> <br/> ჩამოტვირთვას შესაძლოა დასჭირდეს ერთი ან ორი წუთი 3G სისწრაფეზე. თუ <b> მობილური ინტერნეტის ტარიფი</b>.<br/&gt ულიმიტო არ გაქვთ, შესაძლოა გადახდა მოგიწიოთ; თუ არ ხართ დარწმუნებული მობილური ინტერნეტის აქტიური ტარიფის შესახებ, გირჩევთ, იპოვოთ Wi-Fi კავშირი და ავტომატურად დაიწყოთ ჩამოტვირთვა.<br/> <br/> რჩევა: ლექსიკონების ჩამოტვირთვა და ამოშლა შეიძლება სექციიდან <b>ენა და შეყვანა</b> თქვენი მობილური მოწყობილობის <b>პარამეტრების</b> მენიუში."</string> <string name="download_over_metered" msgid="1643065851159409546">"ახლა ჩამოტვირთვა (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>მბაიტი)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi კავშირზე ჩამოტვირთვა"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g>-ისთვის ხელმისაწვდომია ლექსიკონი"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-სთვის ხელმისაწვდომია ლექსიკონი"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"დააჭირეთ განხილვას და ჩამოტვირთეთ"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"ჩამოტვირთვა: <xliff:g id="LANGUAGE">%1$s</xliff:g>-ის შემოთავაზებები მალე მომზადდება."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"იტვირთება: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-ის შემოთავაზებები მალე მომზადდება."</string> <string name="version_text" msgid="2715354215568469385">"ვერსია <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"დამატება"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"ლექსიკონში დამატება"</string> diff --git a/java/res/values-kk/strings-talkback-descriptions.xml b/java/res/values-kk/strings-talkback-descriptions.xml new file mode 100644 index 000000000..13adf830d --- /dev/null +++ b/java/res/values-kk/strings-talkback-descriptions.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="896961781287283493">"Дауыспен айтылатын құпия сөз кілттерін есту үшін құлақаспап қосыңыз."</string> + <string name="spoken_current_text_is" msgid="2485723011272583845">"Ағымдағы мәтін - %s"</string> + <string name="spoken_no_text_entered" msgid="7479685225597344496">"Мәтін енгізілмеген"</string> + <!-- no translation found for spoken_auto_correct (8005997889020109763) --> + <skip /> + <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> + <skip /> + <string name="spoken_description_unknown" msgid="3197434010402179157">"Перне коды %d"</string> + <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift қосулы (өшіру үшін түрту)"</string> + <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock қосулы (өшіру үшін түрту)"</string> + <string name="spoken_description_delete" msgid="8740376944276199801">"Жою"</string> + <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Таңбалар"</string> + <string name="spoken_description_to_alpha" msgid="23129338819771807">"Әріптер"</string> + <string name="spoken_description_to_numeric" msgid="591752092685161732">"Сандар"</string> + <string name="spoken_description_settings" msgid="4627462689603838099">"Баптаулар"</string> + <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> + <string name="spoken_description_space" msgid="2582521050049860859">"Бос орын"</string> + <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_search" msgid="1247236163755920808">"Іздеу"</string> + <string name="spoken_description_dot" msgid="40711082435231673">"Нүкте"</string> + <string name="spoken_description_language_switch" msgid="5507091328222331316">"Тілді ауыстыру"</string> + <string name="spoken_description_action_next" msgid="8636078276664150324">"Келесі"</string> + <string name="spoken_description_action_previous" msgid="800872415009336208">"Алдағы"</string> + <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift қосылған"</string> + <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock қосылған"</string> + <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift өшірілген"</string> + <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Таңбалар режимі"</string> + <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Әріптер режимі"</string> + <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Телефон режимі"</string> + <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Телефон таңбалары режимі"</string> + <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Пернетақта жасырылған"</string> + <string name="announce_keyboard_mode" msgid="4729081055438508321">"Көрсетілетін <xliff:g id="MODE">%s</xliff:g> пернетақтасы"</string> + <string name="keyboard_mode_date" msgid="3137520166817128102">"күн"</string> + <string name="keyboard_mode_date_time" msgid="339593358488851072">"күн мен уақыт"</string> + <string name="keyboard_mode_email" msgid="6216248078128294262">"электрондық пошта"</string> + <string name="keyboard_mode_im" msgid="1137405089766557048">"хабар алмасу"</string> + <string name="keyboard_mode_number" msgid="7991623440699957069">"нөмір"</string> + <string name="keyboard_mode_phone" msgid="6851627527401433229">"телефон"</string> + <string name="keyboard_mode_text" msgid="6479436687899701619">"мәтін"</string> + <string name="keyboard_mode_time" msgid="4381856885582143277">"уақыт"</string> + <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> +</resources> diff --git a/java/res/values-kk/strings.xml b/java/res/values-kk/strings.xml index 947ff2fe9..83ac0daf7 100644 --- a/java/res/values-kk/strings.xml +++ b/java/res/values-kk/strings.xml @@ -73,58 +73,9 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Қимыл қадамын көрсету"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамикалық қалқымалы қарап шығу"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Қимылдау кезінде ұсынылған сөзді көру"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сақталды"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Дауыспен айтылатын құпия сөз кілттерін есту үшін құлақаспап қосыңыз."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Ағымдағы мәтін - %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Мәтін енгізілмеген"</string> - <!-- no translation found for spoken_auto_correct (8005997889020109763) --> - <skip /> - <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> - <skip /> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Перне коды %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift қосулы (өшіру үшін түрту)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock қосулы (өшіру үшін түрту)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Жою"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Таңбалар"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Әріптер"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Сандар"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Баптаулар"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Бос орын"</string> - <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_search" msgid="1247236163755920808">"Іздеу"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Нүкте"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Тілді ауыстыру"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Келесі"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Алдағы"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift қосылған"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock қосылған"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift өшірілген"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Таңбалар режимі"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Әріптер режимі"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Телефон режимі"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Телефон таңбалары режимі"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Пернетақта жасырылған"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Көрсетілетін <xliff:g id="MODE">%s</xliff:g> пернетақтасы"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"күн"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"күн мен уақыт"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"электрондық пошта"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"хабар алмасу"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"нөмір"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"телефон"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"мәтін"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"уақыт"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="8244483979855138643">"Фраза қимылы"</string> + <string name="gesture_space_aware_summary" msgid="3226298212755100667">"Бос орын пернесін жанау арқылы қимылдар барысында бос орындарды енгізу"</string> <string name="voice_input" msgid="3583258583521397548">"Дауыстық енгізу пернесі"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Негізгі пернетақтада"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Таңбалар пернетақтасында"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Өшірулі"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Негізгі пернетақтадағы Mic"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Таңбалар пернетақтасындағы Mic"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Дауыстық енгізу өшірілген"</string> <string name="configure_input_method" msgid="373356270290742459">"Енгізу әдістерін теңшеу"</string> <string name="language_selection_title" msgid="1651299598555326750">"Енгізу тілдері"</string> <string name="send_feedback" msgid="1780431884109392046">"Кері байланыс жіберу"</string> diff --git a/java/res/values-km-rKH/donottranslate.xml b/java/res/values-km-rKH/donottranslate-config-spacing-and-punctuations.xml index a9893feec..a9893feec 100644 --- a/java/res/values-km-rKH/donottranslate.xml +++ b/java/res/values-km-rKH/donottranslate-config-spacing-and-punctuations.xml diff --git a/java/res/values-km-rKH/strings-config-important-notice.xml b/java/res/values-km-rKH/strings-config-important-notice.xml new file mode 100644 index 000000000..9d694db74 --- /dev/null +++ b/java/res/values-km-rKH/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"សិក្សាការភ្ជាប់របស់អ្នកនិងទិន្នន័យដែលបានបញ្ចូលដើម្បីធ្វើសំណើឲ្យល្អ"</string> +</resources> diff --git a/java/res/values-km-rKH/strings-talkback-descriptions.xml b/java/res/values-km-rKH/strings-talkback-descriptions.xml new file mode 100644 index 000000000..76bc35f84 --- /dev/null +++ b/java/res/values-km-rKH/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"ដោតកាស ដើម្បីស្ដាប់ពាក្យសម្ងាត់ដែលនិយាយឮៗ។"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"អត្ថបទបច្ចុប្បន្នគឺ %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"គ្មានអត្ថបទបានបញ្ចូល"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> កែ <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ទៅជា <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> អនុវត្តការកែស្វ័យប្រវត្តិ"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"កូដគ្រាប់ចុច %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"បើក Shift (ប៉ះដើម្បីបិទ)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"បើក Caps lock (ប៉ះដើម្បីបិទ)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"លុប"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"និមិត្តសញ្ញា"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"អក្សរ"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"លេខ"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"ការកំណត់"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"ដកឃ្លា"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"ការបញ្ចូលសំឡេង"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"សញ្ញាអារម្មណ៍"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"ស្វែងរក"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"សញ្ញា(.)"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"ប្ដូរភាសា"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"បន្ទាប់"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"មុន"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"បានបើក Shift"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"បានបើក Caps lock"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"បានបិទ Shift"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"របៀបនិមិត្តសញ្ញា"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"របៀបអក្សរ"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"របៀបទូរស័ព្ទ"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"របៀបនិមិត្តសញ្ញាទូរស័ព្ទ"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"បានលាក់ក្ដារចុច"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"បង្ហាញក្ដារចុច <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"កាលបរិច្ឆេទ"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"កាលបរិច្ឆេទ និងពេលវេលា"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"អ៊ីមែល"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ការផ្ញើសារ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"លេខ"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"ទូរស័ព្ទ"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"អត្ថបទ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ពេលវេលា"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"ថ្មីៗ"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"មនុស្ស"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"វត្ថុ"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"ធម្មជាតិ"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"ទីកន្លែង"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"និមិត្តសញ្ញា"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"សញ្ញាអារម្មណ៍"</string> +</resources> diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml index 86ecc5e10..519aa44d0 100644 --- a/java/res/values-km-rKH/strings.xml +++ b/java/res/values-km-rKH/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"លំនាំដើមប្រព័ន្ធ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"ស្នើឈ្មោះទំនាក់ទំនង"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ប្រើឈ្មោះពីទំនាក់ទំនងសម្រាប់ការស្នើ និងកែ"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"ការស្នើផ្ទាល់ខ្លួន"</string> <string name="use_double_space_period" msgid="8781529969425082860">"រយៈពេលចុចដកឃ្លាពីរដង"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"ប៉ះដកឃ្លាពីរដងបញ្ចូលរយៈពេលដែលអនុវត្តតាមដកឃ្លា"</string> <string name="auto_cap" msgid="1719746674854628252">"ការសរសេរជាអក្សរធំស្វ័យប្រវត្តិ"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"បង្ហាញដានកាយវិការ"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"មើលការអណ្ដែតដែលមានចលនាជាមុន"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"មើលពាក្យដែលបានស្នើខណៈពេលកំពុងធ្វើកាយវិការ"</string> - <string name="added_word" msgid="8993883354622484372">"បានរក្សាទុក <xliff:g id="WORD">%s</xliff:g> ៖"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"ដោតកាស ដើម្បីស្ដាប់ពាក្យសម្ងាត់។"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"អត្ថបទបច្ចុប្បន្នគឺ %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"គ្មានអត្ថបទបានបញ្ចូល"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> កែ <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ទៅ <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> អនុវត្តការកែដោយស្វ័យប្រវត្តិ"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"កូដគ្រាប់ចុច %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"បើក Shift (ប៉ះដើម្បីបិទ)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"បើក Caps lock (ប៉ះដើម្បីបិទ)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"និមិត្តសញ្ញា"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"អក្សរ"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"លេខ"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"ការកំណត់"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"ដកឃ្លា"</string> - <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_search" msgid="1247236163755920808">"ស្វែងរក"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"ប្ដូរភាសា"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"បន្ទាប់"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"មុន"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"បានបើក Shift"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"បានបើក Caps lock"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"បានបិទ Shift"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"របៀបនិមិត្តសញ្ញា"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"របៀបអក្សរ"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"របៀបទូរស័ព្ទ"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"របៀបនិមិត្តសញ្ញាទូរស័ព្ទ"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"បានលាក់ក្ដារចុច"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"បង្ហាញក្ដារចុច <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"កាលបរិច្ឆេទ"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"កាលបរិច្ឆេទ និងពេលវេលា"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"អ៊ីមែល"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ផ្ញើសារ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"លេខ"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"ទូរស័ព្ទ"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"អត្ថបទ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ពេលវេលា"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"កាយវិការឃ្លា"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"បញ្ចូលដកឃ្លាអំឡុងកាយវិការ ដោយរំកិលទៅគ្រាប់ចុចដកឃ្លា"</string> <string name="voice_input" msgid="3583258583521397548">"គ្រាប់ចុចបញ្ចូលសំឡេង"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"នៅលើក្ដារចុចចម្បង"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"នៅលើក្ដារចុចនិមិត្តសញ្ញា"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"បិទ"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"មីក្រូហ្វូននៅលើក្ដារចុចចម្បង"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"មីក្រូហ្វូននៅលើក្ដារចុចនិមិត្តសញ្ញា"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"បានបិទការបញ្ចូលសំឡេង"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"គ្មានវិធីសាស្ត្របញ្ចូលសំឡេងបានបើក។ ពិនិត្យមើលការកំណត់ភាសា & ការបញ្ចូល។"</string> <string name="configure_input_method" msgid="373356270290742459">"កំណត់រចនាសម្ព័ន្ធវិធីសាស្ត្របញ្ចូល"</string> <string name="language_selection_title" msgid="1651299598555326750">"បញ្ចូលភាសា"</string> <string name="send_feedback" msgid="1780431884109392046">"ផ្ញើមតិអ្នកប្រើ"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"អង់គ្លេស (អង់គ្លេស)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"អង់គ្លេស (សហរដ្ឋអាមេរិក)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"អេស្ប៉ាញ (សហរដ្ឋអាមេរិក)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"អង់គ្លេស (ចក្រភពអង់គ្លេស) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"អង់គ្លេស (អាមេរិក) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"អេស្ប៉ាញ (អាមេរិក) ( <xliff:g id="LAYOUT">%s</xliff:g> )"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (អក្សរពេញ)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"អង់គ្លេស (ចក្រភពអង់គ្លេស) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"អង់គ្លេស (អាមេរិក) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"អេស្ប៉ាញ (អាមេរិក) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (អក្សរពេញ)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ស៊ីរី)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ឡាតាំង)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"គ្មានភាសា (អក្សរក្រម)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"តាមលំដាប់អក្សរក្រម (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"តាមលំដាប់អក្សរក្រម (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"អានឯកសារវចនានុក្រមខាងក្រៅ"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មានឯកសារវចនានុក្រមនៅក្នុងថតទាញយក"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ជ្រើសឯកសារវចនានុក្រម ដើម្បីដំឡើង"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"ពិតជាដំឡើងឯកសារនេះសម្រាប់ <xliff:g id="LOCALE_NAME">%s</xliff:g> ឬ?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ពិតជាដំឡើងឯកសារនេះសម្រាប់ <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"មានកំហុស"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"រាយវចនានុក្រមទំនាក់ទំនង"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"បោះបង់វចនានុក្រមផ្ទាល់ខ្លួន"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"បោះបង់វចនានុក្រមប្រវត្តិអ្នកប្រើ"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"បោះបង់វចនានុក្រមផ្ទាល់ខ្លួន"</string> <string name="button_default" msgid="3988017840431881491">"លំនាំដើម"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"សូមស្វាគមន៍មកកាន់ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"ជាមួយការវាយបញ្ចូលដោយប្រើកាយវិការ"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"ផ្ទុកឡើងវិញ"</string> <string name="last_update" msgid="730467549913588780">"បានធ្វើបច្ចុប្បន្នភាពចុងក្រោយ"</string> <string name="message_updating" msgid="4457761393932375219">"ពិនិត្យមើលបច្ចុប្បន្នភាព"</string> - <string name="message_loading" msgid="8689096636874758814">"កំពុងផ្ទុក..."</string> + <string name="message_loading" msgid="5638680861387748936">"កំពុងផ្ទុក..."</string> <string name="main_dict_description" msgid="3072821352793492143">"វចនានុក្រមចម្បង"</string> <string name="cancel" msgid="6830980399865683324">"បោះបង់"</string> + <string name="go_to_settings" msgid="3876892339342569259">"ការកំណត់"</string> <string name="install_dict" msgid="180852772562189365">"ដំឡើង"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"បោះបង់"</string> <string name="delete_dict" msgid="756853268088330054">"លុប"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"ភាសាដែលបានជ្រើសនៅលើឧបករណ៍របស់អ្នកមានវចនានុក្រម។ <br/> យើងបានផ្ដល់អនុសាសន៍ <b>ទាញយក</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> វចនានុក្រម ដើម្បីធ្វើឲ្យការវាយបញ្ចូលរបស់អ្នកប្រសើរឡើង។ <br/> <br/> ការទាញយកអាចចំណាយពេលមួយ ឬពីរនាទីតាម 3G ។ ការកាត់លុយអាចអនុវត្ត ប្រសិនបើអ្នកបាន <b>កំណត់ទិន្នន័យគ្មានដែនកំណត់ </b>.<br/> ប្រសិនបើអ្នកមិនប្រាកដថាទិន្នន័យអ្នកមិនបានកំណត់ យើងបានផ្ដល់អនុសាសន៍ដោយស្វែងរកការភ្ជាប់វ៉ាយហ្វាយ ដើម្បីចាប់ផ្ដើមទាញយកដោយស្វ័យប្រវត្តិ។<br/> <br/> ព័ត៌មានជំនួយ៖ អ្នកអាចទាញយក និងលុបវចនានុក្រមដោយចូលទៅ <b>ភាសា& បញ្ចូល</b>នៅក្នុងម៉ឺនុយ <b>ការកំណត់ </b> របស់ឧបករណ៍ចល័ត។"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសាដែលបានជ្រើសនៅលើឧបករណ៍ចល័តមានវចនានុក្រមអាចប្រើបាន។<br/> យើងផ្ដល់អនុសាសន៍ឲ្យ <b>ទាញយក</b> វចនានុក្រមភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បីបង្កើនបទពិសោធន៍វាយបញ្ចូលរបស់អ្នក។<br/> <br/> ការទាញយកអាចចំណាយពេលប្រហែលពីរនាទីនៅតាម 3G។ ការគិតថ្លៃអាចអនុវត្តប្រសិនបើអ្នកមិនប្រើ <b>ផែនការទិន្នន័យគ្មានដែនកំណត់</b>.<br/> បើអ្នកមិនប្រាកដថាផែនការណាមួយដែលអ្នកមាន យើងផ្ដល់អនុសាសន៍ឲ្យភ្ជាប់វ៉ាយហ្វាយ ដើម្បីចាប់ផ្ដើមទាញយកដោយស្វ័យប្រវត្តិ។<br/> <br/> ជំនួយ៖ អ្នកអាចទាញយក និងលុបវចនានុក្រមដោយចូលទៅ <b>ភាសា & ការបញ្ចូល</b> នៅក្នុងម៉ឺនុយ <b>ការកំណត់</b> សម្រាប់ឧបករណ៍ចល័ត។"</string> <string name="download_over_metered" msgid="1643065851159409546">"ទាញយកឥឡូវនេះ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> មេកាបៃ)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"ទាញយកតាមវ៉ាយហ្វាយ"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"វចនានុក្រមអាចប្រើបានសម្រាប់ <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"វចនានុក្រមអាចប្រើបានសម្រាប់ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"ចុច ដើម្បីពិនិត្យមើលឡើងវិញ និងទាញយក"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"ទាញយក៖ ការស្នើសម្រាប់ <xliff:g id="LANGUAGE">%1$s</xliff:g> នឹងបញ្ចប់ឆាប់ៗ។"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"ទាញយក៖ ការស្នើសម្រាប់ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> នឹងរួចរាល់ក្នុងពេលឆាប់ៗនេះ។"</string> <string name="version_text" msgid="2715354215568469385">"កំណែ <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"បន្ថែម"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"បន្ថែមទៅវចនានុក្រម"</string> diff --git a/java/res/values-ko/strings-config-important-notice.xml b/java/res/values-ko/strings-config-important-notice.xml new file mode 100644 index 000000000..47936efc3 --- /dev/null +++ b/java/res/values-ko/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"사용자의 대화 내용과 입력한 데이터를 통해 단어 추천의 정확도를 개선합니다."</string> +</resources> diff --git a/java/res/values-ko/strings-talkback-descriptions.xml b/java/res/values-ko/strings-talkback-descriptions.xml new file mode 100644 index 000000000..6142c6a3b --- /dev/null +++ b/java/res/values-ko/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"비밀번호 키를 음성으로 들으려면 헤드셋을 연결하세요."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"입력한 텍스트: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"입력한 텍스트 없음"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g>을(를) 누르면 <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>을(를) <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>(으)로 수정합니다."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g>을(를) 누르면 자동 수정됩니다."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"키 코드 %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift 키"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift 사용(사용하지 않으려면 탭하세요.)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock 사용(사용하지 않으려면 탭하세요.)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"삭제"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"기호"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"문자"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"숫자"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"설정"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"탭"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"스페이스바"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"음성 입력"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"그림 이모티콘"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"돌아가기"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"검색"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"글머리 기호"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"언어 전환"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"다음"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"이전"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift 사용"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock 사용"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift 사용 중지됨"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"기호 모드"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"문자 모드"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"다이얼 모드"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"전화 기호 모드"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"키보드 숨김"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> 키보드 표시"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"날짜"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"날짜 및 시간"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"이메일"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"문자 메시지"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"숫자"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"전화번호"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"텍스트"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"시간"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"최근"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"사람"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"물건"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"자연"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"장소"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"기호"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"이모티콘"</string> +</resources> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index ca10bdf52..4037abd02 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"시스템 기본값"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"주소록 이름 활용"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"추천 및 수정에 주소록의 이름 사용"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"맞춤 추천 검색어"</string> <string name="use_double_space_period" msgid="8781529969425082860">"더블스페이스 마침표"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"스페이스바를 두 번 탭하면 마침표와 공백 한 개가 삽입됩니다."</string> <string name="auto_cap" msgid="1719746674854628252">"자동 대문자화"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"제스처 흔적 표시"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"동적 플로팅 미리보기"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"제스처에 따라 추천 단어 보기"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"비밀번호 키를 음성으로 들으려면 헤드셋을 연결하세요."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"입력한 텍스트: %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"입력한 텍스트 없음"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g>을(를) 누르면 <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>을(를) <xliff:g id="CORRECTED">%3$s</xliff:g>(으)로 수정합니다."</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g>을(를) 누르면 자동 수정됩니다."</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"키 코드 %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"시프트 키"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 사용(사용하지 않으려면 탭하세요.)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock 사용(사용하지 않으려면 탭하세요.)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"삭제 키"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"기호"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"문자"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"숫자"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"설정"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"탭"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"스페이스"</string> - <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_search" msgid="1247236163755920808">"검색"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"점"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"언어 전환"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"다음"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"이전"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 사용"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock 사용"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 사용중지"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"기호 모드"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"문자 모드"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"다이얼 모드"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"전화 기호 모드"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"키보드 숨김"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> 키보드 표시"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"날짜"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"날짜 및 시간"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"이메일"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"문자 메시지"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"숫자"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"전화번호"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"텍스트"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"시간"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"구문 동작"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"동작 중에 스페이스바 쪽으로 움직여 공백 입력"</string> <string name="voice_input" msgid="3583258583521397548">"음성 입력 키"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"기본 키보드"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"기호 키보드"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"사용 안함"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"기본 키보드의 마이크"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"기호 키보드의 마이크"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"음성 입력이 사용 중지됨"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"사용 설정된 음성 입력 방법이 없습니다. 언어 및 입력 설정을 확인하세요."</string> <string name="configure_input_method" msgid="373356270290742459">"입력 방법 설정"</string> <string name="language_selection_title" msgid="1651299598555326750">"입력 언어"</string> <string name="send_feedback" msgid="1780431884109392046">"의견 보내기"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"영어(영국)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"영어(미국)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"스페인어(미국)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"영어(영국) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"영어(미국) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"스페인어(미국)(<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g>(일반)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"영어(영국)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"영어(미국)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"스페인어(미국)(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(번체)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(키릴어)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(라틴어)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"언어 없음(알파벳)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"알파벳(QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"알파벳(QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"외부 사전 파일 읽기"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"다운로드 폴더에 사전 파일이 없음"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"설치할 사전 파일 선택"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"이 파일을 <xliff:g id="LOCALE_NAME">%s</xliff:g>(으)로 설치하시겠습니까?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"이 파일을 <xliff:g id="LANGUAGE_NAME">%s</xliff:g>(으)로 설치하시겠습니까?"</string> <string name="error" msgid="8940763624668513648">"오류 발생"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"연락처 사전 덤프"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"개인 사전 덤프"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"사용자 기록 사전 덤프"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"맞춤설정 사전 덤프"</string> <string name="button_default" msgid="3988017840431881491">"기본값"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>에 오신 것을 환영합니다."</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"제스처 타이핑 사용"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"새로고침"</string> <string name="last_update" msgid="730467549913588780">"최종 업데이트"</string> <string name="message_updating" msgid="4457761393932375219">"업데이트를 확인하는 중"</string> - <string name="message_loading" msgid="8689096636874758814">"로드 중..."</string> + <string name="message_loading" msgid="5638680861387748936">"로드 중..."</string> <string name="main_dict_description" msgid="3072821352793492143">"기본 사전"</string> <string name="cancel" msgid="6830980399865683324">"취소"</string> + <string name="go_to_settings" msgid="3876892339342569259">"설정"</string> <string name="install_dict" msgid="180852772562189365">"설치"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"취소"</string> <string name="delete_dict" msgid="756853268088330054">"삭제"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"기기에서 선택한 언어로 사용할 수 있는 사전이 있습니다.<br/> <xliff:g id="LANGUAGE">%1$s</xliff:g> 사전을 <b>다운로드</b>하여 입력 환경을 개선해 보세요..<br/> <br/> 3G로 다운로드하는 경우 1-2분 정도 걸립니다. <b>무제한 데이터 요금제</b>가 아닌 경우 요금이 청구됩니다.<br/> 사용 중인 데이터 요금제를 잘 모르는 경우 Wi-Fi에 연결할 수 있는 곳을 찾아 자동 다운로드를 시작하는 것이 좋습니다.<br/> <br/> 도움말: 사전을 다운로드하거나 삭제하려면 <b>언어 및 키보드</b>로 이동하면 되며 이는 휴대기기의 <b>설정</b> 메뉴에 있습니다."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"휴대기기에서 선택한 언어로 사용할 수 있는 사전이 있습니다.<br/> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> 사전을 <b>다운로드</b>하여 입력 환경을 개선해 보세요.<br/> <br/> 3G로 다운로드하는 경우 1~2분 정도 걸립니다. <b>무제한 데이터 요금제</b>가 아닌 경우 요금이 청구될 수 있습니다.<br/> 사용 중인 데이터 요금제를 잘 모르는 경우 Wi-Fi에 연결할 수 있는 곳을 찾아 자동 다운로드를 시작하는 것이 좋습니다.<br/> <br/> 도움말: 사전을 다운로드하거나 삭제하려면 휴대기기의 <b>설정</b> 메뉴에 있는 <b>언어 및 입력</b>으로 이동하면 됩니다."</string> <string name="download_over_metered" msgid="1643065851159409546">"지금 다운로드(<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi를 통해 다운로드"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> 사전을 사용할 수 있습니다."</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> 사전을 사용할 수 있습니다."</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"검토하고 다운로드하려면 누르세요."</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"다운로드 중: <xliff:g id="LANGUAGE">%1$s</xliff:g>에 대한 추천항목이 곧 준비됩니다."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"다운로드 중: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>에 대한 추천항목이 곧 준비됩니다."</string> <string name="version_text" msgid="2715354215568469385">"버전 <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"추가"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"사전에 추가"</string> diff --git a/java/res/values-ky/strings-talkback-descriptions.xml b/java/res/values-ky/strings-talkback-descriptions.xml new file mode 100644 index 000000000..f218bfebe --- /dev/null +++ b/java/res/values-ky/strings-talkback-descriptions.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for spoken_use_headphones (896961781287283493) --> + <skip /> + <!-- no translation found for spoken_current_text_is (2485723011272583845) --> + <skip /> + <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> + <skip /> + <!-- no translation found for spoken_description_unknown (3197434010402179157) --> + <skip /> + <!-- no translation found for spoken_description_shift (244197883292549308) --> + <skip /> + <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> + <skip /> + <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> + <skip /> + <!-- no translation found for spoken_description_delete (8740376944276199801) --> + <skip /> + <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> + <skip /> + <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> + <skip /> + <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> + <skip /> + <!-- no translation found for spoken_description_settings (4627462689603838099) --> + <skip /> + <!-- no translation found for spoken_description_tab (2667716002663482248) --> + <skip /> + <!-- no translation found for spoken_description_space (2582521050049860859) --> + <skip /> + <!-- no translation found for spoken_description_mic (615536748882611950) --> + <skip /> + <!-- no translation found for spoken_description_smiley (2256309826200113918) --> + <skip /> + <!-- no translation found for spoken_description_return (8178083177238315647) --> + <skip /> + <!-- no translation found for spoken_description_dot (40711082435231673) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> + <skip /> + <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> + <skip /> + <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> + <skip /> +</resources> diff --git a/java/res/values-ky/strings.xml b/java/res/values-ky/strings.xml index e30c4b965..3758c2df1 100644 --- a/java/res/values-ky/strings.xml +++ b/java/res/values-ky/strings.xml @@ -110,76 +110,12 @@ <skip /> <!-- no translation found for bigram_prediction_summary (1747261921174300098) --> <skip /> - <!-- no translation found for added_word (8993883354622484372) --> - <skip /> <!-- no translation found for label_to_symbol_key (8516904117128967293) --> <skip /> <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) --> <skip /> - <!-- no translation found for spoken_use_headphones (896961781287283493) --> - <skip /> - <!-- no translation found for spoken_current_text_is (2485723011272583845) --> - <skip /> - <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> - <skip /> - <!-- no translation found for spoken_description_unknown (3197434010402179157) --> - <skip /> - <!-- no translation found for spoken_description_shift (244197883292549308) --> - <skip /> - <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> - <skip /> - <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> - <skip /> - <!-- no translation found for spoken_description_delete (8740376944276199801) --> - <skip /> - <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> - <skip /> - <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> - <skip /> - <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> - <skip /> - <!-- no translation found for spoken_description_settings (4627462689603838099) --> - <skip /> - <!-- no translation found for spoken_description_tab (2667716002663482248) --> - <skip /> - <!-- no translation found for spoken_description_space (2582521050049860859) --> - <skip /> - <!-- no translation found for spoken_description_mic (615536748882611950) --> - <skip /> - <!-- no translation found for spoken_description_smiley (2256309826200113918) --> - <skip /> - <!-- no translation found for spoken_description_return (8178083177238315647) --> - <skip /> - <!-- no translation found for spoken_description_dot (40711082435231673) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> - <skip /> - <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> - <skip /> - <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> - <skip /> <!-- 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) --> - <skip /> - <!-- no translation found for voice_input_modes_off (3745699748218082014) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_off (63875609591897607) --> - <skip /> <!-- no translation found for configure_input_method (373356270290742459) --> <skip /> <!-- no translation found for language_selection_title (1651299598555326750) --> diff --git a/java/res/values-land/config.xml b/java/res/values-land/config.xml index 7d93cc2ff..43ae068f2 100644 --- a/java/res/values-land/config.xml +++ b/java/res/values-land/config.xml @@ -18,6 +18,59 @@ */ --> +<!-- Configuration values for Small Phone Landscape. --> <resources> <bool name="config_use_fullscreen_mode">true</bool> + + <!-- Preferable keyboard height in absolute scale: 1.100in --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">176.0dp</dimen> + <fraction name="config_min_keyboard_height">45%p</fraction> + + <!-- key_height + key_bottom_gap = config_more_keys_keyboard_key_height --> + <dimen name="config_more_keys_keyboard_key_height">44.8dp</dimen> + <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> + <!-- config_more_keys_keyboard_key_height x 1.2 --> + <dimen name="config_more_keys_keyboard_slide_allowance">53.76dp</dimen> + + <fraction name="config_keyboard_top_padding_holo">2.727%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction> + <fraction name="config_key_vertical_gap_holo">5.368%p</fraction> + <fraction name="config_key_horizontal_gap_holo">1.020%p</fraction> + <!-- config_more_keys_keyboard_key_height x -0.5 --> + <dimen name="config_more_keys_keyboard_vertical_correction_holo">-22.4dp</dimen> + <dimen name="config_key_preview_offset_holo">1.6dp</dimen> + + <fraction name="config_key_preview_text_ratio">90%</fraction> + <fraction name="config_key_letter_ratio">65%</fraction> + <fraction name="config_key_large_letter_ratio">74%</fraction> + <fraction name="config_key_label_ratio">40%</fraction> + <fraction name="config_key_hint_letter_ratio">30%</fraction> + <fraction name="config_key_hint_label_ratio">52%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">40%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">40.000%</fraction> + <!-- left or right padding of label alignment --> + <dimen name="config_key_label_horizontal_padding">8dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">3.20%p</fraction> + <fraction name="config_key_letter_ratio_5row">78%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">48%</fraction> + + <dimen name="config_suggestions_strip_height">36dp</dimen> + <dimen name="config_more_suggestions_row_height">36dp</dimen> + <integer name="config_max_more_suggestions_row">2</integer> + <fraction name="config_min_more_suggestions_width">60%</fraction> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">23dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">54dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">23dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">15dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">10%p</fraction> + <fraction name="config_emoji_keyboard_row_height">50%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">54%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">20</integer> </resources> diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml deleted file mode 100644 index c97e68f11..000000000 --- a/java/res/values-land/dimens.xml +++ /dev/null @@ -1,83 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 1.100in --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">176.0dp</dimen> - <fraction name="minKeyboardHeight">45%p</fraction> - <!-- key_height + key_bottom_gap = popup_key_height --> - <dimen name="popup_key_height">44.8dp</dimen> - - <fraction name="keyboard_top_padding_gb">1.818%p</fraction> - <fraction name="keyboard_bottom_padding_gb">0.0%p</fraction> - <fraction name="key_bottom_gap_gb">5.941%p</fraction> - <fraction name="key_horizontal_gap_gb">0.997%p</fraction> - - <fraction name="keyboard_top_padding_holo">2.727%p</fraction> - <fraction name="keyboard_bottom_padding_holo">0.0%p</fraction> - <fraction name="key_bottom_gap_holo">5.368%p</fraction> - <fraction name="key_horizontal_gap_holo">1.020%p</fraction> - - <!-- left or right padding of label alignment --> - <dimen name="key_label_horizontal_padding">8dp</dimen> - - <fraction name="key_letter_ratio">65%</fraction> - <fraction name="key_large_letter_ratio">74%</fraction> - <fraction name="key_label_ratio">40%</fraction> - <fraction name="key_hint_letter_ratio">30%</fraction> - <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_gb">0.0dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">3.20%p</fraction> - <fraction name="key_letter_ratio_5row">78%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">48%</fraction> - - <dimen name="key_preview_offset_holo">1.6dp</dimen> - <!-- popup_key_height x -0.5 --> - <dimen name="more_keys_keyboard_vertical_correction_holo">-22.4dp</dimen> - - <dimen name="suggestions_strip_height">36dp</dimen> - <dimen name="more_suggestions_row_height">36dp</dimen> - <integer name="max_more_suggestions_row">2</integer> - <fraction name="min_more_suggestions_width">60%</fraction> - <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> - <!-- popup_key_height x 1.2 --> - <dimen name="more_keys_keyboard_slide_allowance">53.76dp</dimen> - <!-- popup_key_height x -1.0 --> - <dimen name="more_keys_keyboard_vertical_correction_gb">-44.8dp</dimen> - - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">23dp</dimen> - <dimen name="gesture_floating_preview_text_offset">54dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">23dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">15dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">10%p</fraction> - <fraction name="emoji_keyboard_row_height">50%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">54%p</fraction> - <integer name="emoji_keyboard_max_key_count">20</integer> - -</resources> diff --git a/java/res/values-land/keyboard-heights.xml b/java/res/values-land/keyboard-heights.xml index 670be3329..d57f96be3 100644 --- a/java/res/values-land/keyboard-heights.xml +++ b/java/res/values-land/keyboard-heights.xml @@ -33,7 +33,5 @@ <!-- Preferable keyboard height in absolute scale: 45.0mm --> <!-- Xoom --> <item>HARDWARE=stingray,265.4378</item> - <!-- Default value for unknown device: empty string --> - <item>,</item> </string-array> </resources> diff --git a/java/res/values-land/setup-dimens-small-phone-land.xml b/java/res/values-land/setup-dimens-small-phone-land.xml index 088e6562a..de93eee08 100644 --- a/java/res/values-land/setup-dimens-small-phone-land.xml +++ b/java/res/values-land/setup-dimens-small-phone-land.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">18sp</dimen> <dimen name="setup_step_bullet_text_size">18sp</dimen> <dimen name="setup_step_triangle_indicator_height">18dp</dimen> - <dimen name="setup_step_indicator_height">18dp</dimen> <dimen name="setup_step_title_text_size">18sp</dimen> <dimen name="setup_step_instruction_text_size">14sp</dimen> <dimen name="setup_step_action_text_size">16sp</dimen> diff --git a/java/res/values-lo-rLA/donottranslate.xml b/java/res/values-lo-rLA/donottranslate-config-spacing-and-punctuations.xml index a9893feec..a9893feec 100644 --- a/java/res/values-lo-rLA/donottranslate.xml +++ b/java/res/values-lo-rLA/donottranslate-config-spacing-and-punctuations.xml diff --git a/java/res/values-lo-rLA/strings-config-important-notice.xml b/java/res/values-lo-rLA/strings-config-important-notice.xml new file mode 100644 index 000000000..7880ad158 --- /dev/null +++ b/java/res/values-lo-rLA/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"ຮຽນຮູ້ຈາກການສື່ສານ ແລະຂໍ້ມູນທີ່ທ່ານເຄີຍພິມເພື່ອປັບປຸງຄຳແນະນຳ"</string> +</resources> diff --git a/java/res/values-lo-rLA/strings-talkback-descriptions.xml b/java/res/values-lo-rLA/strings-talkback-descriptions.xml new file mode 100644 index 000000000..681a21370 --- /dev/null +++ b/java/res/values-lo-rLA/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"ສຽບສາຍຫູຟັງ ເພື່ອຟັງສຽງລະຫັດຜ່ານທີ່ຈະຖືກເວົ້າອອກມາ."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"ຂໍ້ຄວາມປັດຈຸບັນແມ່ນ %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"ບໍ່ມີການໃສ່ຂໍ້ຄວາມ"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ແກ້ໄຂ <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ເປັນ <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ດຳເນີນການແກ້ໄຂອັດຕະໂນມັດ"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"ລະຫັດກະແຈ %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift ເປີດນຳໃຊ້ຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock ເປີດຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"ລຶບ"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"ສັນຍາລັກ"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"ໂຕອັກສອນ"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"ໂຕເລກ"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"ການຕັ້ງຄ່າ"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"ແຖບ"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"ຍະຫວ່າງ"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"ການປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"ອີໂມຈິ"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"ກັບຄືນ"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"ຊອກຫາ"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"ຈ້ຳ"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"ສະລັບພາສາ"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"ຕໍ່ໄປ"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"ກ່ອນໜ້ານີ້"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift ເປີດນຳໃຊ້ຢູ່"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock ເປີດນຳໃຊ້ຢູ່"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift ປິດນຳໃຊ້ຢູ່"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"ໂຫມດສັນຍາລັກ"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"ໂຫມດໂຕອັກສອນ"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"ໂຫມດໂທລະສັບ"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"ໂຫມດສັນຍາລັກໂທລະສັບ"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"ເຊື່ອງແປ້ນພິມໄວ້ແລ້ວ"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"ກຳລັງສະແດງແປ້ນພິມ <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ວັນທີ"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ວັນທີແລະເວລາ"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ອີເມວ"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ຂໍ້ຄວາມ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"ໂຕເລກ"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"ໂທລະສັບ"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"ຂໍ້ຄວາມ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ເວລາ"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"ຫາກໍໃຊ້"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"ຄົນ"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"ວັດຖຸ"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"ທຳມະຊາດ"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"ສະຖານທີ່"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"ສັນຍາລັກ"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"ອີໂມຕິຄອນ"</string> +</resources> diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml index a4dbc2de2..76fe5e042 100644 --- a/java/res/values-lo-rLA/strings.xml +++ b/java/res/values-lo-rLA/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"ແນະນຳລາຍຊື່ຜູ່ຕິດຕໍ່"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ໃຊ້ຊື່ຈາກລາຍຊື່ຜູ່ຕິດຕໍ່ສຳລັບການແນະນຳ ແລະ ການຊ່ວຍແກ້ຄຳ"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"ຄຳແນະນຳຕາມການນຳໃຊ້ຂອງທ່ານ"</string> <string name="use_double_space_period" msgid="8781529969425082860">"ຍະຫວ່າງສອງເທື່ອເພື່ອໃສ່ຈ້ຳເມັດ"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"ກົດທີ່ປຸ່ມຍະຫວ່າງສອງເທື່ອເພື່ອໃສ່ຈ້ຳເມັດແລ້ວຕາມດ້ວຍການຍະຫວ່າງ"</string> <string name="auto_cap" msgid="1719746674854628252">"ເຮັດໂຕພິມໃຫຍ່ອັດຕະໂນມັດ"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"ສະແດງຫາງຂອງ Gesture"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"ມີຄຳຕົວຢ່າງລອຍຂຶ້ນມາ"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ເບິ່ງຄຳທີ່ຖືກແນະນຳໃນເວລາທີ່ກຳລັງຊີ້"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ບັນທຶກແລ້ວ"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"ສຽບສາຍຫູຟັງເພື່ອຟັງລະຫັດຜ່ານ."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"ຂໍ້ຄວາມປະຈຸບັນແມ່ນ %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"ບໍ່ມີການໃສ່ຂໍ້ຄວາມ"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> ແກ້ໄຂ <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ເປັນ <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> ປະຕິບັດການແປງຄຳຜິດອັດຕະໂນມັດ"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"ລະຫັດກະແຈ %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ເປີດນຳໃຊ້ຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock ເປີດຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"ລຶບ"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"ສັນຍາລັກ"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"ໂຕອັກສອນ"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"ໂຕເລກ"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"ການຕັ້ງຄ່າ"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"ແທັບ"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"ຍະຫວ່າງ"</string> - <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_search" msgid="1247236163755920808">"ຊອກຫາ"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"ຈ້ຳ"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"ສະລັບພາສາ"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"ຕໍ່ໄປ"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"ກ່ອນໜ້າ"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ເປີດນຳໃຊ້ຢູ່"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ເປີດນຳໃຊ້ຢູ່"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift ປິດນຳໃຊ້ຢູ່"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"ໂຫມດສັນຍາລັກ"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"ໂຫມດໂຕອັກສອນ"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"ໂຫມດໂທລະສັບ"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"ໂຫມດສັນຍາລັກໂທລະສັບ"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"ແປ້ນພິມເຊື່ອງໄວ້"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"ກຳລັງສະແດງແປ້ນພິມ <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ວັນທີ"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ວັນທີແລະເວລາ"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ຂໍ້ຄວາມ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"ໂຕເລກ"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"ໂທລະສັບ"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"ຂໍ້ຄວາມ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ເວລາ"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"ການສະແດງທ່າທາງດ້ວຍປະໂຫຍກ"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ໃສ່ຍະຫວ່າງເຂົ້າໄປໃນຂະນະທີ່ສະແດງທ່າທາງ ໂດຍການເລື່ອນໄປທີ່ປຸ່ມຍະຫວ່າງ"</string> <string name="voice_input" msgid="3583258583521397548">"ປຸ່ມປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"ແປ້ນພິມຫຼັກ"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"ໃນແປ້ນພິມສັນຍາລັກ"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"ປິດ"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ໄມໃນແປ້ນພິມຫຼັກ"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"ໄມໃນແປ້ນພິມສັນຍາລັກ"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ການປ້ອນຂໍ້ມູນດ້ວຍສຽງປິດນຳໃຊ້ຢູ່"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ບໍ່ມີວິທີການປ້ອນສຽງເປີດນໍາໃຊ້. ໃຫ້ກວດເບິ່ງການຕັ້ງຄ່າໃນເມນູ ພາສາ & ການປ້ອນຂໍ້ມູນ."</string> <string name="configure_input_method" msgid="373356270290742459">"ຕັ້ງຄ່າຮູບແບບການປ້ອນຂໍ້ມູນ"</string> <string name="language_selection_title" msgid="1651299598555326750">"ພາສາການປ້ອນຂໍ້ມູນ"</string> <string name="send_feedback" msgid="1780431884109392046">"ສົ່ງຄຳຕິຊົມ"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"ອັງກິດ (ສະຫະລາດຊະອານາຈັກ)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"ອັງກິດ (ສະຫະລັດຯ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"ສະເປນ (ອາເມລິກາ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"ພາສາອັງກິດ (ອັງກິດ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"ອັງກິດ (ອາເມລິກາ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"ແອສປາໂຍນ (ສະຫະລັດ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (ດັ້ງເດີມ)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"ອັງກິດ (ສະຫະລາດຊະອານາຈັກ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"ອັງກິດ (ສະຫະລັດຯ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"ສະແປນນິດ (ສະຫະລັດຯ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ດັ້ງເດີມ)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ຊິຣິວລິກ)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ລາຕິນ)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"ບໍ່ມີພາສາ (ໂຕອັກສອນ)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"ໂຕອັກສອນ (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"ໂຕອັກສອນ (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"ອ່ານໄຟລ໌ວັດຈະນານຸກົມພາຍນອກ"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"ບໍ່ມີໄຟລ໌ວັດຈະນານຸກົມໃນໂຟນເດີຂອງການດາວໂຫລດ"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ເລືອກໄຟລ໌ວັດຈະນານຸກົມເພື່ອຕິດຕັ້ງ"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"ຕິດຕັ້ງໄຟລ໌ນີ້ສຳລັບ <xliff:g id="LOCALE_NAME">%s</xliff:g> ແທ້ບໍ່?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ຕິດຕັ້ງໄຟລ໌ນີ້ສຳລັບ <xliff:g id="LANGUAGE_NAME">%s</xliff:g> ແທ້ບໍ່??"</string> <string name="error" msgid="8940763624668513648">"ມີຂໍ້ຜິດພາດເກີດຂຶ້ນ"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ດຶງຂໍ້ມູນວັດຈະນານຸກົມລາຍຊື່ຜູ່ຕິດຕໍ່"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"ເທຂໍ້ມູນວັດຈະນານຸກົມສ່ວນໂຕ"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ເທຂໍ້ມູນວັດຈະນານຸກົມປະຫວັດຜູ່ໃຊ້"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"ເທຂໍ້ມູນວັດຈະນານຸກົມຄວາມເປັນໂຕຕົນ"</string> <string name="button_default" msgid="3988017840431881491">"ຄ່າເລີ່ມຕົ້ນ"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"ຍິນດີຕ້ອນຮັບສູ່ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"ດ້ວຍການພິມແບບ Gesture"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"ດຶງຂໍ້ມູນໃຫມ່"</string> <string name="last_update" msgid="730467549913588780">"ອັບເດດຫຼ້າສຸດ"</string> <string name="message_updating" msgid="4457761393932375219">"ກຳລັງກວດການອັບເດດ"</string> - <string name="message_loading" msgid="8689096636874758814">"ກຳລັງໂຫລດ..."</string> + <string name="message_loading" msgid="5638680861387748936">"ກຳລັງໂຫຼດ..."</string> <string name="main_dict_description" msgid="3072821352793492143">"ວັດຈະນານຸກົມຫຼັກ"</string> <string name="cancel" msgid="6830980399865683324">"ຍົກເລີກ"</string> + <string name="go_to_settings" msgid="3876892339342569259">"ການຕັ້ງຄ່າ"</string> <string name="install_dict" msgid="180852772562189365">"ຕິດຕັ້ງ"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"ຍົກເລີກ"</string> <string name="delete_dict" msgid="756853268088330054">"ລຶບ"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"ພາສາທີ່ທ່ານເລືອກໃຊ້ໃນອຸປະກອນຂອງທ່ານນັ້ນ ມີວັດຈະນານຸກົມໃຫ້ໃຊ້ພ້ອມ.<br/> ພວກເຮົາແນະນຳໃຫ້ <b>ດາວໂຫລດ</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> ວັດຈະນານຸກົມດັ່ງກ່າວ ເພື່ອເພີ່ມປະສົບການໃນການພິມຂອງທ່ານ.<br/> <br/> ການດາວໂຫລດອາດຈະໃຊ້ເວລາພຽງໜຶ່ງເຖິງສອງນາທີ ໂດຍການໃຊ້ 3G. ທ່ານອາດຈະເສຍຄ່າບໍລິການສຳລັບອິນເຕີເນັດ ຫາກທ່ານບໍ່ມີ <b>ການນຳໃຊ້ອິນເຕີເນັດແບບບໍ່ຈຳກັດ</b>.<br/> ຫາກທ່ານບໍ່ແນ່ໃຈວ່າຮູບແບບການໃຊ້ໃດທີ່ທ່ານມີຢູ່ ພວກເຮົາແນະນຳໃຫ້ຊອກຫາການເຊື່ອມຕໍ່ Wi-Fi ເພື່ອດາວໂຫລດມັນໂດຍອັດຕະໂນມັດ.<br/> <br/> ເຄັດລັບ: ທ່ານສາມາດດາວໂຫລດ ແລະ ລຶບວັດຈະນານຸກົມໄດ້ທີ່ <b>ພາສາ & ການປ້ອນຂໍ້ມູນ</b> ຢູ່ໃນເມນູ <b>ການຕັ້ງຄ່າ</b> ຂອງອຸປະກອນພົກພາຂອງທ່ານ."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ພາສາທີ່ເລືອກໃນອຸປະກອນມືຖືຂອງທ່ານັ້ນມີວັດຈະນານຸກົມທີ່ສາມາດໃຊ້ໄດ້.<br/> ພວກເຮົາຂໍແນະນຳໃຫ້ <b>ດາວໂຫລດ</b> ວັດຈະນານຸກົມ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ເພື່ອປັບປຸງປະສົບການໃນການພິມຂອງທ່ານ.<br/> <br/> ການດາວໂຫລດອາດໃຊ້ເວລາສອງສາມນາທີຜ່ານເຄືອຂ່າຍ 3G. ທ່ານອາດຖືກຮຽກເກັບຄ່າຂໍ້ມູນໄດ້ຫາກທ່ານບໍ່ໄດ້ໃຊ້ <b>ແພັກເກດຂໍ້ມູນແບບບໍ່ຈຳກັດ</b>.<br/> ຫາກທ່ານບໍ່ແນ່ໃຈວ່າທ່ານໃຊ້ແພັກເກດແບບໃດຢູ່ ພວກເຮົາຂໍແນະນຳໃຫ້ທ່ານເຊື່ອມຕໍ່ເຄືອຂ່າຍ Wi-Fi ໃດນຶ່ງແທນເພື່ອເລີ່ມຕົ້ນການດາວໂຫລດໂດຍອັດຕະໂນມັດ.<br/> <br/> ເຄັດລັບ: ທ່ານສາມາດດາວໂຫລດ ແລະລຶບວັດຈະນານຸກົມອອກໄດ້ໂດຍການໄປທີ່ <b>ພາສາ & ການປ້ອນຂໍ້ມູນ</b> ໃນເມນູ <b>ການຕັ້ງຄ່າ</b> ຂອງອຸປະກອນມືຖືຂອງທ່ານ."</string> <string name="download_over_metered" msgid="1643065851159409546">"ດາວໂຫລດດຽວນີ້ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"ດາວໂຫລດຜ່ານ Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"ວັດຈະນານຸກົມສາມາດໃຊ້ໄດ້ກັບ <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"ມີວັດຈະນານຸກົມທີ່ສາມາດໃຊ້ໄດ້ກັບ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"ກົດທີ່ກວດຄືນ ແລະ ດາວໂຫລດ"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"ກຳລັງດາວໂຫລດ: ການແນະນຳສຳລັບ <xliff:g id="LANGUAGE">%1$s</xliff:g> ແລະມັນຈະພ້ອມນຳໃຊ້ໄວໆນີ້"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"ກຳລັງດາວໂຫລດ: ການແນະນຳສຳລັບ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ຈະພ້ອມໃນໄວໆນີ້."</string> <string name="version_text" msgid="2715354215568469385">"ເວີຊັນ <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"ເພີ່ມ"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"ເພີ່ມໄປທີ່ວັດຈະນານຸກົມ"</string> diff --git a/java/res/values-lt/strings-config-important-notice.xml b/java/res/values-lt/strings-config-important-notice.xml new file mode 100644 index 000000000..93c66e0e3 --- /dev/null +++ b/java/res/values-lt/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Mokytis iš ryšių ir įvestų duomenų, siekiant pagerinti pasiūlymus"</string> +</resources> diff --git a/java/res/values-lt/strings-talkback-descriptions.xml b/java/res/values-lt/strings-talkback-descriptions.xml new file mode 100644 index 000000000..07119cb65 --- /dev/null +++ b/java/res/values-lt/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Prijunkite ausines, kad išgirstumėte sakomus slaptažodžio klavišus."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Dabartinis tekstas yra %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nėra įvesto teksto"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> pataiso <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> į <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> atlieka automatinį taisymą"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Klavišo kodas %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Klavišas „Shift“"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Klavišas „Shift“ įjungtas (palieskite, kad išjungtumėte)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Įjungtos didžiosios raidės (palieskite, kad išjungtumėte)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Ištrinti"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simbolių klavišas"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Raidžių klavišas"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Skaičių klavišas"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Nustatymai"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabuliavimo klavišas"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Tarpo klavišas"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Balso įvestis"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Jaustukai"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Grįžti"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Paieška"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Taškas"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Keisti kalbą"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Kitas"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Ankstesnis"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Klavišas „Shift“ įgalintas"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Didžiųjų raidžių klavišas įgalintas"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Klavišas „Shift“ išjungtas"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Simbolių režimas"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Raidžių režimas"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefonų numerių režimas"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefonų numerių simbolių režimas"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klaviatūra paslėpta"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Klaviatūra rodoma <xliff:g id="KEYBOARD_MODE">%s</xliff:g> režimu"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datos"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datos ir laiko"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"el. pašto"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"susirašinėjimo pranešimais"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"skaičių"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefonų numerių"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teksto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"laiko"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Naujausi"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Žmonės"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objektai"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Gamta"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Vietos"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboliai"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Jaustukai"</string> +</resources> diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml index 1f943944c..c049a165e 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Sist. numat. nustat."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Siūlyti kontaktų vardus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Siūlant ir taisant naudoti vardus iš „Kontaktų“"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Suasmeninti pasiūlymai"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Tšk. ir tarp. pal. dukart"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dukart palietus tarpo klavišą įterpiamas taškas ir tarpas."</string> <string name="auto_cap" msgid="1719746674854628252">"Automatinis didžiųjų raidžių rašymas"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Rodyti gestų kelią"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinaminė slankioji peržiūra"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Gestikuliuojant peržiūrėti siūlomą žodį"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Prijunkite ausines, kad išgirstumėte sakomus slaptažodžio klavišus."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Dabartinis tekstas yra %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nėra įvesto teksto"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> pataiso „<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>“ į „<xliff:g id="CORRECTED">%3$s</xliff:g>“"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> atlieka automatinį taisymą"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Klavišo kodas %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Antrojo lygio klavišas"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Įjungtas antrasis lygis (palieskite, kad išjungtumėte)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Įjungtos didžiosios raidės (palieskite, kad išjungtumėte)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Ištrinti"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboliai"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Raidės"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Skaičiai"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Nustatymai"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Skirtukas"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Tarpas"</string> - <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_search" msgid="1247236163755920808">"Ieškoti"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Taškas"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Keisti kalbą"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Kitas"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Ankstesnis"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Įgalintas antrasis lygis"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Įgalintos didžiosios raidės"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Antrasis lygis išjungtas"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Simbolių režimas"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Raidžių režimas"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefono režimas"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefono simbolių režimas"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klaviatūra paslėpta"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Klaviatūra rodoma <xliff:g id="MODE">%s</xliff:g> režimu"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datos"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datos ir laiko"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"el. pašto"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"susirašinėjimo pranešimais"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"skaičių"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefonų numerių"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teksto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"laiko"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frazės gestas"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Atlikdami gestus įveskite tarpus perbraukę tarpo klavišą"</string> <string name="voice_input" msgid="3583258583521397548">"Įvesties balsu klavišas"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pagr. klaviatūroje"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simbolių klaviatūr."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Išjungta"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrof. pagr. klav."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrof. simb. klav."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Balso įv. neleidž."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nėra jokių įgalintų įvesties balsu metodų. Patikrinkite kalbos ir įvesties nustatymus."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigūruoti įvesties metodus"</string> <string name="language_selection_title" msgid="1651299598555326750">"Įvesties kalbos"</string> <string name="send_feedback" msgid="1780431884109392046">"Siųsti atsiliepimą"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Anglų k. (JK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglų k. (JAV)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Ispanų k. (JAV)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Angliška (JK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Angliška (JAV) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Ispanų k. (JAV) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicinė)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Anglų (JK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Anglų (JAV) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Ispanų (JAV) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicinė)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kirilica)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (lotynų)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Kalbos nėra (abėcėlė)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Abėcėlė (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Abėcėlė (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Skaityti išorinį žodyno failą"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Atsisiuntimų aplanke nėra žodyno failų"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Pasirinkite diegiamą žodyno failą"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Ar tikrai įdiegti šį failą <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Ar tikrai įdiegti šį failą <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Įvyko klaida"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Sudaryti kontaktų žodyną"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Iškelti asmeninį žodyną"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Iškelti naudotojo istorijos žodyną"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Iškelti suasmeninimo žodyną"</string> <string name="button_default" msgid="3988017840431881491">"Numatytieji"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Sveiki! Tai „<xliff:g id="APPLICATION_NAME">%s</xliff:g>“"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"naudojant įvestį gestais"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Atnaujinti"</string> <string name="last_update" msgid="730467549913588780">"Paskutinį kartą atnaujinta"</string> <string name="message_updating" msgid="4457761393932375219">"Ieškoma naujinių"</string> - <string name="message_loading" msgid="8689096636874758814">"Įkeliama..."</string> + <string name="message_loading" msgid="5638680861387748936">"Įkeliama…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Pagrindinis žodynas"</string> <string name="cancel" msgid="6830980399865683324">"Atšaukti"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Nustatymai"</string> <string name="install_dict" msgid="180852772562189365">"Įdiegti"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Atšaukti"</string> <string name="delete_dict" msgid="756853268088330054">"Ištrinti"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Galimas mobiliajame įrenginyje pasirinktos kalbos žodynas.<br/> Rekomenduojame <b>atsisiųsti</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> žodyną, kad būtų patogiau įvesti tekstą.<br/> <br/> Atsisiuntimas per 3G turėtų trukti 1–2 min. Jei neturite <b>neribotų duomenų plano</b>, galite būti apmokestinti.<br/> Jei nežinote, kokį planą turite, rekomenduojame rasti „Wi-Fi“ ryšį, kad atsisiuntimas prasidėtų automatiškai.<br/> <br/> Patarimas: galite atsisiųsti ir pašalinti žodynus mobiliojo įrenginio meniu <b>Nustatymai</b> skiltyje <b>Kalba ir įvestis</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Galimas jūsų mobiliajame įrenginyje pasirinktos kalbos žodynas.<br/> Rekomenduojame <b>atsisiųsti</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> žodyną, kad patobulintumėte teksto įvedimą.<br/> <br/> Naudojant 3G ryšį atsisiuntimas užtruks vieną ar dvi minutes. Jei naudojate ne <b>neribotų duomenų planą</b>, gali būti taikomi mokesčiai.<br/> Jei nesate tikri, kurį duomenų planą naudojate, rekomenduojame rasti „Wi-Fi“ ryšį, kad atsisiuntimas būtų pradėtas automatiškai.<br/> <br/> Patarimas: žodynus galite atsisiųsti ir pašalinti apsilankę mobiliojo įrenginio skiltyje <b>Kalba ir įvestis</b>, esančioje meniu <b>Nustatymai</b>."</string> <string name="download_over_metered" msgid="1643065851159409546">"Atsisiųsti dabar (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Atsisiųsti per „Wi-Fi“"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Galimas <xliff:g id="LANGUAGE">%1$s</xliff:g> žodynas"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Galimas <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> žodynas"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Paspauskite, kad peržiūrėtumėte ir atsisiųstumėte"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Atsisiunčiama. Netrukus bus galimi <xliff:g id="LANGUAGE">%1$s</xliff:g> pasiūlymai."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Atsisiunčiama. Netrukus bus galimi <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> pasiūlymai."</string> <string name="version_text" msgid="2715354215568469385">"<xliff:g id="VERSION_NUMBER">%1$s</xliff:g> versija"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Pridėti"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Pridėti prie žodyno"</string> diff --git a/java/res/values-lv/strings-config-important-notice.xml b/java/res/values-lv/strings-config-important-notice.xml new file mode 100644 index 000000000..15dc4b3a1 --- /dev/null +++ b/java/res/values-lv/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Izmantojiet saziņu un ievadītos datus, lai uzlabotu ieteikumus."</string> +</resources> diff --git a/java/res/values-lv/strings-talkback-descriptions.xml b/java/res/values-lv/strings-talkback-descriptions.xml new file mode 100644 index 000000000..eb32e9dcc --- /dev/null +++ b/java/res/values-lv/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Pievienojiet austiņas, lai dzirdētu paroles rakstzīmes."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Pašreizējais teksts ir %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Teksts nav ievadīts"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Nospiežot taustiņu <xliff:g id="KEY_NAME">%1$s</xliff:g>, “<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>” tiek labots uz “<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>”."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Taustiņam <xliff:g id="KEY_NAME">%1$s</xliff:g> ir automātiskas labošanas funkcija."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Taustiņu kods %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Pārslēgšanas taustiņš"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Pārslēgšanas režīms ir iespējots (pieskarieties, lai atspējotu)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Burtslēgs ir iespējots (pieskarieties, lai atspējotu)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Dzēšanas taustiņš"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simboli"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Burti"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Cipari"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Iestatījumi"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabulēšanas taustiņš"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Atstarpēšanas taustiņš"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Balss ievade"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emocijzīmes"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Ievadīšanas taustiņš"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Meklēšanas taustiņš"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punkta aizzīme"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Valodas mainīšana"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Tālāk"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Atpakaļ"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Pārslēgšanas režīms ir iespējots"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Burtslēgs ir iespējots"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Pārslēgšanas režīms ir atspējots"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Simbolu režīms"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Burtu režīms"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Tālruņa režīms"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Tālruņa simbolu režīms"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastatūra ir paslēpta"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Tiek rādīts tastatūras režīms: <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datums"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datums un laiks"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-pasts"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ziņojumapmaiņa"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"cipari"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"tālrunis"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teksts"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"laiks"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Pēdējie"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Cilvēki"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objekti"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Daba"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Vietas"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboli"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emocijzīmes"</string> +</resources> diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml index 8ea24edb7..901c3486f 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Sistēmas noklusējums"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Ieteikt kontaktp. vārdus"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Izmantot kontaktpersonu vārdus kā ieteikumus un labojumus"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalizēti ieteikumi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubultpiesk. = punkts"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Divreiz pieskaroties atst. taustiņam, ievada punktu un atstarpi."</string> <string name="auto_cap" msgid="1719746674854628252">"Automātiska lielo burtu lietošana"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Rādīt žesta pēdas"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamisk. peldošais priekšsk."</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Skatiet ieteikto vārdu, veicot žestu."</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Pievienojiet austiņas, lai dzirdētu paroles rakstzīmes."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Pašreizējais teksts ir %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nav ievadīts teksts"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Nospiežot taustiņu <xliff:g id="KEY">%1$s</xliff:g>, “<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>” tiek labots uz “<xliff:g id="CORRECTED">%3$s</xliff:g>”."</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Taustiņam <xliff:g id="KEY">%1$s</xliff:g> ir automātiskas labošanas funkcija."</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Taustiņu kods %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Pārslēgšanas taustiņš"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Pārslēgšanas taustiņš iespējots (pieskarieties, lai atspējotu)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Burtslēgs iespējots (pieskarieties, lai atspējotu)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Dzēšanas taustiņš"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboli"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Burti"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Skaitļi"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Iestatījumi"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulēšanas taustiņš"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Atstarpes taustiņš"</string> - <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_search" msgid="1247236163755920808">"Meklēt"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punkts"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Mainīt valodu"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Nākamā"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Iepriekšējā"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Pārslēgšanas režīms iespējots"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Burtslēgs iespējots"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Pārslēgšanas režīms atspējots"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Simbolu režīms"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Burtu režīms"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Tālruņa režīms"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Tālruņa simbolu režīms"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastatūra ir paslēpta"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Tiek rādīts tastatūras režīms <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datums"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datums un laiks"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-pasts"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ziņojumapmaiņa"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"cipari"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"tālrunis"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teksts"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"laiks"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frāzes žests"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Lai ievietotu atstarpi, velciet uz atstarpes taustiņu."</string> <string name="voice_input" msgid="3583258583521397548">"Balss ievades atslēga"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Uz galv. tastatūras"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Uz simbolu tastat."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Izslēgts"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr.uz galv.tastat."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr.uz simb.tastat."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Balss iev. atspējota"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nav iespējota neviena balss ievades metode. Pārbaudiet valodas un ievades iestatījumus."</string> <string name="configure_input_method" msgid="373356270290742459">"Ievades metožu konfigurēšana"</string> <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string> <string name="send_feedback" msgid="1780431884109392046">"Sūtīt atsauksmes"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"Spāņu (ASV)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Angļu (Lielbritānija) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Angļu (ASV) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spāņu (ASV) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicionālā)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Angļu (Lielbritānija) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Angļu (ASV) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spāņu (ASV) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionālā)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kirilica)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latīņu)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nav valodas (alfabēts)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabēts (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabēts (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ārējās vārdnīcas faila nolasīšana"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Mapē Lejupielādes nav neviena vārdnīcas faila."</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Instalējamā vārdnīcas faila atlasīšana"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vai instalēt šo failu šādai valodai: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Vai tiešām instalēt šo failu šādai valodai: <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Radās kļūda"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Kontaktpersonu vārdnīcas izmete"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Personiskās vārdnīcas izmete"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Lietotāja vēstures vārdnīcas izmete"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Personalizētās vārdnīcas izmete"</string> <string name="button_default" msgid="3988017840431881491">"Noklusējums"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Laipni lūdzam pakalpojumā <xliff:g id="APPLICATION_NAME">%s</xliff:g>,"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"kurā varat izmantot ievadi ar žestiem"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Atsvaidzināt"</string> <string name="last_update" msgid="730467549913588780">"Pēdējo reizi atjaunināts"</string> <string name="message_updating" msgid="4457761393932375219">"Notiek pārbaude, vai ir pieejami atjauninājumi."</string> - <string name="message_loading" msgid="8689096636874758814">"Notiek ielāde..."</string> + <string name="message_loading" msgid="5638680861387748936">"Notiek ielāde…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Galvenā vārdnīca"</string> <string name="cancel" msgid="6830980399865683324">"Atcelt"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Iestatījumi"</string> <string name="install_dict" msgid="180852772562189365">"Instalēt"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Atcelt"</string> <string name="delete_dict" msgid="756853268088330054">"Dzēst"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Mobilajā ierīcē atlasītajai valodai ir pieejama vārdnīca.<br/>Ieteicams <b>lejupielādēt</b> vārdnīcu (<xliff:g id="LANGUAGE">%1$s</xliff:g>), lai uzlabotu rakstīšanas iespējas.<br/><br/>Lejupielāde, izmantojot 3G tīklu, ilgs dažas minūtes. Ja nelietojat <b>neierobežotu datu plānu</b>, var tikt piemērota maksa.<br/>Ja nezināt, kādu datu plānu lietojat, ieteicams atrast Wi-Fi savienojumu, lai automātiski sāktu lejupielādi.<br/><br/>Padoms. Vārdnīcas var lejupielādēt un noņemt mobilās ierīces izvēlnes <b>Iestatījumi</b> sadaļā <b>Valoda un ievade</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobilajā ierīcē atlasītajai valodai ir pieejama vārdnīca.<br/> Ieteicams <b>lejupielādēt</b> šo vārdnīcu (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>), lai uzlabotu rakstīšanas iespējas.<br/> <br/> Lejupielāde, izmantojot 3G tīklu, ilgs tikai dažas minūtes. Ja nelietojat <b>neierobežotu datu plānu</b>, var tikt piemērota maksa.<br/> Ja nezināt, kādu datu plānu lietojat, ieteicams atrast Wi-Fi savienojumu, lai automātiski sāktu lejupielādi.<br/> <br/> Padoms: vārdnīcas var lejupielādēt un noņemt sadaļā <b>Valoda un ievade</b>, kas atrodas mobilās ierīces izvēlnē <b>Iestatījumi</b>."</string> <string name="download_over_metered" msgid="1643065851159409546">"Lejupielādēt tūlīt (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Lejupielādēt, izmantojot Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Ir pieejama vārdnīca šādai valodai: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Ir pieejama vārdnīca šādai valodai: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Nospiediet, lai pārskatītu un lejupielādētu"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Notiek lejupielāde. Drīz būs pieejami ieteikumi šādai valodai: <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Notiek lejupielāde. Drīz būs pieejami ieteikumi šādai valodai: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Versija <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Pievienot"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Pievienot vārdnīcai"</string> diff --git a/java/res/values-mk/strings-talkback-descriptions.xml b/java/res/values-mk/strings-talkback-descriptions.xml new file mode 100644 index 000000000..05b816ab7 --- /dev/null +++ b/java/res/values-mk/strings-talkback-descriptions.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for spoken_use_headphones (896961781287283493) --> + <skip /> + <!-- no translation found for spoken_current_text_is (2485723011272583845) --> + <skip /> + <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> + <skip /> + <!-- no translation found for spoken_auto_correct (8005997889020109763) --> + <skip /> + <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> + <skip /> + <!-- no translation found for spoken_description_unknown (3197434010402179157) --> + <skip /> + <!-- no translation found for spoken_description_shift (244197883292549308) --> + <skip /> + <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> + <skip /> + <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> + <skip /> + <!-- no translation found for spoken_description_delete (8740376944276199801) --> + <skip /> + <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> + <skip /> + <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> + <skip /> + <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> + <skip /> + <!-- no translation found for spoken_description_settings (4627462689603838099) --> + <skip /> + <!-- no translation found for spoken_description_tab (2667716002663482248) --> + <skip /> + <!-- no translation found for spoken_description_space (2582521050049860859) --> + <skip /> + <!-- no translation found for spoken_description_mic (615536748882611950) --> + <skip /> + <!-- no translation found for spoken_description_smiley (2256309826200113918) --> + <skip /> + <!-- no translation found for spoken_description_return (8178083177238315647) --> + <skip /> + <!-- no translation found for spoken_description_search (1247236163755920808) --> + <skip /> + <!-- no translation found for spoken_description_dot (40711082435231673) --> + <skip /> + <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> + <skip /> + <!-- no translation found for spoken_description_action_next (8636078276664150324) --> + <skip /> + <!-- no translation found for spoken_description_action_previous (800872415009336208) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> + <skip /> + <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> + <skip /> + <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> + <skip /> + <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> + <skip /> + <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> + <skip /> + <!-- no translation found for keyboard_mode_date (3137520166817128102) --> + <skip /> + <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> + <skip /> + <!-- no translation found for keyboard_mode_email (6216248078128294262) --> + <skip /> + <!-- no translation found for keyboard_mode_im (1137405089766557048) --> + <skip /> + <!-- no translation found for keyboard_mode_number (7991623440699957069) --> + <skip /> + <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> + <skip /> + <!-- no translation found for keyboard_mode_text (6479436687899701619) --> + <skip /> + <!-- no translation found for keyboard_mode_time (4381856885582143277) --> + <skip /> + <!-- no translation found for keyboard_mode_url (1519819835514911218) --> + <skip /> +</resources> diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml index 6f685d395..1588534c9 100644 --- a/java/res/values-mk/strings.xml +++ b/java/res/values-mk/strings.xml @@ -126,106 +126,8 @@ <skip /> <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) --> <skip /> - <!-- no translation found for added_word (8993883354622484372) --> - <skip /> - <!-- no translation found for spoken_use_headphones (896961781287283493) --> - <skip /> - <!-- no translation found for spoken_current_text_is (2485723011272583845) --> - <skip /> - <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> - <skip /> - <!-- no translation found for spoken_auto_correct (8005997889020109763) --> - <skip /> - <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> - <skip /> - <!-- no translation found for spoken_description_unknown (3197434010402179157) --> - <skip /> - <!-- no translation found for spoken_description_shift (244197883292549308) --> - <skip /> - <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> - <skip /> - <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> - <skip /> - <!-- no translation found for spoken_description_delete (8740376944276199801) --> - <skip /> - <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> - <skip /> - <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> - <skip /> - <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> - <skip /> - <!-- no translation found for spoken_description_settings (4627462689603838099) --> - <skip /> - <!-- no translation found for spoken_description_tab (2667716002663482248) --> - <skip /> - <!-- no translation found for spoken_description_space (2582521050049860859) --> - <skip /> - <!-- no translation found for spoken_description_mic (615536748882611950) --> - <skip /> - <!-- no translation found for spoken_description_smiley (2256309826200113918) --> - <skip /> - <!-- no translation found for spoken_description_return (8178083177238315647) --> - <skip /> - <!-- no translation found for spoken_description_search (1247236163755920808) --> - <skip /> - <!-- no translation found for spoken_description_dot (40711082435231673) --> - <skip /> - <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> - <skip /> - <!-- no translation found for spoken_description_action_next (8636078276664150324) --> - <skip /> - <!-- no translation found for spoken_description_action_previous (800872415009336208) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> - <skip /> - <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> - <skip /> - <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> - <skip /> - <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> - <skip /> - <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> - <skip /> - <!-- no translation found for keyboard_mode_date (3137520166817128102) --> - <skip /> - <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> - <skip /> - <!-- no translation found for keyboard_mode_email (6216248078128294262) --> - <skip /> - <!-- no translation found for keyboard_mode_im (1137405089766557048) --> - <skip /> - <!-- no translation found for keyboard_mode_number (7991623440699957069) --> - <skip /> - <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> - <skip /> - <!-- no translation found for keyboard_mode_text (6479436687899701619) --> - <skip /> - <!-- no translation found for keyboard_mode_time (4381856885582143277) --> - <skip /> - <!-- no translation found for keyboard_mode_url (1519819835514911218) --> - <skip /> <!-- 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) --> - <skip /> - <!-- no translation found for voice_input_modes_off (3745699748218082014) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_off (63875609591897607) --> - <skip /> <!-- no translation found for configure_input_method (373356270290742459) --> <skip /> <!-- no translation found for language_selection_title (1651299598555326750) --> diff --git a/java/res/values-mn-rMN/strings-config-important-notice.xml b/java/res/values-mn-rMN/strings-config-important-notice.xml new file mode 100644 index 000000000..386d2e789 --- /dev/null +++ b/java/res/values-mn-rMN/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Зөвлөмжүүдийг сайжруулахын тулд таны харилцсан, бичсэн зүйлсээс суралцана"</string> +</resources> diff --git a/java/res/values-mn-rMN/strings-talkback-descriptions.xml b/java/res/values-mn-rMN/strings-talkback-descriptions.xml new file mode 100644 index 000000000..7eb316775 --- /dev/null +++ b/java/res/values-mn-rMN/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Нууц үгний дуудлагыг сонсох бол чихэвчийг залгана уу."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Одоогийн текст %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Текст оруулаагүй"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> нь <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-г <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> руу залруулна"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> авто-залруулалт хийдэг"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Товчийн код %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Шифт"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Сэлгэхийг идэвхжүүлсэн (товшиж идэвхгүйжүүлнэ үү)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Томоор бичихийг асаасан (товшиж идэвхгүйжүүлнэ үү)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Устгах"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Симбол"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Үсэгнүүд"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Тоонууд"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Тохиргоо"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Таб"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Хоосон зай"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Дуугаар оруулах"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Эможи"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Оруулах"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Хайх"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Цэг"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Хэл солих"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Дараах"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Өмнөх"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Сэлгэхийг идэвхжүүлсэн"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Томоор бичихийг идэвхжүүлсэн"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Сэлгэхийг идэвхжүүлээгүй"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Симбол төлөв"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Үсэгнүүд төлөв"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Утасны төлөв"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Утасны символ төлөв"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Гарыг нуусан"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> гар харуулж байна"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"огноо"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"огноо болон цаг"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"имэйл"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"зурвас"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"тоо"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"утас"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"зурвас"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"цаг"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Саяхны"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Хүмүүс"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Объект"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Байгалийн"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Газар"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Симбол"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Эмотикон"</string> +</resources> diff --git a/java/res/values-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml index d4175899f..4c64b3354 100644 --- a/java/res/values-mn-rMN/strings.xml +++ b/java/res/values-mn-rMN/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Системийн үндсэн утга"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Харилцагчдын нэрс санал болгох"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Санал болгох, залруулахда Харилцагчдын нэрсээс ашиглах"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Хувийн тохиргоотой зөвлөмжүүд"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Давхар зайтай цэг"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Ардаа зайтай цэг оруулахын тулд Зай авах дээр давхар товшино уу"</string> <string name="auto_cap" msgid="1719746674854628252">"Автоматаар томруулах"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Зангасан мөрийг харуулах"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамик хөвөгчөөр урьдчилан харах"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Зангах явцад санал болгож буй үгийг харах"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Хадгалагдсан"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Нууц үгний товчнуудыг чангаар уншихыг сонсохын тулд чихэвчээ залгана уу."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Одоогийн текст %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Текст оруулаагүй"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>-г <xliff:g id="CORRECTED">%3$s</xliff:g> руу залруулна"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> автоматаар залруулна"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Товчийн код %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Сэлгэх"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Сэлгэхийг идэвхжүүлсэн (товшиж идэвхгүйжүүлнэ үү)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Томоор бичихийг асаасан (товшиж идэвхгүйжүүлнэ үү)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Устгах"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Симбол"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Үсэгнүүд"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Тоонууд"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Тохиргоо"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Таб"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Хоосон зай"</string> - <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_search" msgid="1247236163755920808">"Хайх"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Цэг"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Хэл солих"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Дараах"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Өмнөх"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Сэлгэхийг идэвхжүүлсэн"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Томоор бичихийг идэвхжүүлсэн"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Сэлгэхийг идэвхжүүлээгүй"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Симбол төлөв"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Үсэгнүүд төлөв"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Утасны төлөв"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Утасны символ төлөв"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Гарыг нуусан"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> гарыг харуулж байна"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"огноо"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"огноо болон цаг"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"и"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"зурвас"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"дугаар"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"утас"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"текст"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"цаг"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Хэллэгийн зангалт"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Зангалтын явцад зай авах товчин дээр гулсуулах замаар зай оруулах"</string> <string name="voice_input" msgid="3583258583521397548">"Дуун оруулгын товч"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Үндсэн гар дээр"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Симбол гар дээр"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Идэвхгүй"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Мик үндсэн гар дээр"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Мик симбол гар дээр"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Дуун оруулах идэвхгүйжсэн"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ямар ч дуу оруулах хэрэглүүр идэвхжээгүй байна. Хэл болон оруулалтын тохиргоог шалгана уу."</string> <string name="configure_input_method" msgid="373356270290742459">"Оруулах аргуудын тохиргоо"</string> <string name="language_selection_title" msgid="1651299598555326750">"Оруулах хэл"</string> <string name="send_feedback" msgid="1780431884109392046">"Санал хүсэлт илгээх"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Англи (ИБ)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Англи (АНУ)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Испани (АНУ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Англи (ИБ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Англи (АНУ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Испани (АНУ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Уламжлалт)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Англи (ИБ) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Англи (АНУ) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Испани (АНУ-ын) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (уламжлалт)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Кирилл)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Латин)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Хэл байхгүй (Цагаан толгой)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Цагаан толгой (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Цагаан толгой (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Толь бичгийн гадны файлыг унших"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Татаж авсан фолдерт толь бичгийн файл байхгүй байна"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Суулгах толь бичгийн файлыг сонгоно уу"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"<xliff:g id="LOCALE_NAME">%s</xliff:g>-д зориулсан энэ файлыг үнэхээр суулгах уу?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>-д зориулсан энэ файлыг үнэхээр суулгах уу?"</string> <string name="error" msgid="8940763624668513648">"Алдаа гарсан"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Харилцагчдын толь бичгийг жагсаах"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Хувийн толь бичгийг хаях"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Хэрэглэгчийн түүхийн толь бичгийг хаях"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Хувийн тохиргоотой толь бичгийг хаях"</string> <string name="button_default" msgid="3988017840431881491">"Үндсэн"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Та <xliff:g id="APPLICATION_NAME">%s</xliff:g>-д тавтай морилно уу"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"Зангаагаар бичихээр"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Дахин шинэчлэх"</string> <string name="last_update" msgid="730467549913588780">"Сүүлд шинэчлэгдсэн"</string> <string name="message_updating" msgid="4457761393932375219">"Шинэчлэлтийг шалгаж байна"</string> - <string name="message_loading" msgid="8689096636874758814">"Ачаалж байна..."</string> + <string name="message_loading" msgid="5638680861387748936">"Ачаалж байна..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Үндсэн толь бичиг"</string> <string name="cancel" msgid="6830980399865683324">"Цуцлах"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Тохиргоо"</string> <string name="install_dict" msgid="180852772562189365">"Суулгах"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Цуцлах"</string> <string name="delete_dict" msgid="756853268088330054">"Устгах"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Таны мобайль төхөөрөмж дээр сонгосон хэлэнд толь бичиг байна.<br/> Тус <xliff:g id="LANGUAGE">%1$s</xliff:g> толь бичгийг <b>татаж аван</b> зөв бичилтээ сайжруулахыг бид зөвлөж байна.<br/> <br/> Татаж авахад 3G сүлжээгээр нэг хоёр минут болно. Танд <b>хязгааргүй дата эрх</b> байхгүй бол нэмэлт төлбөр гарч болно.<br/> Та дата эрхийнхээ талаар сайн мэдэхгүй байгаа бол Wi-Fi холболттой газар очин автоматаар татаж авахыг зөвлөж байна.<br/> <br/> Зөвлөмж: Та өөрийн мобайль төхөөрөмжийн <b>Тохиргоо</b> цэсний <b>Хэл & оруулах</b> руу очиж толь бичиг татаж авах буюу устгаж болно."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Таны мобайл төхөөрөмж дээр сонгосон хэлний толь бичиг байна. <br/> Бид танд <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> хэлний толь бичиг <b> татаж аван </ б> бичихэд хялбар болгохыг зөвлөж байна. <br/> <br/> Татаж авахад 3G дээр нэг, хоёр минут болж магадгүй. Хэрэв та <b> хязгааргүй дата ашиглах эрхтэй </ б> биш бол нэмэлт төлбөр гарч болно. Хэрэв та өөрийн дата ашиглалтын эрхийг сайн мэдэхгүй байгаа бол Wi-Fi холболт ашиглан автоматаар татан авахыг эхлүүлэхийг зөвлөж байна.<br/> <br/> <br/> Зөвлөмж: Та өөрийн мобайл төхөөрөмжийн <b> тохиргоо </ б> цэсэнд </ б> Хэл & оролт <b> руу очиж толь бичиг татаж авах, устгах боломжтой."</string> <string name="download_over_metered" msgid="1643065851159409546">"Одоо татах (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi-р татаж авах"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> хэлний толь бичигтэй"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> хэлний толь ашиглах боломжтой"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Шалгах болон татаж авахын тулд дарна уу"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Татаж байна: <xliff:g id="LANGUAGE">%1$s</xliff:g> хэлний санал болгох үгс удахгүй бэлэн болно."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-д зориулсан татан авалтын санал болголтууд удахгүй бэлэн болно."</string> <string name="version_text" msgid="2715354215568469385">"Хувилбар <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Нэмэх"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Толь бичигт нэмэх"</string> diff --git a/java/res/values-ms-rMY/strings-config-important-notice.xml b/java/res/values-ms-rMY/strings-config-important-notice.xml new file mode 100644 index 000000000..705d34ec3 --- /dev/null +++ b/java/res/values-ms-rMY/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Perbaik cadangan berdasarkan komunikasi anda dan data yang ditaip"</string> +</resources> diff --git a/java/res/values-ms-rMY/strings-talkback-descriptions.xml b/java/res/values-ms-rMY/strings-talkback-descriptions.xml new file mode 100644 index 000000000..29c5fd86a --- /dev/null +++ b/java/res/values-ms-rMY/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Pasangkan set kepala untuk mendengar kekunci kata laluan disebut dengan kuat."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Teks semasa adalah %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Tiada teks dimasukkan"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> membetulkan <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> menjadi <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> melakukan auto pembetulan"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kod kunci %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Kunci anjak dihidupkan (ketik untuk melumpuhkan)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Kunci huruf besar dihidupkan (ketik untuk melumpuhkan)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Padam"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simbol"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Huruf"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Nombor"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Tetapan"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"{0}<td class=\"shortcuts\">{/0} Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Input suara"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Kembali"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Carian"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Titik"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Tukar bahasa"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Slps"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Sebelumnya"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Kunci anjak didayakan"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Kunci huruf besar didayakan"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Kunci anjak dilumpuhkan"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Mod simbol"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Mod huruf"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Mod telefon"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Mod simbol telefon"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Papan kekunci tersembunyi"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Menunjukkan papan kekunci <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"tarikh"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"tarikh dan masa"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mel"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"pemesejan"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"nombor"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teks"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"masa"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Terkini"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Orang"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objek"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Alam Semula Jadi"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Tempat"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simbol"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikon"</string> +</resources> diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml index c9b4a0359..cea20217e 100644 --- a/java/res/values-ms-rMY/strings.xml +++ b/java/res/values-ms-rMY/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Tetapan asal sistem"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Cadangkan nama Kenalan"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama daripada Kenalan untuk cadangan dan pembetulan"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Cadangan diperibadikan"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Titik ruang berganda"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Mengetik 2X pada bar ruang memasukkan titik diikuti dengan ruang"</string> <string name="auto_cap" msgid="1719746674854628252">"Autopenghurufbesaran"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Tunjukkan jejak gerak isyarat"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Pratonton terapung dinamik"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Lihat perkataan yang dicadangkan semasa membuat gerak isyarat"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Disimpan"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Pasangkan set kepala untuk mendengar kekunci kata laluan disebut dengan kuat."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Teks semasa adalah %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Tiada teks dimasukkan"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> membetulkan <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> menjadi <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> melakukan auto pembetulan"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kod kunci %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Kunci anjak dihidupkan (ketik untuk melumpuhkan)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Kunci huruf besar dihidupkan (ketik untuk melumpuhkan)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Padam"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simbol"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Huruf"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbers"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Tetapan"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Ruang"</string> - <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">"Kembali"</string> - <string name="spoken_description_search" msgid="1247236163755920808">"Cari"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Tukar bahasa"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Seterusnya"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Sebelumnya"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift didayakan"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kunci huruf besar didayakan"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Kunci anjak dilumpuhkan"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mod simbol"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mod huruf"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mod telefon"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mod simbol telefon"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Papan kekunci tersembunyi"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Menunjukkan <xliff:g id="MODE">%s</xliff:g> papan kekunci"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"tarikh"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"tarikh dan masa"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mel"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"pemesejan"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"nombor"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teks"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"masa"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gerak isyarat frasa"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Luncur ke kekunci ruang untuk masukkan ruang semasa gerak isyarat"</string> <string name="voice_input" msgid="3583258583521397548">"Kunci input suara"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pada papan kekunci utama"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Pada papan kekunci simbol"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Dimati"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon pada papan kekunci utama"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon pada papan kekunci simbol"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Input suara dilmphkn"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tiada kaedah input suara didayakan. Semak Bahasa & tetapan input."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan kaedah input"</string> <string name="language_selection_title" msgid="1651299598555326750">"Bahasa input"</string> <string name="send_feedback" msgid="1780431884109392046">"Hantar maklum balas"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Bahasa Inggeris (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Bahasa Inggeris (Australia)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Bahasa Sepanyol (AS)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Bahasa Inggeris (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Bahasa Inggeris (AS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Bahasa Sepanyol (AS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Tradisional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Bahasa Inggeris (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Bahasa Inggeris (AS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Bahasa Sepanyol (AS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyril)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Tiada bahasa (Abjad)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Abjad (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Abjad (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Baca fail kamus luaran"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Tiada fail kamus dalam folder Muat Turun"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Pilih fail kamus untuk dipasang"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Betul-betul pasang fail ini untuk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Betul-betul pasang fail ini untuk <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Berlaku ralat"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Longgokan kamus kenalan"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Longgokan kamus peribadi"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Longgokan kamus sejarah pengguna"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Longgokan kamus pemperibadian"</string> <string name="button_default" msgid="3988017840431881491">"Lalai"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Selamat datang ke <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"dengan Taipan Gerak Isyarat"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Muatkan semula"</string> <string name="last_update" msgid="730467549913588780">"Kali terakhir dikemas kini"</string> <string name="message_updating" msgid="4457761393932375219">"Menyemak kemas kini"</string> - <string name="message_loading" msgid="8689096636874758814">"Memuatkan..."</string> + <string name="message_loading" msgid="5638680861387748936">"Memuatkan…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Kamus utama"</string> <string name="cancel" msgid="6830980399865683324">"Batal"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Tetapan"</string> <string name="install_dict" msgid="180852772562189365">"Pasang"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Batal"</string> <string name="delete_dict" msgid="756853268088330054">"Padam"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Bahasa pilihan pada peranti mudah alih anda mempunyai kamus tersedia.<br/> Kami mengesyorkan <b>memuat turun</b> kamus <xliff:g id="LANGUAGE">%1$s</xliff:g> untuk memperbaik pengalaman menaip anda.<br/> <br/> Muat turun boleh mengambil masa seminit atau dua melalui 3G. Caj mungkin dikenakan jika anda tidak mempunyai <b>pelan data tanpa had</b>.<br/> Jika anda tidak pasti jenis pelan data yang anda miliki, kami mengesyorkan agar anda mencari sambungan Wi-Fi untuk mula memuat turun secara automatik.<br/> <br/> Petua: Anda boleh memuat turun dan mengalih keluar kamus dengan pergi ke menu <b>Bahasa & input</b> dalam <b>Tetapan</b> peranti mudah alih anda."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Bahasa pilihan pada peranti mudah alih anda sudah mempunyai kamus yang tersedia.<br/> Kami mengesyorkan <b>memuat turun</b> kamus <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> untuk memperbaik pengalaman menaip anda.<br/> <br/> Muat turun boleh mengambil masa satu atau dua minit melalui 3G. Caj mungkin dikenakan jika anda tidak mempunyai <b>pelan data tanpa had</b>.<br/> Jika anda tidak pasti jenis pelan data yang anda gunakan, kami mengesyorkan agar anda mencari sambungan Wi-Fi untuk mula memuat turun secara automatik.<br/> <br/> Petua: Anda boleh memuat turun dan mengalih keluar kamus dengan pergi ke menu <b>Bahasa& input</b> dalam <b>Tetapan</b> peranti mudah alih anda."</string> <string name="download_over_metered" msgid="1643065851159409546">"Muat turun sekarang (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Muat turun melalui Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Kamus tersedia untuk <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Kamus tersedia untuk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Tekan untuk mengulas dan memuat turun"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Memuat turun: cadangan untuk <xliff:g id="LANGUAGE">%1$s</xliff:g> akan sedia tidak lama lagi."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Memuat turun: cadangan untuk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> akan sedia tidak lama lagi."</string> <string name="version_text" msgid="2715354215568469385">"Versi <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"tambah"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Tambah ke kamus"</string> diff --git a/java/res/values-nb/strings-config-important-notice.xml b/java/res/values-nb/strings-config-important-notice.xml new file mode 100644 index 000000000..01a774c7e --- /dev/null +++ b/java/res/values-nb/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Bruk kommunikasjonen og inndataene dine for å få bedre forslag"</string> +</resources> diff --git a/java/res/values-nb/strings-talkback-descriptions.xml b/java/res/values-nb/strings-talkback-descriptions.xml new file mode 100644 index 000000000..96edf38c8 --- /dev/null +++ b/java/res/values-nb/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Koble til hodetelefoner for å høre opplesing av tegnene i passordet."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Gjeldende tekst er %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Ingen tekst er skrevet inn"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> retter <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> til <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> utfører automatisk retting"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Tastaturkode %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift er på (trykk for å deaktivere)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock er på (trykk for å deaktivere)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Slett"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboler"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Bokstaver"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Tall"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Innstillinger"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Mellomromstasten"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Stemmedata"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Søk"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Prikk"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Bytt språk"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Neste"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Forrige"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift er aktivert"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock er aktivert"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift er deaktivert"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbolmodus"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Bokstavmodus"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Ringemodus"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Ringemodus med symboler"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastaturet er skjult"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Viser <xliff:g id="KEYBOARD_MODE">%s</xliff:g>-tastatur"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"dato"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"dato og klokkeslett"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-post"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"tekstmeldinger"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"tall"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"klokkeslett"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"nettadresse"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Nylige"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personer"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objekter"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Steder"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboler"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Smilefjes"</string> +</resources> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 00aa10da7..e4f16032c 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Systemstandard"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå kontaktnavn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Bruk navn fra Kontakter til forslag og korrigeringer"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Spesialtilpassede forslag"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Punktum ved doble mellomrom"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dobbeltrykk på mellomromstasten for punktum etterfulgt av mellomrom"</string> <string name="auto_cap" msgid="1719746674854628252">"Stor forbokstav"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Vis bevegelsesspor"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamisk flytende forhåndsvsn."</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Se det foreslåtte ordet mens du utfører bevegelser"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Koble til hodetelefoner for å høre opplesing av bokstavene i passordet."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Gjeldende tekst er %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Ingen tekst er skrevet inn"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> retter <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> til <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> utfører automatisk retting"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Tastaturkode %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift er på (trykk for å deaktivere)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock er på (trykk for å deaktivere)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Slett"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboler"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Bokstaver"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Tall"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Innstillinger"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulator"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Mellomrom"</string> - <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_search" msgid="1247236163755920808">"Søk"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Prikk"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Bytt språk"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Neste"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Forrige"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift er aktivert"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock er aktivert"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift er deaktivert"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolmodus"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Bokstavmodus"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Ringemodus"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Ringemodus med symboler"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastaturet er skjult"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Viser <xliff:g id="MODE">%s</xliff:g>-tastatur"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"dato"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"dato og klokkeslett"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-post"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"tekstmeldinger"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"tall"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"tid"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"Nettadresse"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frasebevegelse"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Sett inn mellomrom ved å dra fingeren til mellomromstasten"</string> <string name="voice_input" msgid="3583258583521397548">"Tast for taleinndata"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"På hovedtastatur"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"På talltastatur"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Av"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon på hovedtast."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon på talltastatur"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Taleinndata er deaktiv."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen taleinndatametoder er aktivert. Sjekk Språk og inndata-innstillingene."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inndatametoder"</string> <string name="language_selection_title" msgid="1651299598555326750">"Inndataspråk"</string> <string name="send_feedback" msgid="1780431884109392046">"Send tilbakemelding"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannia)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spansk (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engelsk (Storbritannia) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engelsk (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spansk (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradisjonell)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engelsk (Storbritannia) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engelsk (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spansk (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradisjonelt)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kyrillisk)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Ingen språk (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Bruk en ekstern ordlistefil"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Det ligger ingen ordboksfiler i Nedlastinger-mappen"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Velg ordboksfilen du vil installere"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vil du virkelig installere denne filen for <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Vil du virkelig installere denne filen for <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Det oppsto en feil"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Generer ordliste for kontakter"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Tøm den personlige ordlisten"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Tøm brukerlogg-ordlisten"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Tøm tilpasningsordlisten"</string> <string name="button_default" msgid="3988017840431881491">"Standard"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Velkommen til <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"med Ordføring"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Last inn på nytt"</string> <string name="last_update" msgid="730467549913588780">"Sist oppdatert"</string> <string name="message_updating" msgid="4457761393932375219">"Ser etter oppdateringer ..."</string> - <string name="message_loading" msgid="8689096636874758814">"Laster inn …"</string> + <string name="message_loading" msgid="5638680861387748936">"Laster inn …"</string> <string name="main_dict_description" msgid="3072821352793492143">"Hovedordliste"</string> <string name="cancel" msgid="6830980399865683324">"Avbryt"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Innstillinger"</string> <string name="install_dict" msgid="180852772562189365">"Installer"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Avbryt"</string> <string name="delete_dict" msgid="756853268088330054">"Slett"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Det valgte språket på mobilenheten din har en tilgjengelig ordliste.<br/> Vi anbefaler å <b>laste ned</b> ordlisten for <xliff:g id="LANGUAGE">%1$s</xliff:g>. Dette forbedrer skriveopplevelsen din.<br/> <br/> Nedlastingen kan ta fra ett til to minutter via 3G. Belastninger kan påløpe hvis du ikke har et abonnement med <b>ubegrenset databruk</b>.<br/> Hvis du er usikker på hvilken abonnementstype du har, anbefaler vi deg å finne en Wi-Fi-tilkobling for å starte nedlastingen automatisk.<br/> <br/> Tips: Du kan laste ned og fjerne ordlister ved å gå til <b>Språk og inndata</b> i menyen for <b>Innstillinger</b> på mobilenheten din."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Det valgte språket på mobilenheten din har en tilgjengelig ordliste.<br/> Vi anbefaler å <b>laste ned</b> ordlisten for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Dette forbedrer skriveopplevelsen din.<br/> <br/> Nedlastingen kan ta fra ett til to minutter via 3G. Belastninger kan påløpe hvis du ikke har et abonnement med <b>ubegrenset databruk</b>.<br/> Hvis du er usikker på hvilken abonnementstype du har, anbefaler vi deg å finne en Wi-Fi-tilkobling for å starte nedlastingen automatisk.<br/> <br/> Tips: Du kan laste ned og fjerne ordlister ved å gå til <b>Språk og inndata</b> i menyen for <b>Innstillinger</b> på mobilenheten din."</string> <string name="download_over_metered" msgid="1643065851159409546">"Last ned nå (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Last ned via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"En ordliste er tilgjengelig for <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"En ordliste er tilgjengelig for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Trykk for å se gjennom og laste ned"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Laster ned: Forslag blir snart tilgjengelige for <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Laster ned: forslag til <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> er snart klare"</string> <string name="version_text" msgid="2715354215568469385">"Versjon <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Legg til"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Legg til i ordlisten"</string> diff --git a/java/res/values-ne-rNP/strings-action-keys.xml b/java/res/values-ne-rNP/strings-action-keys.xml new file mode 100644 index 000000000..34b0a14a7 --- /dev/null +++ b/java/res/values-ne-rNP/strings-action-keys.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2013, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="label_go_key" msgid="4033615332628671065">"जानु"</string> + <string name="label_next_key" msgid="5586407279258592635">"अर्को"</string> + <string name="label_previous_key" msgid="1421141755779895275">"पहिलो"</string> + <string name="label_done_key" msgid="7564866296502630852">"भयो"</string> + <string name="label_send_key" msgid="482252074224462163">"पठाउनुहोस्"</string> + <string name="label_pause_key" msgid="2225922926459730642">"रोक्नुहोस्"</string> + <string name="label_wait_key" msgid="5891247853595466039">"पर्खनुहोस्"</string> +</resources> diff --git a/java/res/values-ne-rNP/strings-appname.xml b/java/res/values-ne-rNP/strings-appname.xml new file mode 100644 index 000000000..8b967e8d7 --- /dev/null +++ b/java/res/values-ne-rNP/strings-appname.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2013, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="english_ime_name" msgid="5940510615957428904">"एन्ड्रोइड किबोर्ड (AOSP)"</string> + <string name="spell_checker_service_name" msgid="1254221805440242662">"एन्ड्रोइड हिज्जे जाँचकी (AOSP)"</string> + <string name="english_ime_settings" msgid="5760361067176802794">"एन्ड्रोइड किबोर्ड सेटिङ्हरू (AOSP)"</string> + <string name="android_spell_checker_settings" msgid="6123949487832861885">"एन्ड्रोइड हिज्जे परीक्षक सेटिङ्हरू(AOSP)"</string> +</resources> diff --git a/java/res/values-ne-rNP/strings-config-important-notice.xml b/java/res/values-ne-rNP/strings-config-important-notice.xml new file mode 100644 index 000000000..8816da773 --- /dev/null +++ b/java/res/values-ne-rNP/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"सुझावहरू सुधार गर्न सञ्चारहरू र टाइप गरिएको डेटाबाट जान्नुहोस्"</string> +</resources> diff --git a/java/res/values-ne-rNP/strings-talkback-descriptions.xml b/java/res/values-ne-rNP/strings-talkback-descriptions.xml new file mode 100644 index 000000000..cffed33db --- /dev/null +++ b/java/res/values-ne-rNP/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"पासवर्ड कुञ्जीहरू ठूलो स्वरमा बोलेको आवाज सुन्नका लागि हेडसेट जोड्नुहोस्।"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"वर्तमान पाठ %s हो"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"कुनै पाठ प्रविष्टि गरिएको छैन"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ले <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> लाई <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> मा सच्याउँछ"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ले स्वतः सच्याउने गर्छ"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"कुञ्जी कोड %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"सिफ्ट"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"सिफ्ट सक्रिय छ (असक्षम पार्न ट्याप गर्नुहोस्)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"क्याप्स लक सकृय छ (असक्षम पार्न ट्याप गर्नुहोस्)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"मेटाउनुहोस्"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"प्रतिकहरू"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"अक्षरहरू"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"नम्बरहरू"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"सेटिङ्हरू"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"ट्याब"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"स्पेस"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"आवाज निवेश"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"इमोजी"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"फर्कनुहोस्"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"खोजी गर्नुहोस्"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"डट्"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"भाषा स्विच गर्नुहोस्"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"अर्को"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"अघिल्लो"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"सिफ्ट सक्षम पारिएको छ"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"क्याप्स लक सक्षम पारिएको छ"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"सिफ्ट असक्षम पारिएको छ"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"प्रतिक ढाँचा"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"अक्षर ढाँचा"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"फोन ढाँचा"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"फोन प्रतिक मोड"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"किबोर्ड लुकाइएको छ"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> किबोर्ड देखाउँदै"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"मिति"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"मिति र समय"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"इमेल"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"सन्देश पठाइदै"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"सङ्ख्या"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"फोन"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"पाठ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"समय"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"हालैका"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"मानिसहरू"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"वस्तुहरू"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"प्रकृति"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"स्थानहरू"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"प्रतिकहरू"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"ईमोटिकन्स"</string> +</resources> diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml new file mode 100644 index 000000000..f467443b3 --- /dev/null +++ b/java/res/values-ne-rNP/strings.xml @@ -0,0 +1,204 @@ +<?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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्पहरू"</string> + <string name="english_ime_research_log" msgid="8492602295696577851">"लग निर्देशनहरू शोध गर्नुहोस्"</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> + <string name="general_category" msgid="1859088467017573195">"सामान्य"</string> + <string name="correction_category" msgid="2236750915056607613">"पाठ सुधार"</string> + <string name="gesture_typing_category" msgid="497263612130532630">"इशारा टाइप गर्ने"</string> + <string name="misc_category" msgid="6894192814868233453">"अन्य विकल्पहरू"</string> + <string name="advanced_settings" msgid="362895144495591463">"जटिल सेटिङहरू"</string> + <string name="advanced_settings_summary" msgid="4487980456152830271">"विज्ञहरूका लागि विकल्पहरू"</string> + <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"अन्य इनपुट विधिमा स्विच गर्नुहोस्"</string> + <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"भाषा स्विच किले अन्य इनपुट विधि पनि समेट्छ"</string> + <string name="show_language_switch_key" msgid="5915478828318774384">"भाषा स्विच कुञ्जी"</string> + <string name="show_language_switch_key_summary" msgid="7343403647474265713">"जब बहुसङ्ख्यक इनपुट भाषाहरू सक्षम भएपछि देखाउनुहोस्"</string> + <string name="sliding_key_input_preview" msgid="6604262359510068370">"स्लाइड सूचक देखाउनुहोस्"</string> + <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"सिफ्ट वा प्रतिक कुञ्जीमा स्लाइड गर्ने बेला दृश्य सङ्केत देखाउनुहोस्"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"कि पपअप खारेजी ढिलाइ"</string> + <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ढिलाइ छैन"</string> + <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"पूर्वनिर्धारित"</string> + <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> मिलिसेकेन्ड"</string> + <string name="settings_system_default" msgid="6268225104743331821">"प्रणाली पूर्वनिर्धारित"</string> + <string name="use_contacts_dict" msgid="4435317977804180815">"सम्पर्क नामहरू सुझाव गर्नुहोस्"</string> + <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव र सुधारका लागि सम्पर्कबाट नामहरू प्रयोग गर्नुहोस्"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"निजीकृत सुझावहरू"</string> + <string name="use_double_space_period" msgid="8781529969425082860">"डबल-स्पेस पूर्णविराम"</string> + <string name="use_double_space_period_summary" msgid="6532892187247952799">"स्पेसबारमा डबल ट्याप गर्नाले पूर्णविरामपछि स्पेस राख्दछ"</string> + <string name="auto_cap" msgid="1719746674854628252">"स्वतः पूँजिकरण"</string> + <string name="auto_cap_summary" msgid="7934452761022946874">"प्रत्येक वाक्यको पहिलो शब्द क्यापिटल गर्नुहोस्"</string> + <string name="edit_personal_dictionary" msgid="3996910038952940420">"व्यक्तिगत शब्दकोश"</string> + <string name="configure_dictionaries_title" msgid="4238652338556902049">"एड-अन शब्दकोश"</string> + <string name="main_dictionary" msgid="4798763781818361168">"मुख्य शब्दकोश"</string> + <string name="prefs_show_suggestions" msgid="8026799663445531637">"सुधार सुझावहरू देखाउने"</string> + <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"टाइप गर्ने बेलामा सुझाव शब्दहरू देखाउनुहोस्"</string> + <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"सधैँ देखाउने"</string> + <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"चित्र मोडमा देखाउनुहोस्"</string> + <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"सधैँ लुकाउने"</string> + <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"आपत्तिजनक शब्दहरूलाई रोक्नुहोस्"</string> + <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"सम्भावित आपत्तिजनक शब्दहरू सुझाव नगर्नुहोस्"</string> + <string name="auto_correction" msgid="7630720885194996950">"स्वतः सुधार"</string> + <string name="auto_correction_summary" msgid="5625751551134658006">"गल्ती टाइप भएका शब्दहरूलाई स्पेसबार र पङ्चुएसनले स्वचालित रूपमा सच्याउँछन्।"</string> + <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"बन्द"</string> + <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"सामान्य"</string> + <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"आक्रामक"</string> + <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"ज्यादै आक्रामक"</string> + <string name="bigram_prediction" msgid="1084449187723948550">"अर्को शब्द सुझाव"</string> + <string name="bigram_prediction_summary" msgid="3896362682751109677">"सुझावहरू निर्माण गर्न अघिल्लो शब्द प्रयोग गर्नुहोस्"</string> + <string name="gesture_input" msgid="826951152254563827">"इशारा टाइप गर्ने सक्षम पार्नुहोस्"</string> + <string name="gesture_input_summary" msgid="9180350639305731231">"अक्षर स्लाइड गरी शब्द इनपुट गर्नुहोस्"</string> + <string name="gesture_preview_trail" msgid="3802333369335722221">"इशारा ट्रेल देखाउनुहोस्"</string> + <string name="gesture_floating_preview_text" msgid="4443240334739381053">"गतिशील फ्लोटिङ पूर्वावलोकन"</string> + <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"इशारा गर्दा सुझाव दिइएको शब्द हेर्नुहोस्"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"वाक्यांश इशारा"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"इशाराको बखतमा स्पेस कुञ्जीमा ग्लाईडिंग द्वारा आगत खाली ठाउँहरू"</string> + <string name="voice_input" msgid="3583258583521397548">"आवाज इनपुट कुञ्जी"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कुनै आवाज इनपुट विधिहरू सक्षम गरिएका छैनन्। भाषा र इनपुट सेटिङहरूको जाँच गर्नुहोस्।"</string> + <string name="configure_input_method" msgid="373356270290742459">"इनपुट विधिहरू कन्फिगर गर्नुहोस्"</string> + <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषाहरू"</string> + <string name="send_feedback" msgid="1780431884109392046">"प्रतिक्रिया पठाउनुहोस्"</string> + <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाहरू"</string> + <string name="hint_add_to_dictionary" msgid="573678656946085380">"बचत गर्न पुनः छुनुहोस्"</string> + <string name="has_dictionary" msgid="6071847973466625007">"उपलब्ध शब्दकोश"</string> + <string name="prefs_enable_log" msgid="6620424505072963557">"प्रयोगकर्ता प्रतिक्रिया सक्षम पार्नुहोस्"</string> + <string name="prefs_description_log" msgid="7525225584555429211">"स्वचालित रूपमा प्रयोग तथ्याङ्कहरू र क्यास रिपोर्टहरू पठाएर यस इनपुट विधि सम्पादकलाई सुधार्न सहयोग गर्नुहोस्।"</string> + <string name="keyboard_layout" msgid="8451164783510487501">"किबोर्ड थिम"</string> + <string name="subtype_en_GB" msgid="88170601942311355">"अंग्रेजी (युके)"</string> + <string name="subtype_en_US" msgid="6160452336634534239">"अंग्रेजी (युएस्)"</string> + <string name="subtype_es_US" msgid="5583145191430180200">"स्पेनिस (युएस्)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"अंग्रेजी (बेलायत) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"अंग्रेजी (अमेरिका) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"स्पेनेली (अमेरिका) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (परम्परागत)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (सिरिलिक)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ल्याटिन)"</string> + <string name="subtype_no_language" msgid="7137390094240139495">"कुनै भाषा होइन (वर्णमाला)"</string> + <string name="subtype_no_language_qwerty" msgid="244337630616742604">"वर्णमाला (QWERTY)"</string> + <string name="subtype_no_language_qwertz" msgid="443066912507547976">"वर्णमाला (QWERTZ)"</string> + <string name="subtype_no_language_azerty" msgid="8144348527575640087">"वर्णमाला (AZERTY)"</string> + <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"वर्णमाला (Dvorak)"</string> + <string name="subtype_no_language_colemak" msgid="5837418400010302623">"वर्णमाला (Colemak)"</string> + <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"वर्णमाला (PC)"</string> + <string name="subtype_emoji" msgid="7483586578074549196">"इमोजी"</string> + <string name="keyboard_color_scheme" msgid="9192934113872818070">"रङ योजना"</string> + <string name="keyboard_color_scheme_white" msgid="6684064723850265438">"सेतो"</string> + <string name="keyboard_color_scheme_blue" msgid="2488527224758177593">"नीलो"</string> + <string name="custom_input_styles_title" msgid="8429952441821251512">"अनुकूलन इनपुट शैली"</string> + <string name="add_style" msgid="6163126614514489951">"शैली थप्नुहोस्"</string> + <string name="add" msgid="8299699805688017798">"थप्नुहोस्"</string> + <string name="remove" msgid="4486081658752944606">"हटाउनुहोस्"</string> + <string name="save" msgid="7646738597196767214">"बचत गर्नुहोस्"</string> + <string name="subtype_locale" msgid="8576443440738143764">"भाषा"</string> + <string name="keyboard_layout_set" msgid="4309233698194565609">"लेआउट"</string> + <string name="custom_input_style_note_message" msgid="8826731320846363423">"तपाईँले प्रयोग गर्न सुरु गर्न अघि तपाईँको अनुकूलन इनपुट शैली सक्षम पारिनु पर्छ। के तपाईँ यसलाई अहिले सक्षम पार्न चाहनु हुन्छ?"</string> + <string name="enable" msgid="5031294444630523247">"सक्षम पार्नुहोस्"</string> + <string name="not_now" msgid="6172462888202790482">"अहिले होइन"</string> + <string name="custom_input_style_already_exists" msgid="8008728952215449707">"यस्तो इनपुट शैली पहिले नै अवस्थित छ: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string> + <string name="prefs_usability_study_mode" msgid="1261130555134595254">"प्रयोग अध्ययन मोड"</string> + <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"कुञ्जी लामो थिचाइ ढिलाइ"</string> + <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"कुञ्जी थिचाइ भाइब्रेसन अवधि"</string> + <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"कुञ्जी थिचाइ आवाज भोल्युम"</string> + <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"बाह्य शब्दकोश फाइल पढ्नुहोस्"</string> + <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"डाउनलोड फोल्डरमा कुनै शब्दकोश फाइलहरू छैनन्।"</string> + <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"स्थापना गर्न कुनै शब्दकोश फाइल चयन गर्नुहोस्"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"वास्तवमै <xliff:g id="LANGUAGE_NAME">%s</xliff:g> को लागि यो फाइल स्थापना गर्नुहुन्छ?"</string> + <string name="error" msgid="8940763624668513648">"कुनै त्रुटि भयो"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"सम्पर्क शब्दकोश भेला गर्नुहोस्"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"व्यक्तिगत शब्दकोश डम्प गर्नुहोस्"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"प्रयोगकर्ता इतिहास शब्दकोश डम्प गर"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"निजीकरण शब्दकोश डम्प गर्नुहोस्"</string> + <string name="button_default" msgid="3988017840431881491">"पूर्वनिर्धारित"</string> + <string name="setup_welcome_title" msgid="6112821709832031715">"तपाईँलाई स्वागत छ<xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> + <string name="setup_welcome_additional_description" msgid="8150252008545768953">"इशारा टाइप गर्नेसँग"</string> + <string name="setup_start_action" msgid="8936036460897347708">"सुरु गरौं"</string> + <string name="setup_next_action" msgid="371821437915144603">"अर्को चरण"</string> + <string name="setup_steps_title" msgid="6400373034871816182">"स्थापना गर्दै <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> + <string name="setup_step1_title" msgid="3147967630253462315">"सक्षम पार्नुहोस् <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> + <string name="setup_step1_instruction" msgid="2578631936624637241">"कृपया जाँच गर्नुहोस् \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" तपाईँको भाषा र इनपुट सेटिङमा। यसले तपाईँलाई तपाईँको उपकरणमा सञ्चालन गर्न आधिकारिकता प्रदान गर्छ।"</string> + <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> पहिले नै तपाईँको भाषा र इनपुट सेटिङमा सक्षम पारिएको छ, त्यसैले यो कदम सकिसकिएको छ। अर्कोमा जानुहोस्!"</string> + <string name="setup_step1_action" msgid="4366513534999901728">"सेटिङहरूमा सक्षम पार्नुहोस्"</string> + <string name="setup_step2_title" msgid="6860725447906690594">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>मा स्विच गर्नुहोस्"</string> + <string name="setup_step2_instruction" msgid="9141481964870023336">"त्यसपछि, \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" लाई तपाईँको सक्रिय पाठ इनपुट विधिका रूपमा चयन गर्नुहोस्।"</string> + <string name="setup_step2_action" msgid="1660330307159824337">"इनपुट विधि स्विच गर्नुहोस्"</string> + <string name="setup_step3_title" msgid="3154757183631490281">"बधाई छ, तपाईँले सेट पुरा गर्नुभयो!"</string> + <string name="setup_step3_instruction" msgid="8025981829605426000">"अब तपाईँ <xliff:g id="APPLICATION_NAME">%s</xliff:g>का साथ तपाईँका सम्पूर्ण मनपर्ने अनुप्रयोगहरू टाइप गर्न सक्नुहुन्छ।"</string> + <string name="setup_step3_action" msgid="600879797256942259">"थप भाषाहरू कन्फिगर गर्नुहोस्"</string> + <string name="setup_finish_action" msgid="276559243409465389">"समाप्त भयो"</string> + <string name="show_setup_wizard_icon" msgid="5008028590593710830">"अनुप्रयोग आइकन देखाउनुहोस्"</string> + <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"लन्चरमा अनुप्रयोग आइकन देखाउनुहोस्"</string> + <string name="app_name" msgid="6320102637491234792">"शब्दकोश प्रदायक"</string> + <string name="dictionary_provider_name" msgid="3027315045397363079">"शब्दकोश प्रदायक"</string> + <string name="dictionary_service_name" msgid="6237472350693511448">"शब्दकोश सेवा"</string> + <string name="download_description" msgid="6014835283119198591">"शब्दकोश अद्यावधिक जानकारी"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"एड-अन शब्दकोश"</string> + <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"उपलब्ध शब्दकोश"</string> + <string name="dictionary_settings_summary" msgid="5305694987799824349">"शब्दकोशहरूका लागि सेटिङहरू"</string> + <string name="user_dictionaries" msgid="3582332055892252845">"प्रयोगकर्ता शब्दकोशहरू"</string> + <string name="default_user_dict_pref_name" msgid="1625055720489280530">"प्रयोगकर्ता शब्दकोश"</string> + <string name="dictionary_available" msgid="4728975345815214218">"उपलब्ध शब्दकोश"</string> + <string name="dictionary_downloading" msgid="2982650524622620983">"हाल डाउनलोड गर्दै"</string> + <string name="dictionary_installed" msgid="8081558343559342962">"स्थापित"</string> + <string name="dictionary_disabled" msgid="8950383219564621762">"स्थापित, असक्षम पारिएको"</string> + <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"शब्दकोश सेवासँग जोड्न समस्या"</string> + <string name="no_dictionaries_available" msgid="8039920716566132611">"शब्दकोशहरू उपलब्ध छैनन्"</string> + <string name="check_for_updates_now" msgid="8087688440916388581">"पुनः ताजा गर्नुहोस्"</string> + <string name="last_update" msgid="730467549913588780">"पछिल्लो अद्यावधिक"</string> + <string name="message_updating" msgid="4457761393932375219">"अद्यावधिकको लागि जाँच गर्दै"</string> + <string name="message_loading" msgid="5638680861387748936">"लोड हुँदै..."</string> + <string name="main_dict_description" msgid="3072821352793492143">"मुख्य शब्दकोश"</string> + <string name="cancel" msgid="6830980399865683324">"रद्द गर्नुहोस्"</string> + <string name="go_to_settings" msgid="3876892339342569259">"सेटिङ्हरू"</string> + <string name="install_dict" msgid="180852772562189365">"स्थापना गर्नुहोस्"</string> + <string name="cancel_download_dict" msgid="7843340278507019303">"रद्द गर्नुहोस्"</string> + <string name="delete_dict" msgid="756853268088330054">"मेट्नुहोस्"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"तपाईँको मोबाइल उपकरणमा चयन गरिएको भाषाको शब्दकोश उपलब्ध छ। <br/> तपाईँको टाइप गर्ने अनुभव सुधार गर्न हामी <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>को शब्दकोश <b> डाउनलोड गर्न </b> सिफारिस गर्दछौँ। यो डाउनलोड गर्न 3G मा एक वा दुई मिनेट लिन सक्छ। तपाईँ एक <b> तपाईँको असीमित डेटा योजना </b> छैन भने शुल्क लागू हुन सक्छ। तपाईँसँग कुन डेटा योजना छ भन्ने निश्चित छैन भने Wi-Fi जडान गरेर स्वचालित डाउनलोड गर्न हामी सिफारिस गर्दछौँ। युक्ति: तपाईँ आफ्नो मोबाइल उपकरणको </b> भाषा र इनपुट <b> <b>सेटिङ </b> मेनुमा गएर शब्दकोशलाई डाउनलोड र हटाउन सक्नुहुन्छ।"</string> + <string name="download_over_metered" msgid="1643065851159409546">"(अब डाउनलोड गर्नुहोस्<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> + <string name="do_not_download_over_metered" msgid="2176209579313941583">"वाइ-फाइको माध्ययमद्वार डाउनलोड गर्नुहोस्"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>को लागि एउटा शब्दकोश उपलब्ध छ"</string> + <string name="dict_available_notification_description" msgid="1075194169443163487">"समीक्षा गर्न थिच्नुहोस् र डाउनलोड गर्नुहोस्"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"डाउनलोड गर्दै: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>को लागि सुझावहरू चाँडै नै तयार हुने छ।"</string> + <string name="version_text" msgid="2715354215568469385">"संस्करण <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> + <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"थप्नुहोस्"</string> + <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"शब्दकोशमा थप्नुहोस्"</string> + <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"पदावली"</string> + <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"थप विकल्पहरू"</string> + <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"कम विकल्पहरू"</string> + <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"ठीक छ"</string> + <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"शब्द:"</string> + <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"सर्टकट:"</string> + <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"भाषा:"</string> + <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"एउटा शब्द टाइप गर्नुहोस्"</string> + <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"वैकल्पिक सर्टकट"</string> + <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"शब्द सम्पादन गर्नुहोस्"</string> + <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"सम्पादन गर्नुहोस्"</string> + <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"मेट्नुहोस्"</string> + <string name="user_dict_settings_empty_text" msgid="558499587532668203">"तपाईँसँग प्रयोगकर्ता शब्दकोशमा कुनै शब्द छैन।\"थप्नुहोस्\"(+) बटनमा छोएर एउटा शब्द थप्नुहोस्।"</string> + <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"सबै भाषाहरूका लागि"</string> + <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"थप भाषाहरू..."</string> + <string name="user_dict_settings_delete" msgid="110413335187193859">"मेट्नुहोस्"</string> + <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> +</resources> diff --git a/java/res/values-nl/strings-config-important-notice.xml b/java/res/values-nl/strings-config-important-notice.xml new file mode 100644 index 000000000..a340c99f9 --- /dev/null +++ b/java/res/values-nl/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Suggesties verbeteren met uw communicatie en getypte gegevens"</string> +</resources> diff --git a/java/res/values-nl/strings-talkback-descriptions.xml b/java/res/values-nl/strings-talkback-descriptions.xml new file mode 100644 index 000000000..8dcd5748d --- /dev/null +++ b/java/res/values-nl/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Sluit een headset aan om wachtwoordtoetsen hardop te laten voorlezen."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Huidige tekst is %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Geen tekst ingevoerd"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Met <xliff:g id="KEY_NAME">%1$s</xliff:g> wordt <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> gecorrigeerd naar <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Met <xliff:g id="KEY_NAME">%1$s</xliff:g> voert u automatische correctie uit"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Toetscode %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift aan (tik om uit te schakelen)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock aan (tik om uit te schakelen)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Verwijderen"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbolen"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letters"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Cijfers"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Instellingen"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Spatiebalk"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Spraakinvoer"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Zoeken"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Taal wijzigen"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Volgende"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Vorige"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift ingeschakeld"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock ingeschakeld"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift uitgeschakeld"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbolen"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Alfanumeriek toetsenbord"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Toetsenbord telefoon"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefoonsymbolen"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Toetsenbord verborgen"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Toetsenbord voor <xliff:g id="KEYBOARD_MODE">%s</xliff:g> wordt weergegeven"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum en tijd"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"berichten"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"nummer"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefoon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"tijd"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recent"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Mensen"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objecten"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natuur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Plaatsen"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbolen"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticons"</string> +</resources> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index dcbf2c09c..342464fc8 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Systeemstandaard"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Contactnamen suggereren"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen uit Contacten gebruiken voor suggesties en correcties"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Gepersonaliseerde suggesties"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbeltik is punt, spatie"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbeltik op spatiebalk voor een punt gevolgd door een spatie"</string> <string name="auto_cap" msgid="1719746674854628252">"Auto-hoofdlettergebruik"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Gebarenspoor weergeven"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamisch zwevend voorbeeld"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Het voorgestelde woord weergeven tijdens het tekenen"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Sluit een headset aan om wachtwoordtoetsen hardop te laten voorlezen."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Huidige tekst is %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Geen tekst ingevoerd"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Met <xliff:g id="KEY">%1$s</xliff:g> wordt <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> gecorrigeerd naar <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Met <xliff:g id="KEY">%1$s</xliff:g> voert u automatische correctie uit"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Toetscode %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift aan (tik om uit te schakelen)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock aan (tik om uit te schakelen)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Verwijderen"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbolen"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Cijfers"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Instellingen"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spatie"</string> - <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_search" msgid="1247236163755920808">"Zoeken"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Stip"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Taal wijzigen"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Volgende"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Vorige"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ingeschakeld"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock ingeschakeld"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift uitgeschakeld"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolen"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Alfanumeriek toetsenbord"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Toetsenbord telefoon"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefoonsymbolen"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Toetsenbord verborgen"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> toetsenbord wordt weergegeven"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum en tijd"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"berichten"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"nummer"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefoon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"tijd"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gebaar voor woordgroep"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Spaties invoeren bij gebaren door naar de spatietoets te bewegen"</string> <string name="voice_input" msgid="3583258583521397548">"Toets voor spraakinvoer"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Op hoofdtoetsenbord"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Op symbooltoetsenb."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Uitgeschakeld"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Microfoon op hoofdtoetsenbord"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic op symb.toetsb."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Spraakinvoer is uit"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen spraakinvoermethoden ingeschakeld. Ga naar \'Instellingen voor taal en invoer\'."</string> <string name="configure_input_method" msgid="373356270290742459">"Invoermethoden configureren"</string> <string name="language_selection_title" msgid="1651299598555326750">"Invoertalen"</string> <string name="send_feedback" msgid="1780431884109392046">"Feedback verzenden"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engels (GB)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spaans (VS)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engels (VK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engels (VS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spaans (VS) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditioneel)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engels (VK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engels (VS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spaans (VS) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditioneel)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyrillisch)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latijns)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Geen taal (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Extern woordenboekbestand lezen"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Geen woordenboekbestanden in de map \'Downloads\'"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selecteer een woordenboekbestand om te installeren"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Wilt u dit bestand voor <xliff:g id="LOCALE_NAME">%s</xliff:g> echt installeren?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Wilt u dit bestand voor het <xliff:g id="LANGUAGE_NAME">%s</xliff:g> echt installeren?"</string> <string name="error" msgid="8940763624668513648">"Er is een fout opgetreden"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Contactenwoordenboek dumpen"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Persoonlijk woordenboek dumpen"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Woordenb. gebruikersgesch. dumpen"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Personalisatiewoordenboek dumpen"</string> <string name="button_default" msgid="3988017840431881491">"Standaard"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Welkom bij <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"met Invoer met bewegingen"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Vernieuwen"</string> <string name="last_update" msgid="730467549913588780">"Laatst bijgewerkt"</string> <string name="message_updating" msgid="4457761393932375219">"Controleren op updates"</string> - <string name="message_loading" msgid="8689096636874758814">"Wordt geladen…"</string> + <string name="message_loading" msgid="5638680861387748936">"Laden…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Algemeen woordenboek"</string> <string name="cancel" msgid="6830980399865683324">"Annuleren"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Instellingen"</string> <string name="install_dict" msgid="180852772562189365">"Installeren"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Annuleren"</string> <string name="delete_dict" msgid="756853268088330054">"Verwijderen"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Er is een woordenboek voor de geselecteerde taal beschikbaar op uw mobiele apparaat.<br/> We raden u aan het woordenboek voor het <xliff:g id="LANGUAGE">%1$s</xliff:g> te <b>downloaden</b> om uw typvaardigheid te verbeteren.<br/> <br/> De download kan één of twee minuten duren via 3G. Er kunnen kosten worden berekend als u geen <b>onbeperkt gegevensabonnement</b> heeft.<br/> Als u niet zeker weet welk gegevensabonnement u heeft, raden we u aan een wifi-verbinding te zoeken om de download automatisch te starten.<br/> <br/> Tip: u kunt woordenboeken downloaden en verwijderen via <b>Taal en invoer</b> in het menu <b>Instellingen</b> van uw mobiele apparaat."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Er is een woordenboek beschikbaar voor de geselecteerde taal op uw mobiele apparaat.<br/> We raden u aan het woordenboek voor het <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> te <b>downloaden</b> om uw typvaardigheid te verbeteren.<br/> <br/> De download kan één of twee minuten duren via 3G. Er kunnen kosten worden berekend als u geen <b>onbeperkt gegevensabonnement</b> heeft.<br/> Als u niet zeker weet welk gegevensabonnement u heeft, raden we u aan een wifi-verbinding te zoeken om de download automatisch te starten.<br/> <br/> Tip: u kunt woordenboeken downloaden en verwijderen via <b>Taal en invoer</b> in het menu <b>Instellingen</b> van uw mobiele apparaat."</string> <string name="download_over_metered" msgid="1643065851159409546">"Nu downloaden (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Downloaden via wifi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Er is een woordenboek beschikbaar voor het <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Er is een woordenboek beschikbaar voor het <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Druk om te controleren en te downloaden"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Downloaden: suggesties voor het <xliff:g id="LANGUAGE">%1$s</xliff:g> zijn straks beschikbaar."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Downloaden: suggesties voor het <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> zijn straks beschikbaar."</string> <string name="version_text" msgid="2715354215568469385">"Versie <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Toevoegen"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Toevoegen aan woordenboek"</string> diff --git a/java/res/values-pl/strings-config-important-notice.xml b/java/res/values-pl/strings-config-important-notice.xml new file mode 100644 index 000000000..315a61bc2 --- /dev/null +++ b/java/res/values-pl/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Analizuj wiadomości i wpisywane dane, by ulepszać podpowiedzi"</string> +</resources> diff --git a/java/res/values-pl/strings-talkback-descriptions.xml b/java/res/values-pl/strings-talkback-descriptions.xml new file mode 100644 index 000000000..567bb3b23 --- /dev/null +++ b/java/res/values-pl/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Podłącz zestaw słuchawkowy, by usłyszeć znaki hasła wypowiadane na głos."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Aktualny tekst: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nie wpisano tekstu"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> poprawia <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> wykonuje autokorektę"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kod klawisza: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift włączony (kliknij, by wyłączyć)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock włączony (kliknij, by wyłączyć)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Usuń"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symbole"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Litery"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Liczby"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Ustawienia"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Karta"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Spacja"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Rozpoznawanie mowy"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emotikony"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Szukaj"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Kropka"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Przełącz język"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Dalej"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Wstecz"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift włączony"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock włączony"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift wyłączony"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Tryb symboli"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Tryb liter"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Tryb telefonu"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Tryb symboli telefonu"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klawiatura ukryta"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Pokazuję klawiaturę w trybie <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data i godzina"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"SMS"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"liczba"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"tekst"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"godzina"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"adres URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Niedawne"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Osoby"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Obiekty"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Przyroda"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Miejsca"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symbole"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikony"</string> +</resources> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index c78674a9b..c4261c60e 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -33,7 +33,7 @@ <string name="misc_category" msgid="6894192814868233453">"Inne opcje"</string> <string name="advanced_settings" msgid="362895144495591463">"Ustawienia zaawansowane"</string> <string name="advanced_settings_summary" msgid="4487980456152830271">"Opcje dla ekspertów"</string> - <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Włącz inne metody wprowadzania"</string> + <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Inne metody wprowadzania"</string> <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Klawisz zmiany języka obejmuje też inne metody wprowadzania"</string> <string name="show_language_switch_key" msgid="5915478828318774384">"Klawisz zmiany języka"</string> <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Pokaż, gdy włączonych jest kilka języków wprowadzania"</string> @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Ustawienie domyślne"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proponuj osoby z kontaktów"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"W propozycjach i poprawkach użyj nazwisk z kontaktów"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Spersonalizowane sugestie"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Szybka kropka ze spacją"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dwukrotne kliknięcie spacji wstawia kropkę ze spacją"</string> <string name="auto_cap" msgid="1719746674854628252">"Wstawiaj wielkie litery"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Pokazuj ślad gestu"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamiczny podgląd słowa"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Podczas gestykulacji będzie widoczne podpowiadane słowo"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Podłącz zestaw słuchawkowy, aby usłyszeć znaki hasła wypowiadane na głos."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Aktualny tekst: %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nie wprowadzono tekstu"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> poprawia <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> wykonuje autokorektę"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kod klawisza: %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift włączony (kliknij, by wyłączyć)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock włączony (kliknij, by wyłączyć)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Usuń"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbole"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Litery"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Liczby"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Ustawienia"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spacja"</string> - <string name="spoken_description_mic" msgid="615536748882611950">"Rozpoznawanie mowy"</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_search" msgid="1247236163755920808">"Szukaj"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Przełącz język"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Dalej"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Wstecz"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift włączony"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock włączony"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift wyłączony"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Tryb symboli"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Tryb liter"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Tryb telefonu"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Tryb symboli telefonu"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klawiatura ukryta"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Pokazuję klawiaturę w trybie <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"data"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"data i godzina"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"SMS"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"liczba"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"godzina"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gest wyrażenia"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Wpisuj spacje podczas gestów, przesuwając palec do klawisza spacji"</string> <string name="voice_input" msgid="3583258583521397548">"Klawisz rozpoznawania mowy"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na klawiaturze głównej"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klawiaturze z symbolami"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Wyłącz"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon na klawiaturze głównej"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon na klawiaturze z symbolami"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Rozpoznawanie mowy jest wyłączone"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie włączono żadnych metod wprowadzania głosowego. Sprawdź ustawienia języka i wprowadzania."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfiguruj metody wprowadzania"</string> <string name="language_selection_title" msgid="1651299598555326750">"Języki wprowadzania"</string> <string name="send_feedback" msgid="1780431884109392046">"Prześlij opinię"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"angielski (Wielka Brytania)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angielski (Stany Zjednoczone)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"hiszpański (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angielski (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"angielski (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"hiszpański (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradycyjny)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Angielski (Wielka Brytania) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Angielski (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Hiszpański (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradycyjny)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cyrylica)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (alfabet łaciński)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Bez języka (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -162,14 +119,18 @@ <string name="not_now" msgid="6172462888202790482">"Nie teraz"</string> <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Taki styl wprowadzania już istnieje: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tryb badania przydatności"</string> - <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Opóźn. przy przytrzym. przycisku"</string> - <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Czas wibr. przy naciśn. przycisku"</string> - <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Głośność przy naciśn. przycisku"</string> + <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Opóźnienie przy długim naciśnięciu"</string> + <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Wibracja przy naciśniętym klawiszu"</string> + <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Głośność przy naciśniętym klawiszu"</string> <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Odczyt zewnętrznego pliku słownika"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Brak plików słownika w folderze Pobrane pliki"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Wybierz plik słownika do zainstalowania"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Czy na pewno zainstalować ten plik dla języka: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Czy na pewno zainstalować ten plik dla języka: <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Wystąpił błąd"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Wyciąg ze słownika kontaktów"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Wyciąg ze słownika osobistego"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Wyciąg ze słownika historii użytk."</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Wyciąg ze słownika personalizacji"</string> <string name="button_default" msgid="3988017840431881491">"Domyślne"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Witamy w aplikacji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"z pisaniem gestami"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Odśwież"</string> <string name="last_update" msgid="730467549913588780">"Ostatnia aktualizacja"</string> <string name="message_updating" msgid="4457761393932375219">"Sprawdzanie dostępności aktualizacji"</string> - <string name="message_loading" msgid="8689096636874758814">"Wczytuję..."</string> + <string name="message_loading" msgid="5638680861387748936">"Wczytuję…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Słownik główny"</string> <string name="cancel" msgid="6830980399865683324">"Anuluj"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Ustawienia"</string> <string name="install_dict" msgid="180852772562189365">"Zainstaluj"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Anuluj"</string> <string name="delete_dict" msgid="756853268088330054">"Usuń"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Dla języka, którego używasz na swoim urządzeniu przenośnym, jest dostępny słownik.<br/> Warto <b>pobrać</b> ten słownik <xliff:g id="LANGUAGE">%1$s</xliff:g>, by ułatwić sobie pisanie.<br/> <br/> Pobieranie trwa do dwóch minut (przez 3G). Jeśli nie masz <b>abonamentu z nieograniczoną transmisją danych</b>, operator może naliczyć opłatę.<br/> Jeśli nie wiesz, jaki masz abonament, połącz się z Wi-Fi, by automatycznie rozpocząć pobieranie.<br/> <br/> Wskazówka: słowniki możesz pobierać i usuwać na urządzeniu w sekcji <b>Język, klawiatura, głos</b> w menu <b>Ustawienia</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Do języka, którego używasz na swoim urządzeniu przenośnym, jest dostępny słownik.<br/> Warto <b>pobrać</b> ten słownik <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>, by ułatwić sobie pisanie.<br/> <br/> Pobieranie trwa do dwóch minut (przez 3G). Jeśli nie masz <b>abonamentu z nieograniczoną transmisją danych</b>, operator może naliczyć opłatę.<br/> Jeśli nie wiesz, jaki masz abonament, połącz się z Wi-Fi, by automatycznie rozpocząć pobieranie.<br/> <br/> Wskazówka: słowniki możesz pobierać i usuwać w sekcji <b>Język, klawiatura, głos</b> w menu <b>Ustawienia</b> na urządzeniu."</string> <string name="download_over_metered" msgid="1643065851159409546">"Pobierz teraz (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Pobierz przez Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Dostępny jest słownik <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Dostępny jest słownik <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Naciśnij, by sprawdzić i pobrać"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Pobieranie – wkrótce będą dostępne sugestie w tym języku: <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Pobieranie – wkrótce będą dostępne sugestie w tym języku: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Wersja <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Dodaj"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Dodaj do słownika"</string> diff --git a/java/res/values-port/setup-dimens-small-phone-port.xml b/java/res/values-port/setup-dimens-small-phone-port.xml index 8ac72ea7c..cf2751f1b 100644 --- a/java/res/values-port/setup-dimens-small-phone-port.xml +++ b/java/res/values-port/setup-dimens-small-phone-port.xml @@ -20,7 +20,6 @@ <dimen name="setup_welcome_description_text_size">20sp</dimen> <dimen name="setup_step_bullet_text_size">18sp</dimen> <dimen name="setup_step_triangle_indicator_height">18dp</dimen> - <dimen name="setup_step_indicator_height">18dp</dimen> <dimen name="setup_step_title_text_size">18sp</dimen> <dimen name="setup_step_instruction_text_size">14sp</dimen> <dimen name="setup_step_action_text_size">16sp</dimen> diff --git a/java/res/values-pt-rPT/strings-config-important-notice.xml b/java/res/values-pt-rPT/strings-config-important-notice.xml new file mode 100644 index 000000000..38e2499d4 --- /dev/null +++ b/java/res/values-pt-rPT/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Aprender com comunicações e dados introd. para melhorar sugestões"</string> +</resources> diff --git a/java/res/values-pt-rPT/strings-talkback-descriptions.xml b/java/res/values-pt-rPT/strings-talkback-descriptions.xml new file mode 100644 index 000000000..bf51caa78 --- /dev/null +++ b/java/res/values-pt-rPT/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Ligar auscultadores com microfone integrado para ouvir as teclas da palavra-passe."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"O texto atual é %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nenhum texto digitado"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> para <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> executa a correção automática"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Código da tecla %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift ativado (tocar para desativar)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock ativado (tocar para desativar)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Eliminar"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Símbolos"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letras"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Números"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Definições"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Separador"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espaço"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrada de voz"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Voltar"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Pesquisar"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Ponto"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Mudar de idioma"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Seguinte"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Anterior"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift ativado"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock ativado"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift desativado"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modo de símbolos"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modo de letras"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modo de telemóvel"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modo de símbolos de telemóvel"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Teclado oculto"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"A mostrar o teclado de <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data e hora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mensagens"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"números"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telemóvel"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"texto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"hora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recentes"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Pessoas"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objetos"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natureza"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Locais"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Símbolos"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Ícones expressivos"</string> +</resources> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index c27758116..8b75dd0dd 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Predef. do sistema"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de Contactos"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nomes dos Contactos para sugestões e correções"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Sugestões personalizadas"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Ponto de espaço duplo"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Tocar duas vezes na barra espaço insere ponto seguido de espaço"</string> <string name="auto_cap" msgid="1719746674854628252">"Letras maiúsculas automáticas"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar percurso do gesto"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Pré-visual. flutuante dinâmica"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Ver palavra sugerida enquanto toca"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Ligar auscultadores com microfone integrado para ouvir as teclas da palavra-passe."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"O texto atual é %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nenhum texto digitado"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> para <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> executa correção automática"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Código da tecla %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ativado (tocar para desativar)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock ativado (tocar para desativar)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Símbolos"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letras"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Números"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Definições"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espaço"</string> - <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_search" msgid="1247236163755920808">"Pesquisar"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Mudar de idioma"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Seguinte"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ativado"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ativado"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift desativado"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modo de símbolos"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modo de letras"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modo de telemóvel"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modo de símbolos de telemóvel"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Teclado oculto"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"A mostrar teclado de <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"data"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"data e hora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mensagens"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"números"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telemóvel"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"texto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URLs"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Toque de expressão"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Deslize p/ a tecla de espaço p/ introduzir espaços durante toques"</string> <string name="voice_input" msgid="3583258583521397548">"Chave de entrada de voz"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"No teclado principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"No teclado símbolos"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Desligar"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. tecl. principal"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic. tecl. símbolos"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entr. voz desact."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as definições de Idioma e introdução."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de introdução"</string> <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string> <string name="send_feedback" msgid="1780431884109392046">"Enviar comentários"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Inglês (RU)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglês (EUA)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Espanhol (EUA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglês (RU) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglês (EUA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Espanhol (EUA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Tradicional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglês (RU) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglês (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Espanhol (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cirílico)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latim)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Sem idioma (alfabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ler ficheiro de dicionário externo"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Não há ficheiros de dicionário na pasta Transferências"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selecione um ficheiro de dicionário para instalar"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Instalar mesmo este ficheiro para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Instalar mesmo este ficheiro para <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Ocorreu um erro"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Transferir dicionário de contactos"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Descarregar dicionário pessoal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Desc. dicion. do hist. do utiliz."</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Descarregar dicionário de personal."</string> <string name="button_default" msgid="3988017840431881491">"Predefinido"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Bem-vindo(a) a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"com a Escrita com Gestos"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Atualizar"</string> <string name="last_update" msgid="730467549913588780">"Última atualização"</string> <string name="message_updating" msgid="4457761393932375219">"A verificar existência de atualizações"</string> - <string name="message_loading" msgid="8689096636874758814">"A carregar..."</string> + <string name="message_loading" msgid="5638680861387748936">"A carregar…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Dicionário principal"</string> <string name="cancel" msgid="6830980399865683324">"Cancelar"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Definições"</string> <string name="install_dict" msgid="180852772562189365">"Instalar"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancelar"</string> <string name="delete_dict" msgid="756853268088330054">"Eliminar"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"O idioma selecionado no dispositivo móvel tem um dicionário disponível.<br/> Recomendamos que <b>transfira</b> o dicionário de <xliff:g id="LANGUAGE">%1$s</xliff:g> para melhorar a sua experiência de introdução de texto.<br/> <br/> A transferência pode demorar um ou dois minutos acima de 3G. Poderão ser aplicadas taxas se não tiver um <b>plano de dados ilimitado</b>.<br/> Se não tiver a certeza do plano de dados que tem, recomendamos que localize uma ligação Wi-Fi para começar a transferência automaticamente.<br/> <br/> Sugestão: pode transferir e remover dicionários acedendo a <b>Idioma e introdução</b> no menu <b>Definições</b> do disp. móvel."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"O idioma selecionado no disp. móvel tem um dicionário disponível.<br/> Recomendamos que <b>transfira</b> o dicionário de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para melhorar a sua experiência de introdução de texto.<br/> <br/> A transferência pode demorar um ou dois minutos através de 3G. Poderão ser aplicadas taxas se não tiver um <b>plano de dados ilimitado</b>.<br/> Se não tiver a certeza do plano de dados que tem, recomendamos que procure uma ligação Wi-Fi para começar a transferência automaticamente.<br/> <br/> Sugestão: Pode transferir e remover dicionários acedendo a <b>Idioma e introdução</b> no menu <b>Definições</b> do disp. móvel."</string> <string name="download_over_metered" msgid="1643065851159409546">"Transferir agora (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Transferir via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Está disponível um dicionário para <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Está disponível um dicionário de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Prima para consultar e transferir"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"A transferir: as sugestões para <xliff:g id="LANGUAGE">%1$s</xliff:g> estarão prontas em breve."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"A transferir: as sugestões para <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> estarão prontas em breve"</string> <string name="version_text" msgid="2715354215568469385">"Versão <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Adicionar"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Adicionar ao dicionário"</string> diff --git a/java/res/values-pt/strings-config-important-notice.xml b/java/res/values-pt/strings-config-important-notice.xml new file mode 100644 index 000000000..86af5ff6d --- /dev/null +++ b/java/res/values-pt/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Aprender com mensagens e dados digitados para melhorar sugestões"</string> +</resources> diff --git a/java/res/values-pt/strings-talkback-descriptions.xml b/java/res/values-pt/strings-talkback-descriptions.xml new file mode 100644 index 000000000..01aac3931 --- /dev/null +++ b/java/res/values-pt/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Conecte um fone de ouvido para ouvir as chaves de senha."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"O texto atual é %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nenhum texto digitado"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> para <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> realiza correção automática"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Código de tecla %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift ativado (toque para desativar)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock ativado (toque para desativar)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Excluir"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Símbolos"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Letras"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Números"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Configurações"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Espaço"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Entrada de texto por voz"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emojis"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Pesquisar"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Ponto"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Alterar idioma"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Próximo"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Anterior"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift ativado"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock ativado"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift desativado"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modo de símbolos"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modo de letras"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modo de telefone"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modo de símbolos do telefone"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Teclado oculto"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Mostrando teclado <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"data e hora"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mensagens"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"número"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefone"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"texto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"hora"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recentes"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Pessoas"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Objetos"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natureza"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Lugares"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Símbolos"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticons"</string> +</resources> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index f98ef8cd6..afee26d25 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -39,25 +39,26 @@ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Mostrar quando vários idiomas de entrada estiverem ativados"</string> <string name="sliding_key_input_preview" msgid="6604262359510068370">"Mostrar indicador de deslize"</string> <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Mostrar indicação visual ao deslizar teclas Shift ou de símbolos"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Dispens. atraso chave princ."</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Duração de popup da tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Padrão"</string> <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string> <string name="settings_system_default" msgid="6268225104743331821">"Padrão do sistema"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de contato"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nomes dos Contatos para sugestões e correções"</string> - <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço p/ ponto"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Sugestões personalizadas"</string> + <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço para ponto"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Toque duplo na barra de espaço insere um ponto seguido de espaço"</string> - <string name="auto_cap" msgid="1719746674854628252">"Capitaliz. automática"</string> + <string name="auto_cap" msgid="1719746674854628252">"Capitalização automática"</string> <string name="auto_cap_summary" msgid="7934452761022946874">"Iniciar a primeira palavra de cada frase com letra maiúscula"</string> <string name="edit_personal_dictionary" msgid="3996910038952940420">"Dicionário pessoal"</string> <string name="configure_dictionaries_title" msgid="4238652338556902049">"Dicionários complementares"</string> <string name="main_dictionary" msgid="4798763781818361168">"Dicionário principal"</string> - <string name="prefs_show_suggestions" msgid="8026799663445531637">"Exibir sugestões de correção"</string> + <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostrar sugestões de correção"</string> <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Exibir sugestões de palavras durante a digitação"</string> <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostrar sempre"</string> <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Mostrar em modo retrato"</string> - <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Sempre ocultar"</string> + <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Não mostrar"</string> <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Bloquear palavras ofensivas"</string> <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Não sugerir palavras potencialmente ofensivas"</string> <string name="auto_correction" msgid="7630720885194996950">"Correção automática"</string> @@ -66,63 +67,17 @@ <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string> <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Agressivo"</string> <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Muito agressivo"</string> - <string name="bigram_prediction" msgid="1084449187723948550">"Sugestões para a palavra seguinte"</string> + <string name="bigram_prediction" msgid="1084449187723948550">"Sugerir palavra seguinte"</string> <string name="bigram_prediction_summary" msgid="3896362682751109677">"Usar a palavra anterior ao fazer sugestões"</string> <string name="gesture_input" msgid="826951152254563827">"Ativar a escrita com gestos"</string> <string name="gesture_input_summary" msgid="9180350639305731231">"Inserir uma palavra deslizando os dedos pelas letras"</string> <string name="gesture_preview_trail" msgid="3802333369335722221">"Mostrar percurso do gesto"</string> - <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Visualizaç. dinâmica flutuante"</string> + <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Previsão dinâmica flutuante"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Ver a palavra sugerida ao usar gestos"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Conecte um fone de ouvido para ouvir as chaves de senha em voz alta."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"O texto atual é %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nenhum texto digitado"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corrige <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> para <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> realiza correção automática"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Código de tecla %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ativado (toque para desativar)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock ativado (toque para desativar)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Excluir"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Símbolos"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letras"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Números"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Configurações"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Espaço"</string> - <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_search" msgid="1247236163755920808">"Pesquisar"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Alterar idioma"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Próximo"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Anterior"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ativado"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ativado"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift desativado"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modo de símbolos"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modo de cartas"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modo de telefone"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modo de símbolos de telefone"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Teclado oculto"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Mostrando teclado <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"data"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"data e hora"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mensagens"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"número"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefone"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"texto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> - <string name="voice_input" msgid="3583258583521397548">"Chave de entrada de texto por voz"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"No teclado principal"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"No teclado de símb."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Desativado"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. no teclado"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic. no teclado"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Texto por voz desat."</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gesto de frase"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Inserir espaços durante gestos deslizando até a tecla de espaço"</string> + <string name="voice_input" msgid="3583258583521397548">"Tecla p/ inserir texto por voz"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as configurações \"Idioma e entrada\"."</string> <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string> <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string> <string name="send_feedback" msgid="1780431884109392046">"Enviar comentários"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"espanhol (EUA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Inglês (Reino Unido) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Inglês (EUA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"espanhol (EUA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Inglês (Reino Unido) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Inglês (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Espanhol (EUA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cirílico)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latino)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nenhum idioma (alfabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Ler arquivo de dicionário externo"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Nenhum arquivo de dicionário na pasta Downloads"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selecione um arquivo de dicionário para instalar"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Deseja instalar este arquivo para <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Deseja instalar este arquivo para <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Ocorreu um erro"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Listar dicionário de contatos"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Despejar dicionário pessoal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Despejar dicio. de hist. do usuário"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Despejar dicion. de personalização"</string> <string name="button_default" msgid="3988017840431881491">"Padrão"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Bem-vindo ao <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"com entrada por gestos"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Atualizar"</string> <string name="last_update" msgid="730467549913588780">"Última atualização"</string> <string name="message_updating" msgid="4457761393932375219">"Verificando atualizações"</string> - <string name="message_loading" msgid="8689096636874758814">"Carregando..."</string> + <string name="message_loading" msgid="5638680861387748936">"Carregando…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Dicionário principal"</string> <string name="cancel" msgid="6830980399865683324">"Cancelar"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Configurações"</string> <string name="install_dict" msgid="180852772562189365">"Instalar"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Cancelar"</string> <string name="delete_dict" msgid="756853268088330054">"Excluir"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"O idioma selecionado em seu dispositivo móvel tem um dicionário disponível.<br/> Recomendamos <b>fazer o download</b> do dicionário de <xliff:g id="LANGUAGE">%1$s</xliff:g> para melhorar sua experiência de digitação.<br/> O download pode levar um ou dois minutos por conexão 3G. Tarifas podem ser aplicáveis caso você não tenha um <b>plano de dados ilimitado</b>.<br/> Se você não tem certeza quanto a seu plano de dados, recomendamos encontrar uma conexão Wi-Fi para iniciar o download automaticamente.<br/> Dica: você pode fazer o download de dicionários e removê-los acessando <b>Idioma e entrada</b> no menu <b>Configurações</b> de seu dispositivo móvel."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"O idioma selecionado em seu dispositivo móvel tem um dicionário disponível.<br/> Recomendamos <b>fazer o download</b> do dicionário de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para melhorar sua experiência de digitação.<br/> O download pode levar um ou dois minutos por conexão 3G. Tarifas podem ser aplicáveis caso você não tenha um <b>plano de dados ilimitado</b>.<br/> Se você não tem certeza quanto a seu plano de dados, recomendamos encontrar uma conexão Wi-Fi para iniciar o download automaticamente.<br/> Dica: você pode fazer o download de dicionários e removê-los acessando <b>Idioma e entrada</b> no menu <b>Configurações</b> do dispositivo móvel."</string> <string name="download_over_metered" msgid="1643065851159409546">"Fazer o download agora (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Fazer o download por Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Há um dicionário disponível para <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Há um dicionário disponível para <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pressione para consultar e fazer o download"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Download em andamento: as sugestões para <xliff:g id="LANGUAGE">%1$s</xliff:g> estarão prontas em breve."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Download em andamento: as sugestões para <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> estarão disponíveis em breve."</string> <string name="version_text" msgid="2715354215568469385">"Versão <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Adicionar"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Adicionar ao dicionário"</string> diff --git a/java/res/values-rm/strings-talkback-descriptions.xml b/java/res/values-rm/strings-talkback-descriptions.xml new file mode 100644 index 000000000..05b816ab7 --- /dev/null +++ b/java/res/values-rm/strings-talkback-descriptions.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- no translation found for spoken_use_headphones (896961781287283493) --> + <skip /> + <!-- no translation found for spoken_current_text_is (2485723011272583845) --> + <skip /> + <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> + <skip /> + <!-- no translation found for spoken_auto_correct (8005997889020109763) --> + <skip /> + <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> + <skip /> + <!-- no translation found for spoken_description_unknown (3197434010402179157) --> + <skip /> + <!-- no translation found for spoken_description_shift (244197883292549308) --> + <skip /> + <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> + <skip /> + <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> + <skip /> + <!-- no translation found for spoken_description_delete (8740376944276199801) --> + <skip /> + <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> + <skip /> + <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> + <skip /> + <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> + <skip /> + <!-- no translation found for spoken_description_settings (4627462689603838099) --> + <skip /> + <!-- no translation found for spoken_description_tab (2667716002663482248) --> + <skip /> + <!-- no translation found for spoken_description_space (2582521050049860859) --> + <skip /> + <!-- no translation found for spoken_description_mic (615536748882611950) --> + <skip /> + <!-- no translation found for spoken_description_smiley (2256309826200113918) --> + <skip /> + <!-- no translation found for spoken_description_return (8178083177238315647) --> + <skip /> + <!-- no translation found for spoken_description_search (1247236163755920808) --> + <skip /> + <!-- no translation found for spoken_description_dot (40711082435231673) --> + <skip /> + <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> + <skip /> + <!-- no translation found for spoken_description_action_next (8636078276664150324) --> + <skip /> + <!-- no translation found for spoken_description_action_previous (800872415009336208) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> + <skip /> + <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> + <skip /> + <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> + <skip /> + <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> + <skip /> + <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> + <skip /> + <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> + <skip /> + <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> + <skip /> + <!-- no translation found for keyboard_mode_date (3137520166817128102) --> + <skip /> + <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> + <skip /> + <!-- no translation found for keyboard_mode_email (6216248078128294262) --> + <skip /> + <!-- no translation found for keyboard_mode_im (1137405089766557048) --> + <skip /> + <!-- no translation found for keyboard_mode_number (7991623440699957069) --> + <skip /> + <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> + <skip /> + <!-- no translation found for keyboard_mode_text (6479436687899701619) --> + <skip /> + <!-- no translation found for keyboard_mode_time (4381856885582143277) --> + <skip /> + <!-- no translation found for keyboard_mode_url (1519819835514911218) --> + <skip /> +</resources> diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index 3f0bab963..2ea98cf53 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -122,105 +122,8 @@ <skip /> <!-- no translation found for gesture_floating_preview_text_summary (4472696213996203533) --> <skip /> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Memorisà"</string> - <!-- no translation found for spoken_use_headphones (896961781287283493) --> - <skip /> - <!-- no translation found for spoken_current_text_is (2485723011272583845) --> - <skip /> - <!-- no translation found for spoken_no_text_entered (7479685225597344496) --> - <skip /> - <!-- no translation found for spoken_auto_correct (8005997889020109763) --> - <skip /> - <!-- no translation found for spoken_auto_correct_obscured (6276420476908833791) --> - <skip /> - <!-- no translation found for spoken_description_unknown (3197434010402179157) --> - <skip /> - <!-- no translation found for spoken_description_shift (244197883292549308) --> - <skip /> - <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) --> - <skip /> - <!-- no translation found for spoken_description_caps_lock (3276478269526304432) --> - <skip /> - <!-- no translation found for spoken_description_delete (8740376944276199801) --> - <skip /> - <!-- no translation found for spoken_description_to_symbol (5486340107500448969) --> - <skip /> - <!-- no translation found for spoken_description_to_alpha (23129338819771807) --> - <skip /> - <!-- no translation found for spoken_description_to_numeric (591752092685161732) --> - <skip /> - <!-- no translation found for spoken_description_settings (4627462689603838099) --> - <skip /> - <!-- no translation found for spoken_description_tab (2667716002663482248) --> - <skip /> - <!-- no translation found for spoken_description_space (2582521050049860859) --> - <skip /> - <!-- no translation found for spoken_description_mic (615536748882611950) --> - <skip /> - <!-- no translation found for spoken_description_smiley (2256309826200113918) --> - <skip /> - <!-- no translation found for spoken_description_return (8178083177238315647) --> - <skip /> - <!-- no translation found for spoken_description_search (1247236163755920808) --> - <skip /> - <!-- no translation found for spoken_description_dot (40711082435231673) --> - <skip /> - <!-- no translation found for spoken_description_language_switch (5507091328222331316) --> - <skip /> - <!-- no translation found for spoken_description_action_next (8636078276664150324) --> - <skip /> - <!-- no translation found for spoken_description_action_previous (800872415009336208) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) --> - <skip /> - <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) --> - <skip /> - <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) --> - <skip /> - <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone (6520207943132026264) --> - <skip /> - <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) --> - <skip /> - <!-- no translation found for announce_keyboard_hidden (8718927835531429807) --> - <skip /> - <!-- no translation found for announce_keyboard_mode (4729081055438508321) --> - <skip /> - <!-- no translation found for keyboard_mode_date (3137520166817128102) --> - <skip /> - <!-- no translation found for keyboard_mode_date_time (339593358488851072) --> - <skip /> - <!-- no translation found for keyboard_mode_email (6216248078128294262) --> - <skip /> - <!-- no translation found for keyboard_mode_im (1137405089766557048) --> - <skip /> - <!-- no translation found for keyboard_mode_number (7991623440699957069) --> - <skip /> - <!-- no translation found for keyboard_mode_phone (6851627527401433229) --> - <skip /> - <!-- no translation found for keyboard_mode_text (6479436687899701619) --> - <skip /> - <!-- no translation found for keyboard_mode_time (4381856885582143277) --> - <skip /> - <!-- no translation found for keyboard_mode_url (1519819835514911218) --> - <skip /> <!-- 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) --> - <skip /> - <!-- no translation found for voice_input_modes_off (3745699748218082014) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) --> - <skip /> - <!-- no translation found for voice_input_modes_summary_off (63875609591897607) --> - <skip /> <!-- no translation found for configure_input_method (373356270290742459) --> <skip /> <string name="language_selection_title" msgid="1651299598555326750">"Linguas da cumonds vocals"</string> diff --git a/java/res/values-ro/strings-config-important-notice.xml b/java/res/values-ro/strings-config-important-notice.xml new file mode 100644 index 000000000..f481e8972 --- /dev/null +++ b/java/res/values-ro/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Utilizează mesajele și datele introduse pt. a îmbunătăți sugestiile"</string> +</resources> diff --git a/java/res/values-ro/strings-talkback-descriptions.xml b/java/res/values-ro/strings-talkback-descriptions.xml new file mode 100644 index 000000000..2b428eb0b --- /dev/null +++ b/java/res/values-ro/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Conectați un set căști-microfon pentru a auzi tastele apăsate când introduceți parola."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Textul curent este %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nu a fost introdus text"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corectează <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> cu <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> efectuează corectare automată"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Tasta cu codul %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Tasta Shift este activată (apăsați pentru a o dezactiva)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Tasta Caps Lock este activată (apăsați pentru a o dezactiva)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Ștergeți"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simboluri"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Litere"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Cifre"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Setări"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Tasta Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Intrare vocală"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoticonuri"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Căutați"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Bulină"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Schimbați limba"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Înai."</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Înapoi"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Tasta Shift a fost activată"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Tasta Caps Lock este activată"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Tasta Shift a fost dezactivată"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Modul Simboluri"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Modul Alfanumeric"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Modul Telefon"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Modul Telefon cu simboluri"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tastatura este ascunsă"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Se afișează tastatura pentru <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"data"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"date și ore"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"adrese de e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mesaje"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"numere"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefoane"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ore"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"adrese URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Recente"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Persoane"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Obiecte"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natură"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Locații"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboluri"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emoticonuri"</string> +</resources> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 147f83e61..51d3c5901 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Valoare prestabilită"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugeraţi nume din Agendă"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Sugestii personalizate"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Inserează punct spațiu"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubla atingere a barei de spațiu inserează punct urmat de spațiu"</string> <string name="auto_cap" msgid="1719746674854628252">"Scriere automată cu majuscule"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Se afişează urma gestului"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Sugestie flotantă dinamică"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Afişaţi cuvântul sugerat când utilizaţi gesturi"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Textul curent este %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nu a fost introdus text"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> corectează <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> cu <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> efectuează corectare automată"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Tasta cu codul %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Tasta Shift este activată (apăsaţi pentru a o dezactiva)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Tasta Caps Lock este activată (apăsaţi pentru a o dezactiva)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboluri"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Litere"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Cifre"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Setări"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Spaţiu"</string> - <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_search" msgid="1247236163755920808">"Căutaţi"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punct"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Schimbaţi limba"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Înainte"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Înapoi"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Tasta Shift a fost activată"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Tasta Caps Lock a fost activată"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Tasta Shift a fost dezactivată"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Modul Simboluri"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Modul Alfanumeric"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Modul Telefon"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Modul Telefon cu simboluri"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tastatura este ascunsă"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Se afișează tastatura pentru <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"date"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"date și ore"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"adrese de e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mesaje"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"numere"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefoane"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ore"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"adrese URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Gest expresie"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Introduceți spații în timpul gesturilor, glisând pe tasta spațiu"</string> <string name="voice_input" msgid="3583258583521397548">"Tastă pentru intrarea vocală"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pe tastat. princip."</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Pe tastat. simbol."</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Dezactivată"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. pe tast. princ."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micr. pe tast. simb."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Intr. vocală dezact."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nicio metodă de intrare vocală activată. Verificați setările pentru limbă și introducere de text."</string> <string name="configure_input_method" msgid="373356270290742459">"Configuraţi metodele de intrare"</string> <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string> <string name="send_feedback" msgid="1780431884109392046">"Trimiteți feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"engleză (Regatul Unit)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"engleză (S.U.A.)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"spaniolă (S.U.A.)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engleză (Regatul Unit) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engleză (S.U.A.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spaniolă (S.U.A.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradițional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engleză (Regatul Unit) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engleză (S.U.A.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spaniolă (S.U.A.) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradițională)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Chirilică)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latină)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Nicio limbă (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Citiți fișierul de dicționar extern"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Nu există fișiere dicționar în dosarul Descărcări"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Selectați un fișier dicționar de instalat"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Doriți să instalați acest fișier pentru <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Doriți să instalați acest fișier pentru <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"A apărut o eroare"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Listați dicționar persoane contact"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Listați dicționar personal"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Listați dicționar istoric utilizator"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Listați dicționar personalizare"</string> <string name="button_default" msgid="3988017840431881491">"Prestabilit"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Bun venit la <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"cu Tastarea gestuală"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Actualizați"</string> <string name="last_update" msgid="730467549913588780">"Data ultimei modificări"</string> <string name="message_updating" msgid="4457761393932375219">"Se verifică existența actualizărilor"</string> - <string name="message_loading" msgid="8689096636874758814">"Se încarcă..."</string> + <string name="message_loading" msgid="5638680861387748936">"Se încarcă..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Dicționar principal"</string> <string name="cancel" msgid="6830980399865683324">"Anulaţi"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Setări"</string> <string name="install_dict" msgid="180852772562189365">"Instalați"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Anulați"</string> <string name="delete_dict" msgid="756853268088330054">"Ștergeți"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Limba selectată pe dispozitivul mobil are un dicționar disponibil.<br/> Vă recomandăm să <b>descărcați</b> dicționarul de <xliff:g id="LANGUAGE">%1$s</xliff:g> pentru a vă îmbunătăți experiența la introducerea textului.<br/> <br/> Descărcarea prin 3G poate dura un minut sau două. Se pot aplica taxe dacă nu aveți un <b>plan de date nelimitat</b>.<br/> Dacă nu știți sigur ce plan de date aveți, găsiți o conexiune Wi-Fi și descărcați automat.<br/> <br/> Sfat: puteți să descărcați și să eliminați dicționare accesând <b>Limbă și introducere de text</b> din meniul <b>Setări</b>, pe dispozitivul mobil."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Pentru limba selectată pe dispozitivul dvs. mobil este disponibil un dicționar.<br/> Vă recomandăm să <b>descărcați</b> dicționarul de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> pentru o mai bună experiență a introducerii de text.<br/> <br/> Descărcarea poate dura un minut sau două prin 3G. Dacă nu aveți un <b>plan de date nelimitat</b>, se pot aplica taxe.<br/> Dacă nu știți sigur ce plan de date aveți, vă recomandăm să căutați o conexiune Wi-Fi pentru a începe automat descărcarea.<br/> <br/> Sfat: puteți să descărcați și să ștergeți dicționare accesând opțiunea <b>Limbă și introducere de text</b> din meniul <b>Setări</b> al dispozitivului mobil."</string> <string name="download_over_metered" msgid="1643065851159409546">"Descărcați acum (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Descărcați prin Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Este disponibil un dicționar pentru <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Este disponibil un dicționar pentru <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Apăsați pentru examinare și descărcare"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Se descarcă: sugestiile pentru <xliff:g id="LANGUAGE">%1$s</xliff:g> vor fi gata în curând."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Se descarcă: sugestiile pentru <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> vor fi gata în curând."</string> <string name="version_text" msgid="2715354215568469385">"Versiunea <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Adăugați"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Adăugați în dicționar"</string> diff --git a/java/res/values-ru/strings-config-important-notice.xml b/java/res/values-ru/strings-config-important-notice.xml new file mode 100644 index 000000000..5e6999c1f --- /dev/null +++ b/java/res/values-ru/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Устройство будет запоминать то, что вы вводите чаще всего"</string> +</resources> diff --git a/java/res/values-ru/strings-talkback-descriptions.xml b/java/res/values-ru/strings-talkback-descriptions.xml new file mode 100644 index 000000000..7e64f11b0 --- /dev/null +++ b/java/res/values-ru/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Подключите гарнитуру, чтобы услышать пароль."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Введенный текст: %s."</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Текст не введен."</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"При нажатии клавиши <xliff:g id="KEY_NAME">%1$s</xliff:g> слово <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> будет исправлено на <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>."</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Клавиша <xliff:g id="KEY_NAME">%1$s</xliff:g> выполняет автоисправление."</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Код клавиши %d."</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Клавиша верхнего регистра."</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Верхний регистр включен. Нажмите, чтобы отключить."</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock включен. Нажмите, чтобы отключить."</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Удалить."</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Символы."</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Буквы."</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Цифры."</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Настройки."</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Клавиша Tab."</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Пробел."</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Голосовой ввод."</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Смайлики."</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Ввод."</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Поиск."</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Маркер списка."</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Сменить язык."</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Далее."</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Назад."</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Верхний регистр включен."</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock включен."</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Верхний регистр отключен."</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Режим добавления символов."</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Режим ввода текста."</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Режим набора номера."</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Режим телефонных символов."</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Клавиатура скрыта."</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Включен режим <xliff:g id="KEYBOARD_MODE">%s</xliff:g>."</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ввода даты"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ввода даты и времени"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"ввода адреса электронной почты"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ввода сообщения"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"ввода цифр"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"набора номера"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"ввода текста"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ввода времени"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"ввода URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Недавно использованные."</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Люди."</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Объекты."</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Природа."</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Места."</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Символы."</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Смайлики."</string> +</resources> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 8bbaead0a..bef248385 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"По умолчанию"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Подсказывать имена"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Подсказывать исправления на основе имен из списка контактов"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Пользовательские словари"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Ставить точки автоматически"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Вводить точку с пробелом двойным нажатием кнопки \"Пробел\"."</string> <string name="auto_cap" msgid="1719746674854628252">"Заглавные автоматически"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Рисовать линию"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Показывать подсказки"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Показывать подсказки при вводе текста"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Подключите гарнитуру, чтобы услышать пароль."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Введенный текст: %s."</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Текст не введен"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"При нажатии клавиши \"<xliff:g id="KEY">%1$s</xliff:g>\" слово \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" будет исправлено на \"<xliff:g id="CORRECTED">%3$s</xliff:g>\""</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Для клавиши \"<xliff:g id="KEY">%1$s</xliff:g>\" назначена функция автоисправления"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Код клавиши:%d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Клавиша верхнего регистра"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Верхний регистр включен (нажмите, чтобы отключить)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock включен (нажмите, чтобы отключить)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Клавиша удаления"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Клавиша символов"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Буквы"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Цифры"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Настройки"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Клавиша табуляции"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Пробел"</string> - <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_search" msgid="1247236163755920808">"Поиск"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Сменить язык"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Далее"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Верхний регистр включен"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock включен"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Верхний регистр отключен"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Режим добавления символов"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Режим ввода текста"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Режим набора номера"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Режим телефонных символов"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Клавиатура скрыта"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Включен режим <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ввода даты"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ввода даты и времени"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"ввода адреса электронной почты"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ввода сообщения"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"ввода цифр"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"набора номера"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"ввода текста"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ввода времени"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"ввода URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Непрерывный ввод фраз"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Проводите по клавише пробела после каждого слова"</string> <string name="voice_input" msgid="3583258583521397548">"Кнопка голосового ввода"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Значок на основной клавиатуре"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Значок на клавиатуре символов"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Выкл."</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Значок на основной клавиатуре"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Значок на клавиатуре символов"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Голосовой ввод откл."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Голосовой способ ввода не включен. Проверьте раздел настроек \"Язык и ввод\"."</string> <string name="configure_input_method" msgid="373356270290742459">"Настройка способов ввода"</string> <string name="language_selection_title" msgid="1651299598555326750">"Языки ввода"</string> <string name="send_feedback" msgid="1780431884109392046">"Отправить отзыв"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"английский (Великобритания)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"английский (США)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Испанский (США)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Английская (Великобр.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Английская (США) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Испанский (США): <xliff:g id="LAYOUT">%s</xliff:g>"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (традиционный)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Английский (Великобритания, <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Английский (США, <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Испанский (США, <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (классическая)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (кириллица)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (латиница)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Язык не определен (латиница)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Латиница (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Латиница (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Загрузить словарь из файла"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"В папке \"Загрузки\" нет словарей"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Выберите файл словаря"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Установить этот файл для следующего языка: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Установить этот файл для следующего языка: <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Ошибка"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Выгрузить словарь контактов"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Выгрузить личный словарь"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Выгрузить словарь польз. истории"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Выгрузить словарь персонализации"</string> <string name="button_default" msgid="3988017840431881491">"По умолчанию"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Представляем приложение \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\""</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"с непрерывным вводом"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Обновить"</string> <string name="last_update" msgid="730467549913588780">"Последнее обновление"</string> <string name="message_updating" msgid="4457761393932375219">"Проверка обновлений…"</string> - <string name="message_loading" msgid="8689096636874758814">"Загрузка..."</string> + <string name="message_loading" msgid="5638680861387748936">"Загрузка…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Основной словарь"</string> <string name="cancel" msgid="6830980399865683324">"Отмена"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Настройки"</string> <string name="install_dict" msgid="180852772562189365">"Установить"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Отмена"</string> <string name="delete_dict" msgid="756853268088330054">"Удалить"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Доступен <xliff:g id="LANGUAGE">%1$s</xliff:g> словарь для проверки правописания.<br/>Рекомендуем <b>установить</b> его, чтобы быстрее вводить текст.<br/><br/>Если вашим тарифом предусмотрена <b>безлимитная передача данных</b>, словарь можно загрузить через сеть 3G (это займет всего пару минут).<br/>Если вы не помните подробностей своего тарифного плана, лучше подключитесь к сети Wi-Fi (загрузка начнется автоматически).<br/><br/>Совет. Чтобы добавить, удалить или настроить словарь, откройте раздел <b>Язык и ввод</b> в настройках своего устройства."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Доступен словарь для проверки правописания (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>).<br/>Рекомендуем <b>установить</b> его, чтобы быстрее вводить текст.<br/><br/>Если вашим тарифом предусмотрена <b>безлимитная передача данных</b>, словарь можно загрузить через сеть 3G (это займет всего пару минут).<br/>Если вы не помните подробностей своего тарифного плана, лучше подключитесь к сети Wi-Fi (загрузка начнется автоматически).<br/><br/>Совет. Чтобы добавлять, удалять и настраивать словари, откройте раздел <b>Язык и ввод</b> в настройках устройства."</string> <string name="download_over_metered" msgid="1643065851159409546">"Загрузить (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> МБ)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Загрузить через Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Доступен словарь: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Доступен словарь: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Нажмите, чтобы просмотреть и загрузить"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Загрузка словаря: <xliff:g id="LANGUAGE">%1$s</xliff:g>…"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Загрузка словаря (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>)…"</string> <string name="version_text" msgid="2715354215568469385">"Версия <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Добавить"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Добавление в словарь"</string> diff --git a/java/res/values-sk/strings-config-important-notice.xml b/java/res/values-sk/strings-config-important-notice.xml new file mode 100644 index 000000000..9b15ac992 --- /dev/null +++ b/java/res/values-sk/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Zlepšovať návrhy na základe komunikácie a zadaných údajov"</string> +</resources> diff --git a/java/res/values-sk/strings-talkback-descriptions.xml b/java/res/values-sk/strings-talkback-descriptions.xml new file mode 100644 index 000000000..605aceb38 --- /dev/null +++ b/java/res/values-sk/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Ak si chcete pri zadávaní hesla vypočuť nahlas vyslovené klávesy, pripojte náhlavnú súpravu."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Aktuálny text je %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Nie je zadaný žiadny text"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Klávesom <xliff:g id="KEY_NAME">%1$s</xliff:g> opravíte slovo <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Klávesom <xliff:g id="KEY_NAME">%1$s</xliff:g> spustíte automatické opravy"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Kód klávesa %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Kláves Shift je zapnutý (zakážete ho klepnutím)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Kláves Caps Lock je zapnutý (zakážete ho klepnutím)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Odstrániť"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboly"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Písmená"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Čísla"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Nastavenia"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Karta"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Medzerník"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Hlasový vstup"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Hľadať"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Bodka"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Prepnúť jazyk"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Ďalej"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Naspäť"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Kláves Shift je povolený"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Kláves Caps Lock je povolený"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Kláves Shift je zakázaný"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Režim symbolov"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Režim písmen"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Režim telefónu"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Režim telefónnych symbolov"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klávesnica je skrytá"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Je zobrazená klávesnica <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"dátum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"dátum a čas"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-mail"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"odosielanie správ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"číslo"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefón"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"čas"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"Adresa URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Nedávne"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Ľudia"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Predmety"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Príroda"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Miesta"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboly"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Emotikony"</string> +</resources> diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index d1f966cea..9a3564782 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Predvolené nastav."</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhnúť mená kontaktov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Používať mená z Kontaktov na návrhy a opravy"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Prispôsobené návrhy"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Bodka s medzerou"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dvojitým klepnutím na medzerník vložíte bodku a medzeru."</string> <string name="auto_cap" msgid="1719746674854628252">"Veľké písmená automaticky"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Zobrazovať stopu gesta"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamická plávajúca ukážka"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Zobrazenie navrhovaného slova pri písaní gestami"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Ak si chcete pri zadávaní hesla vypočuť nahlas vyslovené klávesy, pripojte náhlavnú súpravu."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Aktuálny text je %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Nie je zadaný žiadny text"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Klávesom <xliff:g id="KEY">%1$s</xliff:g> opravíte slovo <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> na <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Klávesom <xliff:g id="KEY">%1$s</xliff:g> spustíte automatické opravy"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Kód klávesu %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Kláves Shift je zapnutý (zakážete ho klepnutím)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Kláves Caps Lock je zapnutý (zakážete ho klepnutím)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboly"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Písmená"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Čísla"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Nastavenia"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Karta"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Medzerník"</string> - <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_search" msgid="1247236163755920808">"Hľadať"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Bodka"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Prepnúť jazyk"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Ďalšie"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Predchádzajúce"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Kláves Shift je povolený"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kláves Caps Lock je povolený"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Kláves Shift je zakázaný"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Režim symbolov"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Režim písmen"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Režim telefónu"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Režim telefónnych symbolov"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klávesnica je skrytá"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Zobrazenie klávesnice v režime <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"dátum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"dátum a čas"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mail"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"odosielanie správ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"číslo"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefón"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"Adresa URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frázové gesto"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Medzery medzi gestá vložíte prejdením po klávese medzerníka"</string> <string name="voice_input" msgid="3583258583521397548">"Kľúč hlasového vstupu"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na hlavnej klávesnici"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klávesnici so symbolmi"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Vypnuté"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofón na hlavnej klávesnici"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofón na klávesnici so symbolmi"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hlasový vstup je zakázaný"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie sú povolené žiadne metódy hlasového vstupu. Skontrolujte nastavenia položky Jazyk a vstup."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurovať metódy vstupu"</string> <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string> <string name="send_feedback" msgid="1780431884109392046">"Odoslať spätnú väzbu"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"španielčina (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angličtina (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"angličtina (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"španielčina (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradičná)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"angličtina (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"angličtina (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"španielčina (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradičná)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cyrilika)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinka)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Žiadny jazyk (latinka)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Latinka (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Latinka (QWERTZ)"</string> @@ -166,10 +123,14 @@ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trvanie vibrov. pri stlač. kl."</string> <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Hlasitosť pri stlačení klávesu"</string> <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Čítať súbor externého slovníka"</string> - <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"V priečinku Preberanie nie sú žiadne súbory slovníka"</string> + <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"V priečinku Sťahovanie nie sú žiadne súbory slovníka"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Vyberte súbor slovníka, ktorý chcete nainštalovať"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Chcete nainštalovať tento súbor pre jazyk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Chcete nainštalovať tento súbor pre jazyk <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Vyskytla sa chyba"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Vypísať slovník kontaktov"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Vypísať osobný slovník"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Vypísať slovník histór. používateľa"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Vypísať slovník prispôsobení"</string> <string name="button_default" msgid="3988017840431881491">"Predvolené"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Vitajte v aplikácii <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"s funkciou Písanie gestami"</string> @@ -199,7 +160,7 @@ <string name="user_dictionaries" msgid="3582332055892252845">"Používateľské slovníky"</string> <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Používateľský slovník"</string> <string name="dictionary_available" msgid="4728975345815214218">"K dispozícii je slovník"</string> - <string name="dictionary_downloading" msgid="2982650524622620983">"Aktuálne sa preberá"</string> + <string name="dictionary_downloading" msgid="2982650524622620983">"Aktuálne sa sťahuje"</string> <string name="dictionary_installed" msgid="8081558343559342962">"Nainštalované"</string> <string name="dictionary_disabled" msgid="8950383219564621762">"Nainštalovaný, zakázaný"</string> <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Probl. s prip. k sl."</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Obnoviť"</string> <string name="last_update" msgid="730467549913588780">"Posledná aktualizácia"</string> <string name="message_updating" msgid="4457761393932375219">"Prebieha kontrola aktualizácií"</string> - <string name="message_loading" msgid="8689096636874758814">"Načítava sa..."</string> + <string name="message_loading" msgid="5638680861387748936">"Prebieha načítavanie..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Hlavný slovník"</string> <string name="cancel" msgid="6830980399865683324">"Zrušiť"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Nastavenia"</string> <string name="install_dict" msgid="180852772562189365">"Inštalovať"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Zrušiť"</string> <string name="delete_dict" msgid="756853268088330054">"Odstrániť"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Pre vybratý jazyk mobilného zariadenia je k dispozícii slovník.<br/> Slovník jazyka <xliff:g id="LANGUAGE">%1$s</xliff:g> vám odporúčame <b>prevziať</b>. Pomôže vám pri zadávaní textu.<br/> <br/> V sieti 3G môže preberanie chvíľu trvať. Ak nemáte <b>neobmedzený dátový program</b>, môžu sa účtovať poplatky.<br/> Ak s určitosťou neviete aký dátový program používate, vyhľadajte pripojenie k sieti Wi-Fi a preberanie sa spustí automaticky.<br/> <br/> Tip: Slovníky môžete v mobilnom zariadení preberať a odstraňovať v časti <b>Jazyk a vstup</b> ponuky <b>Nastavenia</b>."</string> - <string name="download_over_metered" msgid="1643065851159409546">"Prevziať (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> - <string name="do_not_download_over_metered" msgid="2176209579313941583">"Prevziať cez sieť Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"K dispozícii je slovník pre jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Pre vybratý jazyk mobilného zariadenia je k dispozícii slovník.<br/> Slovník jazyka <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> vám odporúčame <b>stiahnuť</b>. Pomôže vám pri zadávaní textu.<br/> <br/> V sieti 3G môže sťahovanie trvať jednu až dve minúty. Ak nemáte <b>neobmedzený dátový program</b>, môžu sa účtovať poplatky.<br/> Ak s určitosťou neviete aký dátový program používate, vyhľadajte pripojenie k sieti Wi-Fi a sťahovanie sa spustí automaticky.<br/> <br/> Tip: Slovníky môžete v mobilnom zariadení sťahovať a odstraňovať v časti <b>Jazyk a vstup</b> ponuky <b>Nastavenia</b>."</string> + <string name="download_over_metered" msgid="1643065851159409546">"Stiahnuť (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> + <string name="do_not_download_over_metered" msgid="2176209579313941583">"Stiahnuť cez sieť Wi-Fi"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"K dispozícii je slovník pre jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Stlačením skontrolujete a prevezmete"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Preberanie: návrhy pre jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> budú čoskoro k dispozícii."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Sťahovanie: návrhy pre jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> budú čoskoro k dispozícii."</string> <string name="version_text" msgid="2715354215568469385">"Verzia <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Pridať"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Pridať do slovníka"</string> diff --git a/java/res/values-sl/strings-config-important-notice.xml b/java/res/values-sl/strings-config-important-notice.xml new file mode 100644 index 000000000..d5bed6fd8 --- /dev/null +++ b/java/res/values-sl/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Vaša sporočila in vnesene podatke uporabi za boljše predloge"</string> +</resources> diff --git a/java/res/values-sl/strings-talkback-descriptions.xml b/java/res/values-sl/strings-talkback-descriptions.xml new file mode 100644 index 000000000..280393a70 --- /dev/null +++ b/java/res/values-sl/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Priključite slušalke, če želite slišati izgovorjene tipke gesla."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Trenutno besedilo je %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Ni vnesenega besedila"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Tipka <xliff:g id="KEY_NAME">%1$s</xliff:g> popravi <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> v <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Tipka <xliff:g id="KEY_NAME">%1$s</xliff:g> izvede samopopravek"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Koda tipke %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Tipka Shift je vklopljena (dotaknite se, da jo onemogočite)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Tipka Caps lock je vklopljena (dotaknite se, da jo onemogočite)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Izbriši"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simboli"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Črke"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Števila"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Nastavitve"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Preslednica"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Glasovni vnos"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Znaki »emoji«"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Iskanje"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Pika"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Preklop jezika"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Naprej"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Nazaj"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Način »Shift« je omogočen"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Funkcija »Caps Lock« je omogočena"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Način »Shift« je onemogočen"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Način simbolov"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Način črk"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Način telefona"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Način simbolov telefona"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tipkovnica je skrita"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Prikaz tipkovnice <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum in ura"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-pošta"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"sporočila"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"števila"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"besedilo"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"ura"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Nedavni"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Osebe"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Predmeti"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Narava"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Mesta"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simboli"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Čustveni simboli"</string> +</resources> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index a0f83c12f..2594aaec4 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Privzeto v sistemu"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlagaj imena stikov"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Uporaba imen iz stikov za predloge in popravke"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Prilagojeni predlogi"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dva presl. za vnos pike"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Z dvojnim dotikom preslednice vstavite piko in za njo presledek"</string> <string name="auto_cap" msgid="1719746674854628252">"Samod. velike začetnice"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Prikaži pot poteze"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamični plavajoči predogled"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Prikaz predlagane besede med vnosom s prstom"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Priključite slušalke, če želite slišati izgovorjene tipke gesla."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Trenutno besedilo je %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Ni vnesenega besedila"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Tipka <xliff:g id="KEY">%1$s</xliff:g> popravi <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> v <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Tipka <xliff:g id="KEY">%1$s</xliff:g> izvede samodejno popravljanje"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Koda tipke %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift je vklopljen (dotaknite se, da onemogočite)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock je vklopljen (dotaknite se, da onemogočite)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simboli"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Pisma"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Številke"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Nastavitve"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulator"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Presledek"</string> - <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_search" msgid="1247236163755920808">"Iskanje"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Pika"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Preklop jezika"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Naprej"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Nazaj"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Način »Shift« je omogočen"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Način »Caps Lock« je omogočen"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Način »Shift« je onemogočen"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Način simbolov"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Način črk"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Način telefona"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Način simbolov telefona"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tipkovnica je skrita"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Prikaz tipkovnice: <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum in ura"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-pošta"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"sporočila"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"števila"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"besedilo"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"ura"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Vnos besed s potezami"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Vnos presledkov pri vnašanju s potezami z drsenjem po preslednici"</string> <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni vnos"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na glavni tipkovnici"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na tipk. s simboli"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Izklopljeno"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. na glavni tipk."</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. na tipk. s sim."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Glas. vnos je onem."</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ni omogočenih glasovnih načinov vnosa. Preverite nastavitve v razdelku »Jezik in vnos«."</string> <string name="configure_input_method" msgid="373356270290742459">"Nastavitev načinov vnosa"</string> <string name="language_selection_title" msgid="1651299598555326750">"Jeziki vnosa"</string> <string name="send_feedback" msgid="1780431884109392046">"Pošljite povratne informacije"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"španščina (ZDA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Angleška (Zdr. kralj.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Angleška (ZDA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"španščina (ZDA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (tradicionalna)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"angleščina (VB) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"angleščina (ZDA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"španščina (ZDA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionalna)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cirilica)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinica)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Brez jezika (latinice)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Latinica (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Latinica (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Branje zunanje datoteke slovarja"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"V mapi »Prenosi« ni nobene datoteke slovarja"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Izberite datoteko slovarja, ki jo želite namestiti"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Zares želite namestiti to datoteko za jezik <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Zares želite namestiti to datoteko za ta jezik: <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Prišlo je do napake"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Izpis slovarja stikov"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Izvoz osebnega slovarja"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Izvoz slovarja zgodovine uporabnika"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Izvoz slovarja za prilagajanje"</string> <string name="button_default" msgid="3988017840431881491">"Privzeto"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Pozdravljeni v aplikaciji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"s pisanjem s kretnjami"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Osveži"</string> <string name="last_update" msgid="730467549913588780">"Nazadnje posodobljeno"</string> <string name="message_updating" msgid="4457761393932375219">"Iskanje posodobitev"</string> - <string name="message_loading" msgid="8689096636874758814">"Nalaganje ..."</string> + <string name="message_loading" msgid="5638680861387748936">"Nalaganje …"</string> <string name="main_dict_description" msgid="3072821352793492143">"Glavni slovar"</string> <string name="cancel" msgid="6830980399865683324">"Prekliči"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Nastavitve"</string> <string name="install_dict" msgid="180852772562189365">"Namesti"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Prekliči"</string> <string name="delete_dict" msgid="756853268088330054">"Izbriši"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Za izbrani jezik v mobilni napravi je na voljo slovar.<br/> Za izboljšano izkušnjo tipkanja priporočamo, da <b>prenesete</b> slovar za ta jezik: <xliff:g id="LANGUAGE">%1$s</xliff:g>.<br/> <br/> Prenos prek povezave 3G lahko traja minuto ali dve. Če nimate <b>neomejenega podatkovnega paketa</b>.<br/>, boste morda morali plačati prenos podatkov. Če ne veste, kateri podatkovni paket imate, priporočamo, da poiščete omrežje Wi-Fi in prenos začnete samodejno.<br/> <br/> Nasvet: Slovarje lahko prenesete in odstranite tako, da v meniju <b>Nastavitve</b> v mobilni napravi odprete <b>Jezik in vnos</b>."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Za izbrani jezik v mobilni napravi je na voljo slovar.<br/> Za izboljšano izkušnjo tipkanja priporočamo, da <b>prenesete</b> slovar za ta jezik: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>.<br/> <br/> Prenos prek povezave 3G lahko traja minuto ali dve. Če nimate <b>neomejenega podatkovnega paketa</b>.<br/>, boste morda morali plačati prenos podatkov. Če ne veste, kateri podatkovni paket imate, priporočamo, da poiščete omrežje Wi-Fi in prenos začnete samodejno.<br/> <br/> Nasvet: slovarje lahko prenesete in odstranite tako, da v meniju <b>Nastavitve</b> v mobilni napravi odprete <b>Jezik in vnos</b>."</string> <string name="download_over_metered" msgid="1643065851159409546">"Prenesi zdaj (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Prenos prek povezave Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Slovar je na voljo za jezik <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Na voljo je slovar za ta jezik: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pritisnite za pregled in prenos"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Predlogi za prenos za jezik <xliff:g id="LANGUAGE">%1$s</xliff:g> bodo kmalu pripravljeni."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Prenos: predlogi za jezik <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> bodo kmalu na voljo."</string> <string name="version_text" msgid="2715354215568469385">"Različica <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Dodaj"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Dodaj v slovar"</string> diff --git a/java/res/values-sr/strings-config-important-notice.xml b/java/res/values-sr/strings-config-important-notice.xml new file mode 100644 index 000000000..943135cfd --- /dev/null +++ b/java/res/values-sr/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Користи комуникације и унете податке ради побољшања предлога"</string> +</resources> diff --git a/java/res/values-sr/strings-talkback-descriptions.xml b/java/res/values-sr/strings-talkback-descriptions.xml new file mode 100644 index 000000000..402d45b91 --- /dev/null +++ b/java/res/values-sr/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Укључите слушалице да бисте чули наглас изговорене тастере за лозинку."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Тренутни текст је %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Текст није унет"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> исправља <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> у <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> обавља аутоматско исправљање"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Кôд тастера %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift је укључен (додирните да бисте га онемогућили)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock је укључен (додирните да бисте га онемогућили)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Избриши"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Симболи"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Слова"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Бројеви"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Подешавања"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Картица"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Размак"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Гласовни унос"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Емоџи"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Претражи"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Тачка"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Пребаци језик"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Претходно"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Следеће"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift је омогућен"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock је омогућен"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift је онемогућен"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Режим симбола"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Режим слова"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Режим телефона"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Режим симбола телефона"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Тастатура је сакривена"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Приказујемо тастатуру у режиму <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"датум"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"датум и време"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"имејл"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"размена порука"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"број"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"телефон"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"текст"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"време"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Недавни контакти"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Људи"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Предмети"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Природа"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Места"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Симболи"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Емотикони"</string> +</resources> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index ce4978ff5..7bd7f67e5 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Подразумевано"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Персонализовани предлози"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Двоструким додиром размака умеће се тачка праћена размаком"</string> <string name="auto_cap" msgid="1719746674854628252">"Аутоматски унос великих слова"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Прикажи траг покрета"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамички плутајући преглед"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Приказује предложену реч при уносу покретом"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Укључите слушалице да бисте чули наглас изговорене тастере за лозинку."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Тренутни текст је %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Текст није унет"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> исправља <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> у <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> обавља функцију аутоматског исправљања"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Кôд тастера %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift је укључен (додирните да бисте га онемогућили)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock је укључен (додирните да бисте га онемогућили)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Симболи"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Слова"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Бројеви"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Подешавања"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Размак"</string> - <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_search" msgid="1247236163755920808">"Претражи"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Тачка"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Пребаци језик"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Следеће"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Претходно"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift је омогућен"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock је омогућен"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift је онемогућен"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Режим симбола"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Режим слова"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Режим телефона"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Режим симбола телефона"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Тастатура је сакривена"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Приказује се тастатура у режиму <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"датум"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"датум и време"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"адреса е-поште"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"размена порука"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"број"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"телефон"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"текст"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"време"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Покрет за фразе"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Уносите размаке током покрета преласком до тастера за размак"</string> <string name="voice_input" msgid="3583258583521397548">"Тастер за гласовни унос"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На главној тастатури"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"На тастатури са симболима"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Искључи"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Микрофон на главној тастатури"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Микрофон на тастатури са симболима"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Гласовни унос је онемогућен"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ниједан метод гласовног уноса није омогућен. Проверите Подешавања језика и уноса."</string> <string name="configure_input_method" msgid="373356270290742459">"Конфигурисање метода уноса"</string> <string name="language_selection_title" msgid="1651299598555326750">"Језици за унос"</string> <string name="send_feedback" msgid="1780431884109392046">"Пошаљи повратне информације"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"енглески (УК)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"енглески (САД)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"шпански (САД)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"енглески (УК) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"енглески (САД) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"шпански (САД) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (традиционални)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"енглески (УК) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"енглески (САД) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"шпански (САД) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (традиционални)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ћирилица)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (латиница)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Нема језика (абецеда)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Абецеда (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Абецеда (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Читање датотеке спољног речника"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"У директоријуму Преузимања нема датотека речника"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Избор датотеке речника за инсталирање"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Желите ли стварно да инсталирате ову датотеку за <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Желите ли стварно да инсталирате ову датотеку за <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Дошло је до грешке"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Направи сирову копију речника контаката"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Направи сирову копију личног речника"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Направи сирову копију речника историје корисника"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Направи сирову копију персонализованог речника"</string> <string name="button_default" msgid="3988017840431881491">"Подразумевано"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Добро дошли у <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"помоћу Куцања покретима"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Освежи"</string> <string name="last_update" msgid="730467549913588780">"Последње ажурирање"</string> <string name="message_updating" msgid="4457761393932375219">"Тражење ажурирања"</string> - <string name="message_loading" msgid="8689096636874758814">"Учитавање..."</string> + <string name="message_loading" msgid="5638680861387748936">"Учитавање…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Главни речник"</string> <string name="cancel" msgid="6830980399865683324">"Откажи"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Подешавања"</string> <string name="install_dict" msgid="180852772562189365">"Инсталирај"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Откажи"</string> <string name="delete_dict" msgid="756853268088330054">"Избриши"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Доступан је речник за изабрани језик на мобилном уређају.<br/> Препоручујемо да <b>преузмете </b> речник за <xliff:g id="LANGUAGE">%1$s</xliff:g> да бисте побољшали доживљај куцања.<br/> <br/> Преузимање може да траје минут или два преко 3G мреже. Трошкови ће можда бити наплаћени ако немате <b>претплатнички пакет без ограничења</b>.<br/> Ако нисте сигурни који претплатнички пакет имате, препоручујемо да пронађете Wi-Fi везу да бисте аутоматски започели преузимање.<br/> <br/> Савет: Речнике можете да преузимате и уклањате тако што ћете посетити <b>Језик и унос</b> у менију <b>Подешавања</b> мобилног уређаја."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Доступан је речник за изабрани језик на мобилном уређају.<br/> Препоручујемо вам да <b>преузмете</b> речник за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> да бисте побољшали доживљај куцања.<br/> <br/> Преузимање може да траје минут или два преко 3G мреже. Трошкови ће можда бити наплаћени ако немате <b>претплатнички пакет без ограничења</b>.<br/> Ако нисте сигурни који претплатнички пакет имате, препоручујемо вам да пронађете Wi-Fi везу да бисте аутоматски започели преузимање.<br/> <br/> Савет: Речнике можете да преузимате и уклањате ако одете на <b>Језик и унос</b> у менију <b>Подешавања</b> на мобилном уређају."</string> <string name="download_over_metered" msgid="1643065851159409546">"Преузми одмах (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Преузми преко Wi-Fi-ја"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Речник је доступан за <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Доступан је речник за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Притисните за преглед и преузимање"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Преузимање: Предлози за <xliff:g id="LANGUAGE">%1$s</xliff:g> ће ускоро бити спремни."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Преузимање: Предлози за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ће ускоро бити спремни."</string> <string name="version_text" msgid="2715354215568469385">"Верзија <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Додај"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Додавање у речник"</string> diff --git a/java/res/values-sv/strings-config-important-notice.xml b/java/res/values-sv/strings-config-important-notice.xml new file mode 100644 index 000000000..9b9b92e46 --- /dev/null +++ b/java/res/values-sv/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Få bättre förslag genom att använda tidigare angiven data och annan kommunikation"</string> +</resources> diff --git a/java/res/values-sv/strings-talkback-descriptions.xml b/java/res/values-sv/strings-talkback-descriptions.xml new file mode 100644 index 000000000..140202d99 --- /dev/null +++ b/java/res/values-sv/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Anslut hörlurar om du vill att lösenordet ska läsas upp."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Nuvarande text är %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Ingen text har angetts"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Om du trycker på <xliff:g id="KEY_NAME">%1$s</xliff:g> rättas <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> till <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Om du trycker på <xliff:g id="KEY_NAME">%1$s</xliff:g> utförs autokorrigering"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Nyckelkod %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Skift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Skift är aktiverat (tryck för att inaktivera)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock på (tryck för att inaktivera)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Ta bort"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Symboler"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Bokstäver"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Siffror"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Inställningar"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tabb"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Blanksteg"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Röstindata"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Retur"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Sökning"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Punkt"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Byt språk"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Nästa"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Föregående"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Skift aktiverat"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock är aktiverat"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Skift är inaktiverat"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbolläge"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Bokstavsläge"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefonläge"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefonsymbolläge"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Tangentbordet är dolt"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Tangentbord för <xliff:g id="KEYBOARD_MODE">%s</xliff:g> visas"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"datum"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"datum och tid"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-post"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"sms/mms"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"siffror"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefonnummer"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"text"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"klockslag"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"webbadresser"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Senaste"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Personer"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Föremål"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Natur"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Platser"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Symboler"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Uttryckssymboler"</string> +</resources> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index afe349afd..7092e6876 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Standardinställning"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Föreslå kontaktnamn"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Använd namn från Kontakter för förslag och korrigeringar"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Anpassade förslag"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelt blanksteg = punkt"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Dubbelt blanksteg ger en punkt följt av mellanslag"</string> <string name="auto_cap" msgid="1719746674854628252">"Automatiska versaler"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Visa spår efter rörelse"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Visa ordförslag vid svepskrivning"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Ordförslaget visas i rörelsen medan du skriver"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Anslut hörlurar om du vill att lösenordet ska läsas upp."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Nuvarande text är %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Ingen text har angetts"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Om du trycker på <xliff:g id="KEY">%1$s</xliff:g> rättas <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> till <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Om du trycker på <xliff:g id="KEY">%1$s</xliff:g> utförs autokorrigering"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Nyckelkod %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Skift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Skift på (knacka lätt för att inaktivera)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock på (knacka lätt för att inaktivera)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboler"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Bokstäver"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Siffror"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Inställningar"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tabb"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Blanksteg"</string> - <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_search" msgid="1247236163755920808">"Sök"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Byt språk"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Nästa"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Föregående"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Skift är aktiverat"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock är aktiverat"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Skift är inaktiverat"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolläge"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Bokstavsläge"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefonläge"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefonsymbolläge"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Tangentbordet är dolt"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Tangentbord för <xliff:g id="MODE">%s</xliff:g> visas"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"datum"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"datum och tid"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-post"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"sms"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"siffror"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefonnummer"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"klockslag"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"webbadresser"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Frasrörelse"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Infoga blanksteg genom att dra fingret över blankstegstangenten"</string> <string name="voice_input" msgid="3583258583521397548">"Röstinmatningsknapp"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"På huvudtangentbord"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"På symboltangentbord"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Av"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mick huvudtangentbord"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mick bland symboler"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Röstinmatning inaktiv"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen röstinmatningsmetod har aktiverats. Kontrollera språk- och inmatningsinställningarna."</string> <string name="configure_input_method" msgid="373356270290742459">"Konfigurera inmatningsmetoder"</string> <string name="language_selection_title" msgid="1651299598555326750">"Inmatningsspråk"</string> <string name="send_feedback" msgid="1780431884109392046">"Skicka feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Engelskt (brittiskt)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelskt (amerikanskt)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"spanska (USA)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Engelskt (brittiskt) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Engelskt (amerikanskt) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"spanska (USA (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (traditionell)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Engelska (Storbritannien) <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Engelska (USA) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spanska (USA (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionell)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (kyrillisk)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (latinsk)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Inget språk (alfabet)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabet (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabet (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Läs extern ordboksfil"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Inga ordboksfiler i mappen Hämtningar"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Välj en ordboksfil att installera"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Vill du verkligen installera filen för <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Vill du verkligen installera filen för <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Ett fel uppstod"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Ta fram ordlista för kontakter"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Dumpa personlig ordlista"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Dumpa ordlista för användarhistorik"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Dumpa anpassad ordlista"</string> <string name="button_default" msgid="3988017840431881491">"Standard"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Välkommen till <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"med svepskrivning"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Uppdatera"</string> <string name="last_update" msgid="730467549913588780">"Informationen uppdaterades senast"</string> <string name="message_updating" msgid="4457761393932375219">"Söker efter uppdateringar"</string> - <string name="message_loading" msgid="8689096636874758814">"Läser in ..."</string> + <string name="message_loading" msgid="5638680861387748936">"Läser in …"</string> <string name="main_dict_description" msgid="3072821352793492143">"Huvudordlista"</string> <string name="cancel" msgid="6830980399865683324">"Avbryt"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Inställningar"</string> <string name="install_dict" msgid="180852772562189365">"Installera"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Avbryt"</string> <string name="delete_dict" msgid="756853268088330054">"Ta bort"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Det finns en ordlista för språket du har valt i din mobila enhet.<br/> Vi rekommenderar att du <b>hämtar</b> ordlistan för <xliff:g id="LANGUAGE">%1$s</xliff:g> så att det blir enklare att skriva.<br/> <br/> Det kan ta någon minut att hämta den via 3G. Avgifter kan tillkomma om du inte har ett abonnemang med <b>obegränsad datatrafik</b>.<br/> Om du är osäker på vilket abonnemang du har rekommenderar vi att du ansluter till ett Wi-Fi-nätverk och hämtar ordlistan automatiskt.<br/> <br/> Tips! Du kan hämta och ta bort ordlistor under <b>Språk och inmatning</b> i menyn <b>Inställningar</b> på den mobila enheten."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Det finns en ordbok för språket du har valt på din mobila enhet.<br/> Vi rekommenderar att du <b>hämtar</b> ordboken på <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Då blir det enklare och smidigare att skriva.<br/> <br/> Hämtningen tar en minut eller två om du använder 3G. Avgifter kan tillkomma om du inte har ett <b>abonnemang med obegränsad data</b>.<br/> Om du inte är säker på vad som ingår i ditt abonnemang rekommenderar vi att du hittar en Wi-Fi-anslutning och påbörjar hämtningen automatiskt.<br/> <br/> Tips: Du kan hämta och ta bort ordböcker via <b>Språk och inmatning</b> i menyn <b>Inställningar</b> på din mobila enhet."</string> <string name="download_over_metered" msgid="1643065851159409546">"Hämta nu (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Hämta via Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"En ordlista är tillgänglig för <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"En ordlista för <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> är tillgänglig"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Tryck om du vill granska och hämta"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Hämtar: förslag för <xliff:g id="LANGUAGE">%1$s</xliff:g> är snart klara."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Hämtar: förslag för <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> är snart klara."</string> <string name="version_text" msgid="2715354215568469385">"Version <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Lägg till"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Lägg till i ordlista"</string> diff --git a/java/res/values-sw/strings-config-important-notice.xml b/java/res/values-sw/strings-config-important-notice.xml new file mode 100644 index 000000000..7b10085b5 --- /dev/null +++ b/java/res/values-sw/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Jifunze kutoka kwenye mawasiliano yako na data iliyocharazwa ili kuboresha mapendekezo"</string> +</resources> diff --git a/java/res/values-sw/strings-talkback-descriptions.xml b/java/res/values-sw/strings-talkback-descriptions.xml new file mode 100644 index 000000000..e9ca282b9 --- /dev/null +++ b/java/res/values-sw/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Chomeka kifaa cha sauti ili usikie vitufe vya nenosiri vikitamkwa kwa sauti."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Maandishi ya sasa ni %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Hakuna maandishi yaliyoingizwa"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> hurekebisha <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> kuwa <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> hufanya marekebisho otomatiki"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Msimbo wa kitufe %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift imewashwa (gonga ili kuizima)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock imewashwa (gonga ili kuizima)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Futa"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Alama"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Herufi"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Nambari"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Mipangilio"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Kichupo"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Nafasi"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Kuweka data kwa kutamka"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Rudi"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Utafutaji"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Nukta"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Badilisha lugha"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Linalofuata"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Iililotangulia"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift imewashwa"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps lock imewashwa"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift imezimwa"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Hali ya alama"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Hali ya herufi"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Hali ya simu"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Hali ya alama za simu"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Kibodi imefichwa"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Inaonyesha kibodi ya <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"tarehe"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"tarehe na wakati"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"barua pepe"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"utumaji ujumbe"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"nambari"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"simu"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"maandishi"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"wakati"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Zilizotumika majuzi"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Watu"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Vitu"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Maumbile"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Maeneo"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Alama"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Vikaragosi"</string> +</resources> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 191ad977c..56312899d 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Chaguo-msingi la mfumo"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Pendekeza majini ya Anwani"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Tumia majina kutoka kwa Anwani kwa mapendekezo na marekebisho"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Mapendekezo yaliyobadilishwa kukufaa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Kitone baada ya nafasi mbili"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Kugonga mara mbili kwenye upau nafasi kunaingiza kitone kikifuatiwa na nafasi"</string> <string name="auto_cap" msgid="1719746674854628252">"Uwekaji wa herufi kubwa kiotomatiki"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Onyesha njia ya ishara"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Kihakiki kinachobadilika cha kuelea"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Onyesha neno lililopendekezwa unapoonyesha ishara"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Chomeka plagi ya kifaa cha kichwa cha kusikiza ili kusikiliza msimbo wa nenosiri inayozungumwa kwa sauti ya juu."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Maandishi ya sasa ni %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Hakuna maandishi yaliyoingizwa"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> hurekebisha <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> kuwa <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> hurekebisha kiotomatiki"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Msimbo wa kitufe %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Badilisha"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift imewashwa (gonga ili kulemaza)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock imewashwa (gonga ili kulemaza)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Futa"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Alama"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Herufi"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Nambari"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Mipangilio"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Kichupo"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Nafasi"</string> - <string name="spoken_description_mic" msgid="615536748882611950">"Kuweka data kwa kutamka"</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_search" msgid="1247236163755920808">"Tafuta"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Nukta"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Badili lugha"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Inayofuata"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Iliyotangulia"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift imewezeshwa"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock imewezeshwa"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift imelemazwa"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Hali ya alama"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Hali ya barua"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Hali ya simu"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Hali ya alama za simu"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Kibodi imefichwa"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Inaonyesha kibodi <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"tarehe"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"tarehe na wakati"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"barua pepe"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"Utumaji ujumbe"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"nambari"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"simu"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"maandishi"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"wakati"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Ishara ya fungu la maneno"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Weka nafasi wakati wa ishara kwa kuelea katika kitufe cha nafasi"</string> <string name="voice_input" msgid="3583258583521397548">"Kibao cha kuweka data kwa kutamka"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Kwenye kibodi kuu"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Kwenye kibodi ya ishara"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Zima"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Maikrofoni kwenye kibodi kuu"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Maikrofoni kwenye kibodi ya ishara"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Kipengele cha kuweka data kwa kutamka kimezimwa"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Hakuna mbinu ya kuweka data kwa kutamka iliyowashwa. Angalia Lugha na mipangilio ya kuingiza data."</string> <string name="configure_input_method" msgid="373356270290742459">"Sanidi mbinu za uingizaji"</string> <string name="language_selection_title" msgid="1651299598555326750">"Lugha za uingizaji"</string> <string name="send_feedback" msgid="1780431884109392046">"Tuma maoni"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Kiingereza cha (Uingereza)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Kiingereza cha (Marekani)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Kihispania (Marekani)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Kiingereza (Uingereza) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Kiingereza (Marekani) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Kihispania (Marekani) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Asili)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Kiingereza (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Kiingereza (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Kihispania (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cha Jadi)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Kikriliki)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Kilatini)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Hakuna lugha (Alfabeti)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabeti (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabeti (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Soma faili ya kamusi ya nje"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Hakuna faili za kamusi katika folda ya Vilivyopakuliwa"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Chagua faili ya kamusi ya kusakinisha"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Isakinishe faili hii kwa <xliff:g id="LOCALE_NAME">%s</xliff:g> kweli?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Ungependa kusakinisha faili hii ya <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Kulikuwa na hitilafu"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Onyesha orodha ya anwani"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Tupa kamusi ya kibinafsi"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Tupa kamusi ya historia ya mtumiaji"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Tupa kamusi ya kuwekewa mapendeleo"</string> <string name="button_default" msgid="3988017840431881491">"Chaguo-msingi"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Karibu kwenye <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"kwa Kuandika kwa ishara"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Onyesha upya"</string> <string name="last_update" msgid="730467549913588780">"Ilibadilishwa mwisho"</string> <string name="message_updating" msgid="4457761393932375219">"Inatafuta sasisho..."</string> - <string name="message_loading" msgid="8689096636874758814">"Inapakia..."</string> + <string name="message_loading" msgid="5638680861387748936">"Inapakia…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Kamusi kuu"</string> <string name="cancel" msgid="6830980399865683324">"Ghairi"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Mipangilio"</string> <string name="install_dict" msgid="180852772562189365">"Sakinisha"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Ghairi"</string> <string name="delete_dict" msgid="756853268088330054">"Futa"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Lugha iliyochaguliwa kwenye kifaa chako cha mkononi ina kamusi inayopatikana.<br/> Tunapendekeza<b>upakuaji wa kamusi</b> <xliff:g id="LANGUAGE">%1$s</xliff:g> ili kuboresha hali yako ya kucharaza.<br/> <br/> Upakuaji unaweza kuchukua dakika moja au mbili kukamilika kwenye 3G. Unaweza kutozwa pesa ikiwa huna mpango wa data <b>usio na kipimo </b>.<br/>Ikiwa huna uhakika una mpango gani wa data, tunapendekeza utafute muunganisho wa Wi-Fi ili uanze upakuaji moja kwa moja.<br/> <br/> Kidokezo: Unaweza kupakua na kuondoa kamusi kwa kuenda kwenye<b>Ingizo la & Lugha</b> katika <b>menyu ya Mipangilio</b> ya kifaa chako cha mkononi."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Lugha iliyochaguliwa kwenye kifaa chako cha mkononi ina kamusi inayopatikana.<br/> Tunapendekeza<b>upakuaji wa kamusi ya</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ili kuboresha hali yako ya kuchapa.<br/> <br/> Upakuaji unaweza kuchukua dakika moja au mbili kukamilika kwenye mtandao wa 3G. Unaweza kutozwa ada ikiwa huna mpango wa data <b>usio na kipimo </b>.<br/>Ikiwa huna uhakika una mpango gani wa data, tunapendekeza utafute muunganisho wa Wi-Fi ili uanze upakuaji kiotomatiki.<br/> <br/> Kidokezo: Unaweza kupakua na kuondoa kamusi kwa kuenda kwenye<b>Lugha na Zana za Kuingiza Datalt;/b> katika <b>menyu ya Mipangilio</b> ya kifaa chako cha mkononi."</string> <string name="download_over_metered" msgid="1643065851159409546">"Pakua sasa (MB<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Pakua kwenye Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Kamusi ya <xliff:g id="LANGUAGE">%1$s</xliff:g> inapatikana"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Kamusi inapatikana ya <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Bonyeza ili kukagua na kupakua"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Inapakua: mapendekezo ya <xliff:g id="LANGUAGE">%1$s</xliff:g> yatakuwa tayari hivi karibuni."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Inapakua: mapendekezo ya <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> yatakuwa tayari hivi karibuni."</string> <string name="version_text" msgid="2715354215568469385">"Toleo la <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Ongeza"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Ongeza kwenye kamusi"</string> diff --git a/java/res/values-sw430dp/config-per-form-factor.xml b/java/res/values-sw430dp/config-per-form-factor.xml new file mode 100644 index 000000000..8868081c3 --- /dev/null +++ b/java/res/values-sw430dp/config-per-form-factor.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- Configuration values for Large Phone. --> +<resources> + <bool name="config_enable_show_key_preview_popup_option">true</bool> + <!-- Whether or not Popup on key press is enabled by default --> + <bool name="config_default_key_preview_popup">true</bool> + <bool name="config_default_sound_enabled">false</bool> + <bool name="config_enable_show_voice_key_option">true</bool> + <bool name="config_key_selection_by_dragging_finger">true</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">false</bool> + <bool name="config_use_fullscreen_mode">false</bool> +</resources> diff --git a/java/res/values-sw540dp-land/config.xml b/java/res/values-sw430dp/config-screen-metrics.xml index b3cd7278d..bc1c964af 100644 --- a/java/res/values-sw540dp-land/config.xml +++ b/java/res/values-sw430dp/config-screen-metrics.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2013, 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. @@ -19,5 +19,6 @@ --> <resources> - <bool name="config_use_fullscreen_mode">false</bool> + <!-- Must be aligned with {@link Constants#SCREEN_METRICS_LARGE_PHONE}. --> + <integer name="config_screen_metrics">1</integer> </resources> diff --git a/java/res/values-sw540dp-land/dimens.xml b/java/res/values-sw540dp-land/dimens.xml deleted file mode 100644 index 002493798..000000000 --- a/java/res/values-sw540dp-land/dimens.xml +++ /dev/null @@ -1,72 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 45.0mm --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">283.5dp</dimen> - <fraction name="minKeyboardHeight">45%p</fraction> - - <fraction name="keyboard_top_padding_gb">2.444%p</fraction> - <fraction name="keyboard_bottom_padding_gb">0.0%p</fraction> - <fraction name="key_bottom_gap_gb">5.200%p</fraction> - <fraction name="key_horizontal_gap_gb">1.447%p</fraction> - - <fraction name="keyboard_top_padding_holo">2.727%p</fraction> - <fraction name="keyboard_bottom_padding_holo">0.0%p</fraction> - <fraction name="key_bottom_gap_holo">4.5%p</fraction> - <fraction name="key_horizontal_gap_holo">0.9%p</fraction> - - <dimen name="popup_key_height">81.9dp</dimen> - - <!-- left or right padding of label alignment --> - <dimen name="key_label_horizontal_padding">18dp</dimen> - - <fraction name="key_letter_ratio">50%</fraction> - <fraction name="key_large_letter_ratio">48%</fraction> - <fraction name="key_label_ratio">32%</fraction> - <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">30.0%</fraction> - <dimen name="key_uppercase_letter_padding">4dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">3.20%p</fraction> - <fraction name="key_letter_ratio_5row">62%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">36%</fraction> - - <dimen name="suggestions_strip_padding">252.0dp</dimen> - <integer name="max_more_suggestions_row">5</integer> - <fraction name="min_more_suggestions_width">50%</fraction> - - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">26dp</dimen> - <dimen name="gesture_floating_preview_text_offset">76dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">26dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">17dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">10%p</fraction> - <fraction name="emoji_keyboard_row_height">33%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">70%p</fraction> - <integer name="emoji_keyboard_max_key_count">30</integer> - -</resources> diff --git a/java/res/values-sw540dp/dimens.xml b/java/res/values-sw540dp/dimens.xml deleted file mode 100644 index 801b7acb5..000000000 --- a/java/res/values-sw540dp/dimens.xml +++ /dev/null @@ -1,98 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 48.0mm --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">302.4dp</dimen> - <fraction name="maxKeyboardHeight">46%p</fraction> - <fraction name="minKeyboardHeight">-35.0%p</fraction> - - <dimen name="popup_key_height">63.0dp</dimen> - - <fraction name="keyboard_top_padding_gb">2.291%p</fraction> - <fraction name="keyboard_bottom_padding_gb">0.0%p</fraction> - <fraction name="key_bottom_gap_gb">4.625%p</fraction> - <fraction name="key_horizontal_gap_gb">2.113%p</fraction> - - <fraction name="keyboard_top_padding_holo">2.335%p</fraction> - <fraction name="keyboard_bottom_padding_holo">4.0%p</fraction> - <fraction name="key_bottom_gap_holo">4.5%p</fraction> - <fraction name="key_horizontal_gap_holo">1.565%p</fraction> - - <dimen name="more_keys_keyboard_key_horizontal_padding">6dp</dimen> - <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> - <!-- popup_key_height x 1.2 --> - <dimen name="more_keys_keyboard_slide_allowance">98.3dp</dimen> - <!-- popup_key_height x -1.0 --> - <dimen name="more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen> - - <!-- left or right padding of label alignment --> - <dimen name="key_label_horizontal_padding">6dp</dimen> - <dimen name="key_hint_letter_padding">3dp</dimen> - <dimen name="key_uppercase_letter_padding">3dp</dimen> - - <fraction name="key_letter_ratio">42%</fraction> - <fraction name="key_large_letter_ratio">45%</fraction> - <fraction name="key_label_ratio">25%</fraction> - <fraction name="key_large_label_ratio">32%</fraction> - <fraction name="key_hint_letter_ratio">23%</fraction> - <fraction name="key_hint_label_ratio">28%</fraction> - <fraction name="key_uppercase_letter_ratio">22%</fraction> - <fraction name="key_preview_text_ratio">50%</fraction> - <fraction name="spacebar_text_ratio">28.0%</fraction> - <dimen name="key_preview_height">94.5dp</dimen> - <dimen name="key_preview_offset_gb">16.0dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">3.20%p</fraction> - <fraction name="key_letter_ratio_5row">52%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">27%</fraction> - - <dimen name="key_preview_offset_holo">8.0dp</dimen> - <!-- popup_key_height x -0.5 --> - <dimen name="more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen> - - <dimen name="suggestions_strip_height">44dp</dimen> - <dimen name="more_suggestions_row_height">44dp</dimen> - <integer name="max_more_suggestions_row">6</integer> - <fraction name="min_more_suggestions_width">90%</fraction> - <dimen name="suggestions_strip_padding">94.5dp</dimen> - <dimen name="suggestion_min_width">48.0dp</dimen> - <dimen name="suggestion_padding">12dp</dimen> - <dimen name="suggestion_text_size">22dp</dimen> - <dimen name="more_suggestions_hint_text_size">33dp</dimen> - - <!-- Gesture trail parameters --> - <dimen name="gesture_trail_width">2.5dp</dimen> - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">28dp</dimen> - <dimen name="gesture_floating_preview_text_offset">87dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">28dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">19dp</dimen> - <dimen name="gesture_floating_preview_round_radius">3dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">12.5%p</fraction> - <fraction name="emoji_keyboard_row_height">33%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">60%p</fraction> - <integer name="emoji_keyboard_max_key_count">24</integer> - -</resources> diff --git a/java/res/values-sw600dp-land/config.xml b/java/res/values-sw600dp-land/config.xml new file mode 100644 index 000000000..00edde161 --- /dev/null +++ b/java/res/values-sw600dp-land/config.xml @@ -0,0 +1,66 @@ +<?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. +*/ +--> + +<!-- Configuration values for Small Tablet Landscape. --> +<resources> + <!-- Preferable keyboard height in absolute scale: 45.0mm --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">283.5dp</dimen> + <fraction name="config_min_keyboard_height">45%p</fraction> + + <dimen name="config_more_keys_keyboard_key_height">81.9dp</dimen> + + <fraction name="config_keyboard_top_padding_holo">2.727%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction> + <fraction name="config_key_vertical_gap_holo">4.5%p</fraction> + <fraction name="config_key_horizontal_gap_holo">0.9%p</fraction> + + <fraction name="config_key_letter_ratio">50%</fraction> + <fraction name="config_key_large_letter_ratio">48%</fraction> + <fraction name="config_key_label_ratio">32%</fraction> + <fraction name="config_key_hint_letter_ratio">23%</fraction> + <fraction name="config_key_hint_label_ratio">34%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">29%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">30.0%</fraction> + <!-- left or right padding of label alignment --> + <dimen name="config_key_label_horizontal_padding">18dp</dimen> + <dimen name="config_key_shifted_letter_hint_padding">4dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">3.20%p</fraction> + <fraction name="config_key_letter_ratio_5row">62%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">36%</fraction> + + <dimen name="config_suggestions_strip_horizontal_padding">252.0dp</dimen> + <integer name="config_max_more_suggestions_row">5</integer> + <fraction name="config_min_more_suggestions_width">50%</fraction> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">26dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">76dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">26dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">17dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">10%p</fraction> + <fraction name="config_emoji_keyboard_row_height">33%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">70%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">30</integer> +</resources> diff --git a/java/res/values-sw600dp/config-per-form-factor.xml b/java/res/values-sw600dp/config-per-form-factor.xml new file mode 100644 index 000000000..aa9a05482 --- /dev/null +++ b/java/res/values-sw600dp/config-per-form-factor.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- Configuration values for Small Tablet. --> +<resources> + <bool name="config_enable_show_key_preview_popup_option">false</bool> + <!-- Whether or not Popup on key press is enabled by default --> + <bool name="config_default_key_preview_popup">false</bool> + <bool name="config_default_sound_enabled">true</bool> + <bool name="config_enable_show_voice_key_option">false</bool> + <bool name="config_key_selection_by_dragging_finger">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">false</bool> + <bool name="config_use_fullscreen_mode">false</bool> +</resources> diff --git a/java/res/drawable/btn_suggestion_gb.xml b/java/res/values-sw600dp/config-screen-metrics.xml index cde12fe55..d16c9253f 100644 --- a/java/res/drawable/btn_suggestion_gb.xml +++ b/java/res/values-sw600dp/config-screen-metrics.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2013, 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,10 +18,7 @@ */ --> -<selector - xmlns:android="http://schemas.android.com/apk/res/android" -> - <item - android:state_pressed="true" - android:drawable="@drawable/btn_suggestion_pressed" /> -</selector> +<resources> + <!-- Must be aligned with {@link Constants#SCREEN_METRICS_SMALL_TABLET}. --> + <integer name="config_screen_metrics">3</integer> +</resources> diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml index e72e4941e..3bd843928 100644 --- a/java/res/values-sw600dp/config.xml +++ b/java/res/values-sw600dp/config.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2013, 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,6 +18,70 @@ */ --> +<!-- Configuration values for Small Tablet Portrait. --> <resources> - <bool name="config_enable_show_voice_key_option">false</bool> + <dimen name="config_key_hysteresis_distance">40.0dp</dimen> + + <!-- Preferable keyboard height in absolute scale: 48.0mm --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">302.4dp</dimen> + <fraction name="config_max_keyboard_height">46%p</fraction> + <fraction name="config_min_keyboard_height">-35.0%p</fraction> + + <dimen name="config_more_keys_keyboard_key_height">63.0dp</dimen> + <dimen name="config_more_keys_keyboard_key_horizontal_padding">6dp</dimen> + <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> + <!-- config_more_keys_keyboard_key_height x 1.2 --> + <dimen name="config_more_keys_keyboard_slide_allowance">98.3dp</dimen> + + <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">4.0%p</fraction> + <fraction name="config_key_vertical_gap_holo">4.5%p</fraction> + <fraction name="config_key_horizontal_gap_holo">1.565%p</fraction> + <!-- config_more_keys_keyboard_key_height x -0.5 --> + <dimen name="config_more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen> + <dimen name="config_key_preview_offset_holo">8.0dp</dimen> + + <dimen name="config_key_preview_height">94.5dp</dimen> + <fraction name="config_key_preview_text_ratio">50%</fraction> + <fraction name="config_key_letter_ratio">42%</fraction> + <fraction name="config_key_large_letter_ratio">45%</fraction> + <fraction name="config_key_label_ratio">25%</fraction> + <fraction name="config_key_large_label_ratio">32%</fraction> + <fraction name="config_key_hint_letter_ratio">23%</fraction> + <fraction name="config_key_hint_label_ratio">28%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">22%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">28.0%</fraction> + <!-- left or right padding of label alignment --> + <dimen name="config_key_label_horizontal_padding">6dp</dimen> + <dimen name="config_key_hint_letter_padding">3dp</dimen> + <dimen name="config_key_shifted_letter_hint_padding">3dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">3.20%p</fraction> + <fraction name="config_key_letter_ratio_5row">52%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">27%</fraction> + + <dimen name="config_suggestions_strip_height">44dp</dimen> + <dimen name="config_more_suggestions_row_height">44dp</dimen> + <integer name="config_max_more_suggestions_row">6</integer> + <fraction name="config_min_more_suggestions_width">90%</fraction> + <dimen name="config_suggestions_strip_horizontal_padding">94.5dp</dimen> + <dimen name="config_suggestion_min_width">48.0dp</dimen> + <dimen name="config_suggestion_text_horizontal_padding">12dp</dimen> + <dimen name="config_suggestion_text_size">22dp</dimen> + <dimen name="config_more_suggestions_hint_text_size">33dp</dimen> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">28dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">87dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">28dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">19dp</dimen> + <dimen name="config_gesture_floating_preview_round_radius">3dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">12.5%p</fraction> + <fraction name="config_emoji_keyboard_row_height">33%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">60%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">24</integer> </resources> diff --git a/java/res/values-sw600dp/donottranslate-config-spacing-and-punctuations.xml b/java/res/values-sw600dp/donottranslate-config-spacing-and-punctuations.xml new file mode 100644 index 000000000..9cc555fbc --- /dev/null +++ b/java/res/values-sw600dp/donottranslate-config-spacing-and-punctuations.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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"> + <!-- Symbols that are suggested between words --> + <string name="suggested_punctuations">:,;,\",(,),\',-,/,@,_</string> +</resources> diff --git a/java/res/values-sw540dp/touch-position-correction.xml b/java/res/values-sw600dp/touch-position-correction.xml index 932b8fc72..6aaa605a6 100644 --- a/java/res/values-sw540dp/touch-position-correction.xml +++ b/java/res/values-sw600dp/touch-position-correction.xml @@ -37,17 +37,6 @@ </string-array> <string-array - name="touch_position_correction_data_gb" - translatable="false" - > - <!-- The default touch position data (See com.android.inputmethod.keyboard.ProximityInfo) - correctionX = 0.0f - correctionY = 0.0f - correctionR = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS - --> - </string-array> - - <string-array name="touch_position_correction_data_holo" translatable="false" > diff --git a/java/res/values-sw768dp-land/config.xml b/java/res/values-sw768dp-land/config.xml index b3cd7278d..3878a9e84 100644 --- a/java/res/values-sw768dp-land/config.xml +++ b/java/res/values-sw768dp-land/config.xml @@ -18,6 +18,49 @@ */ --> +<!-- Configuration values for Large Tablet Landscape. --> <resources> - <bool name="config_use_fullscreen_mode">false</bool> + <!-- Preferable keyboard height in absolute scale: 58.0mm --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">365.4dp</dimen> + <fraction name="config_min_keyboard_height">45%p</fraction> + + <fraction name="config_keyboard_top_padding_holo">1.896%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction> + <fraction name="config_key_vertical_gap_holo">3.690%p</fraction> + <fraction name="config_key_horizontal_gap_holo">1.030%p</fraction> + <dimen name="config_key_preview_offset_holo">8.0dp</dimen> + + <dimen name="config_more_keys_keyboard_key_height">81.9dp</dimen> + + <dimen name="config_key_preview_height">107.1dp</dimen> + <fraction name="config_key_letter_ratio">43%</fraction> + <fraction name="config_key_large_letter_ratio">42%</fraction> + <fraction name="config_key_label_ratio">28%</fraction> + <fraction name="config_key_hint_letter_ratio">23%</fraction> + <fraction name="config_key_hint_label_ratio">28%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">24%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">24.00%</fraction> + <!-- left or right padding of label alignment --> + <dimen name="config_key_label_horizontal_padding">18dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">2.65%p</fraction> + <fraction name="config_key_letter_ratio_5row">53%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">30%</fraction> + + <dimen name="config_suggestions_strip_horizontal_padding">252.0dp</dimen> + <fraction name="config_min_more_suggestions_width">50%</fraction> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">32dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">100dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">32dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">21dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">7.69%p</fraction> + <fraction name="config_emoji_keyboard_row_height">33%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">60%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">39</integer> </resources> diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml deleted file mode 100644 index 653f5e7d5..000000000 --- a/java/res/values-sw768dp-land/dimens.xml +++ /dev/null @@ -1,73 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 58.0mm --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">365.4dp</dimen> - <fraction name="minKeyboardHeight">45%p</fraction> - - <fraction name="keyboard_top_padding_gb">1.896%p</fraction> - <fraction name="keyboard_bottom_padding_gb">0.0%p</fraction> - <fraction name="key_bottom_gap_gb">3.896%p</fraction> - <fraction name="key_horizontal_gap_gb">1.195%p</fraction> - - <fraction name="keyboard_top_padding_holo">1.896%p</fraction> - <fraction name="keyboard_bottom_padding_holo">0.0%p</fraction> - <fraction name="key_bottom_gap_holo">3.690%p</fraction> - <fraction name="key_horizontal_gap_holo">1.030%p</fraction> - - <dimen name="popup_key_height">81.9dp</dimen> - - <!-- left or right padding of label alignment --> - <dimen name="key_label_horizontal_padding">18dp</dimen> - - <fraction name="key_letter_ratio">43%</fraction> - <fraction name="key_large_letter_ratio">42%</fraction> - <fraction name="key_label_ratio">28%</fraction> - <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">107.1dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">2.65%p</fraction> - <fraction name="key_letter_ratio_5row">53%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">30%</fraction> - - <dimen name="key_preview_offset_holo">8.0dp</dimen> - - <dimen name="suggestions_strip_padding">252.0dp</dimen> - <fraction name="min_more_suggestions_width">50%</fraction> - - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">32dp</dimen> - <dimen name="gesture_floating_preview_text_offset">100dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">32dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">21dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">7.69%p</fraction> - <fraction name="emoji_keyboard_row_height">33%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">60%p</fraction> - <integer name="emoji_keyboard_max_key_count">39</integer> - -</resources> diff --git a/java/res/values-sw540dp/config.xml b/java/res/values-sw768dp/config-per-form-factor.xml index 027780ce3..b90fbaea5 100644 --- a/java/res/values-sw540dp/config.xml +++ b/java/res/values-sw768dp/config-per-form-factor.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2013, 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,22 +18,16 @@ */ --> +<!-- Configuration values for Large Tablet. --> <resources> - <bool name="config_enable_show_option_of_key_preview_popup">false</bool> - <bool name="config_enable_bigram_suggestions_option">false</bool> + <bool name="config_enable_show_key_preview_popup_option">false</bool> <!-- Whether or not Popup on key press is enabled by default --> <bool name="config_default_key_preview_popup">false</bool> <bool name="config_default_sound_enabled">true</bool> - <bool name="config_auto_correction_spacebar_led_enabled">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_max_more_keys_column">5</integer> - <!-- - Configuration for MainKeyboardView - --> - <dimen name="config_key_hysteresis_distance">40.0dp</dimen> - <bool name="config_sliding_key_input_enabled">false</bool> + <bool name="config_enable_show_voice_key_option">false</bool> + <bool name="config_key_selection_by_dragging_finger">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> + <bool name="config_use_fullscreen_mode">false</bool> </resources> diff --git a/java/res/layout/key_preview_ics.xml b/java/res/values-sw768dp/config-screen-metrics.xml index 33b6947ef..7769ad80d 100644 --- a/java/res/layout/key_preview_ics.xml +++ b/java/res/values-sw768dp/config-screen-metrics.xml @@ -18,10 +18,7 @@ */ --> -<TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@drawable/keyboard_key_feedback_ics" - android:minWidth="32dp" - android:gravity="center" -/> +<resources> + <!-- Must be aligned with {@link Constants#SCREEN_METRICS_LARGE_TABLET}. --> + <integer name="config_screen_metrics">2</integer> +</resources> diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml index e1c07d6f8..34eec38b8 100644 --- a/java/res/values-sw768dp/config.xml +++ b/java/res/values-sw768dp/config.xml @@ -18,28 +18,68 @@ */ --> +<!-- Configuration values for Large Tablet Portrait. --> <resources> - <bool name="config_enable_show_voice_key_option">false</bool> - <bool name="config_enable_show_option_of_key_preview_popup">false</bool> - <bool name="config_enable_bigram_suggestions_option">false</bool> - <!-- Whether or not Popup on key press is enabled by default --> - <bool name="config_default_key_preview_popup">false</bool> - <bool name="config_default_sound_enabled">true</bool> - <bool name="config_auto_correction_spacebar_led_enabled">false</bool> - <integer name="config_max_more_keys_column">5</integer> - <!-- - Configuration for MainKeyboardView - --> - <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" - 2 = "mdpi 11 inch tablet screen" - 3 = "xhdpi phone screen?" - 4 = ? - --> - <integer name="log_screen_metrics">2</integer> + <!-- Preferable keyboard height in absolute scale: 48.0mm --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">302.4dp</dimen> + <fraction name="config_max_keyboard_height">46%p</fraction> + <fraction name="config_min_keyboard_height">-35.0%p</fraction> + + <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction> + <fraction name="config_key_vertical_gap_holo">3.312%p</fraction> + <fraction name="config_key_horizontal_gap_holo">1.066%p</fraction> + <!-- config_more_keys_keyboard_key_height x -0.5 --> + <dimen name="config_more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen> + <dimen name="config_key_preview_offset_holo">8.0dp</dimen> + + <dimen name="config_more_keys_keyboard_key_height">63.0dp</dimen> + <dimen name="config_more_keys_keyboard_key_horizontal_padding">12dp</dimen> + <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> + <!-- config_more_keys_keyboard_key_height x 1.2 --> + <dimen name="config_more_keys_keyboard_slide_allowance">98.3dp</dimen> + + <dimen name="config_key_preview_height">94.5dp</dimen> + <fraction name="config_key_preview_text_ratio">50%</fraction> + <fraction name="config_key_letter_ratio">40%</fraction> + <fraction name="config_key_large_letter_ratio">42%</fraction> + <fraction name="config_key_label_ratio">28%</fraction> + <fraction name="config_key_large_label_ratio">28%</fraction> + <fraction name="config_key_hint_letter_ratio">23%</fraction> + <fraction name="config_key_hint_label_ratio">28%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">26%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">29.03%</fraction> + <!-- left or right padding of label alignment --> + <dimen name="config_key_label_horizontal_padding">6dp</dimen> + <dimen name="config_key_hint_letter_padding">3dp</dimen> + <dimen name="config_key_shifted_letter_hint_padding">3dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">2.95%p</fraction> + <fraction name="config_key_letter_ratio_5row">51%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">33%</fraction> + + <dimen name="config_suggestions_strip_height">44dp</dimen> + <dimen name="config_more_suggestions_row_height">44dp</dimen> + <integer name="config_max_more_suggestions_row">6</integer> + <fraction name="config_min_more_suggestions_width">90%</fraction> + <dimen name="config_suggestions_strip_horizontal_padding">94.5dp</dimen> + <dimen name="config_suggestion_min_width">46dp</dimen> + <dimen name="config_suggestion_text_horizontal_padding">8dp</dimen> + <dimen name="config_suggestion_text_size">22dp</dimen> + <dimen name="config_more_suggestions_hint_text_size">33dp</dimen> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">26dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">86dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">26dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">17dp</dimen> + <dimen name="config_gesture_floating_preview_round_radius">3dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">10%p</fraction> + <fraction name="config_emoji_keyboard_row_height">33%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">68%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">30</integer> </resources> diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml deleted file mode 100644 index 4671aa28b..000000000 --- a/java/res/values-sw768dp/dimens.xml +++ /dev/null @@ -1,98 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 48.0mm --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">302.4dp</dimen> - <fraction name="maxKeyboardHeight">46%p</fraction> - <fraction name="minKeyboardHeight">-35.0%p</fraction> - - <fraction name="keyboard_top_padding_gb">2.291%p</fraction> - <fraction name="keyboard_bottom_padding_gb">0.0%p</fraction> - <fraction name="key_bottom_gap_gb">4.687%p</fraction> - <fraction name="key_horizontal_gap_gb">1.272%p</fraction> - - <fraction name="keyboard_top_padding_holo">2.335%p</fraction> - <fraction name="keyboard_bottom_padding_holo">0.0%p</fraction> - <fraction name="key_bottom_gap_holo">3.312%p</fraction> - <fraction name="key_horizontal_gap_holo">1.066%p</fraction> - - <dimen name="popup_key_height">63.0dp</dimen> - - <dimen name="more_keys_keyboard_key_horizontal_padding">12dp</dimen> - <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> - <!-- popup_key_height x 1.2 --> - <dimen name="more_keys_keyboard_slide_allowance">98.3dp</dimen> - <!-- popup_key_height x -1.0 --> - <dimen name="more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen> - - <!-- left or right padding of label alignment --> - <dimen name="key_label_horizontal_padding">6dp</dimen> - <dimen name="key_hint_letter_padding">3dp</dimen> - <dimen name="key_uppercase_letter_padding">3dp</dimen> - - <fraction name="key_letter_ratio">40%</fraction> - <fraction name="key_large_letter_ratio">42%</fraction> - <fraction name="key_label_ratio">28%</fraction> - <fraction name="key_large_label_ratio">28%</fraction> - <fraction name="key_hint_letter_ratio">23%</fraction> - <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">94.5dp</dimen> - <dimen name="key_preview_offset_gb">16.0dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">2.95%p</fraction> - <fraction name="key_letter_ratio_5row">51%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">33%</fraction> - - <dimen name="key_preview_offset_holo">8.0dp</dimen> - <!-- popup_key_height x -0.5 --> - <dimen name="more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen> - - <dimen name="suggestions_strip_height">44dp</dimen> - <dimen name="more_suggestions_row_height">44dp</dimen> - <integer name="max_more_suggestions_row">6</integer> - <fraction name="min_more_suggestions_width">90%</fraction> - <dimen name="suggestions_strip_padding">94.5dp</dimen> - <dimen name="suggestion_min_width">46dp</dimen> - <dimen name="suggestion_padding">8dp</dimen> - <dimen name="suggestion_text_size">22dp</dimen> - <dimen name="more_suggestions_hint_text_size">33dp</dimen> - - <!-- Gesture trail parameters --> - <dimen name="gesture_trail_width">2.5dp</dimen> - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">26dp</dimen> - <dimen name="gesture_floating_preview_text_offset">86dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">26dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">17dp</dimen> - <dimen name="gesture_floating_preview_round_radius">3dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">10%p</fraction> - <fraction name="emoji_keyboard_row_height">33%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">68%p</fraction> - <integer name="emoji_keyboard_max_key_count">30</integer> - -</resources> diff --git a/java/res/values-th/donottranslate.xml b/java/res/values-th/donottranslate-config-spacing-and-punctuations.xml index a9893feec..a9893feec 100644 --- a/java/res/values-th/donottranslate.xml +++ b/java/res/values-th/donottranslate-config-spacing-and-punctuations.xml diff --git a/java/res/values-th/strings-config-important-notice.xml b/java/res/values-th/strings-config-important-notice.xml new file mode 100644 index 000000000..3f0b6034a --- /dev/null +++ b/java/res/values-th/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"เรียนรู้จากการสื่อสารและข้อมูลที่พิมพ์ของคุณเพื่อปรับปรุงคำแนะนำ"</string> +</resources> diff --git a/java/res/values-th/strings-talkback-descriptions.xml b/java/res/values-th/strings-talkback-descriptions.xml new file mode 100644 index 000000000..eb712aeac --- /dev/null +++ b/java/res/values-th/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"ข้อความปัจจุบันคือ %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"ไม่มีข้อความ"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> แก้ไข <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> เป็น <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> ทำการแก้ไขอัตโนมัติ"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"รหัสคีย์ %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift เปิดอยู่ (แตะเพื่อปิดใช้งาน)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock เปิดอยู่ (แตะเพื่อปิดใช้งาน)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"ลบ"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"สัญลักษณ์"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"ตัวอักษร"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"หมายเลข"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"การตั้งค่า"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"แท็บ"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"วรรค"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"การป้อนข้อมูลด้วยเสียง"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"อีโมจิ"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"ส่งคืน"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"ค้นหา"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"จุด"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"เปลี่ยนภาษา"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"ถัดไป"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"ก่อนหน้า"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"เปิดใช้งาน Shift แล้ว"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"เปิดใช้งาน Caps Lock แล้ว"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"ปิดใช้งาน Shift แล้ว"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"โหมดสัญลักษณ์"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"โหมดตัวอักษร"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"โหมดโทรศัพท์"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"โหมดสัญลักษณ์โทรศัพท์"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"ซ่อนแป้นพิมพ์แล้ว"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"กำลังแสดงแป้นพิมพ์ <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"วันที่"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"วันที่และเวลา"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"อีเมล"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"ข้อความ"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"หมายเลข"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"โทรศัพท์"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"ข้อความ"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"เวลา"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"ล่าสุด"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"ผู้คน"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"วัตถุ"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"ธรรมชาติ"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"สถานที่"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"สัญลักษณ์"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"ไอคอนสื่ออารมณ์"</string> +</resources> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index 9249c05d5..ece0c4ba9 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"ค่าเริ่มต้นของระบบ"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"แนะนำชื่อผู้ติดต่อ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ใช้ชื่อจากรายชื่อติดต่อสำหรับคำแนะนำและการแก้ไข"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"คำแนะนำในแบบของคุณ"</string> <string name="use_double_space_period" msgid="8781529969425082860">"แตะ Space สองครั้งแทรกจุด"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"แตะ Spacebar สองครั้งจะแทรกจุดตามด้วยช่องว่างหนึ่งช่อง"</string> <string name="auto_cap" msgid="1719746674854628252">"ปรับเป็นตัวพิมพ์ใหญ่อัตโนมัติ"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"แสดงรอยทางเดินของท่าทางสัมผัส"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"ดูตัวอย่างลอยแบบไดนามิก"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"ดูคำแนะนำในขณะที่ใช้ท่าทางสัมผัส"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"ข้อความปัจจุบันคือ %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"ไม่มีข้อความ"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> แก้ไข <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> เป็น <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> ทำการแก้ไขอัตโนมัติ"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"รหัสคีย์ %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift เปิดอยู่ (แตะเพื่อปิดใช้งาน)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock เปิดอยู่ (แตะเพื่อปิดใช้งาน)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"ลบ"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"สัญลักษณ์"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"ตัวอักษร"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"หมายเลข"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"การตั้งค่า"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"แท็บ"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string> - <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_search" msgid="1247236163755920808">"ค้นหา"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"เครื่องหมายจุด"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"เปลี่ยนภาษา"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"ถัดไป"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"ก่อนหน้า"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"เปิดใช้งาน Shift แล้ว"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"เปิดใช้งาน Caps Lock แล้ว"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ปิดใช้งาน Shift แล้ว"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"โหมดสัญลักษณ์"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"โหมดตัวอักษร"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"โหมดโทรศัพท์"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"โหมดสัญลักษณ์โทรศัพท์"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"ซ่อนแป้นพิมพ์แล้ว"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"กำลังแสดงแป้นพิมพ์ <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"วันที่"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"วันที่และเวลา"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"อีเมล"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"ข้อความ"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"หมายเลข"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"โทรศัพท์"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"ข้อความ"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"เวลา"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"ท่าทางสัมผัสสำหรับวลี"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ใส่ช่องว่างระหว่างท่าทางสัมผัสโดยเลื่อนไปยังแป้นเคาะวรรค"</string> <string name="voice_input" msgid="3583258583521397548">"แป้นการป้อนข้อมูลด้วยเสียง"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"บนแป้นพิมพ์หลัก"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"บนแป้นพิมพ์สัญลักษณ์"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"ปิด"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ไมค์บนแป้นพิมพ์หลัก"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"ไมค์บนแป้นพิมพ์สัญลักษณ์"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ปิดใช้งานป้อนข้อมูลด้วยเสียง"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ไม่ได้เปิดใช้วิธีการป้อนข้อมูลด้วยเสียง ตรวจสอบภาษาและการตั้งค่าการป้อนข้อมูล"</string> <string name="configure_input_method" msgid="373356270290742459">"กำหนดค่าวิธีการป้อนข้อมูล"</string> <string name="language_selection_title" msgid="1651299598555326750">"ภาษาในการป้อนข้อมูล"</string> <string name="send_feedback" msgid="1780431884109392046">"ส่งข้อเสนอแนะ"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"อังกฤษ (สหราชอาณาจักร)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"อังกฤษ (อเมริกัน)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"สเปน (สหรัฐอเมริกา)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"อังกฤษ (สหราชอาณาจักร) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"อังกฤษ (สหรัฐอเมริกา) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"สเปน (สหรัฐอเมริกา) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (ดั้งเดิม)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"อังกฤษ (สหราชอาณาจักร) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"อังกฤษ (สหรัฐอเมริกา) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"สเปน (สหรัฐอเมริกา) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ดั้งเดิม)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ซีริลลิก)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (ละติน)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"ไม่มีภาษา (ตัวอักษรละติน)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"ตัวอักษร (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"ตัวอักษร (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"อ่านไฟล์พจนานุกรมภายนอก"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"ไม่มีไฟล์พจนานุกรมในโฟลเดอร์ดาวน์โหลด"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"เลือกไฟล์พจนานุกรมที่จะติดตั้ง"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"ติดตั้งไฟล์นี้สำหรับ <xliff:g id="LOCALE_NAME">%s</xliff:g> จริงๆ หรือ"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ต้องการติดตั้งไฟล์นี้สำหรับ <xliff:g id="LANGUAGE_NAME">%s</xliff:g> จริงหรือ"</string> <string name="error" msgid="8940763624668513648">"เกิดข้อผิดพลาด"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ถ่ายโอนพจนานุกรมที่อยู่ติดต่อ"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"ถ่ายโอนพจนานุกรมส่วนตัว"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ถ่ายโอนพจนานุกรมประวัติผู้ใช้"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"ถ่ายโอนพจนานุกรมในแบบคุณ"</string> <string name="button_default" msgid="3988017840431881491">"ค่าเริ่มต้น"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"ยินดีต้อนรับสู่ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"พร้อมการป้อนข้อมูลด้วยท่าทาง"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"รีเฟรช"</string> <string name="last_update" msgid="730467549913588780">"ปรับปรุงแก้ไขครั้งล่าสุด"</string> <string name="message_updating" msgid="4457761393932375219">"กำลังตรวจสอบการอัปเดต"</string> - <string name="message_loading" msgid="8689096636874758814">"กำลังโหลด..."</string> + <string name="message_loading" msgid="5638680861387748936">"กำลังโหลด…"</string> <string name="main_dict_description" msgid="3072821352793492143">"พจนานุกรมหลัก"</string> <string name="cancel" msgid="6830980399865683324">"ยกเลิก"</string> + <string name="go_to_settings" msgid="3876892339342569259">"การตั้งค่า"</string> <string name="install_dict" msgid="180852772562189365">"ติดตั้ง"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"ยกเลิก"</string> <string name="delete_dict" msgid="756853268088330054">"ลบ"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"ภาษาที่คุณเลือกใช้ในอุปกรณ์เคลื่อนที่มีพจนานุกรมที่สามารถใช้ได้<br/> เราขอแนะนำให้คุณ <b>ดาวน์โหลด</b> พจนานุกรม <xliff:g id="LANGUAGE">%1$s</xliff:g> เพื่อรับประสบการณ์การพิมพ์ที่ดียิ่งขึ้น<br/> <br/>การดาวน์โหลดจะใช้เวลาหนึ่งถึงสองนาทีผ่านทาง 3G ซึ่งอาจมีการเรียกเก็บเงินหากคุณไม่ได้ใช้ <b>แผนบริการข้อมูลแบบไม่จำกัดปริมาณ</b> <br/>หากคุณไม่แน่ใจว่าคุณใช้แผนบริการข้อมูลแบบใด เราขอแนะนำให้คุณเชื่อมต่อ WiFi เพื่อเริ่มการดาวน์โหลดอัตโนมัติ<br/> <br/>เคล็ดลับ: คุณสามารถดาวน์โหลดและนำพจนานุกรมออกได้โดยไปที่ <b>ภาษาและการป้อนข้อมูล</b> ในเมนู <b>การตั้งค่า</b> ในอุปกรณ์เคลื่อนที่ของคุณ"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ภาษาที่คุณเลือกในอุปกรณ์เคลื่อนที่มีพจนานุกรมที่สามารถใช้ได้<br/> เราขอแนะนำให้คุณ <b>ดาวน์โหลด</b> พจนานุกรม <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> เพื่อรับประสบการณ์การพิมพ์ที่ดียิ่งขึ้น<br/> <br/> การดาวน์โหลดอาจใช้เวลาหนึ่งถึงสองนาทีผ่านทาง 3G ซึ่งอาจมีการเรียกเก็บเงินหากคุณไม่ได้ใช้ <b>แผนบริการข้อมูลแบบไม่จำกัดปริมาณ</b>.<br/> หากไม่แน่ใจว่าใช้แผนบริการข้อมูลแบบใด เราขอแนะนำให้คุณเชื่อมต่อ Wi-Fi เพื่อเริ่มการดาวน์โหลดอัตโนมัติ<br/> <br/> เคล็ดลับ: คุณสามารถดาวน์โหลดและลบพจนานุกรมออกได้โดยไปที่ <b>ภาษาและการป้อนข้อมูล</b> ในเมนู <b>การตั้งค่า</b> ในอุปกรณ์เคลื่อนที่ของคุณ"</string> <string name="download_over_metered" msgid="1643065851159409546">"ดาวน์โหลดเลย (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"ดาวน์โหลดผ่าน WiFi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"มีพจนานุกรมให้ใช้งานในภาษา <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"มีพจนานุกรมให้ใช้งานสำหรับ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"กดเพื่อตรวจสอบและดาวน์โหลด"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"กำลังดาวน์โหลด: คำแนะนำสำหรับ <xliff:g id="LANGUAGE">%1$s</xliff:g> จะพร้อมใช้งานเร็วๆ นี้"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"กำลังดาวน์โหลด: คำแนะนำสำหรับ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> จะพร้อมใช้งานเร็วๆ นี้"</string> <string name="version_text" msgid="2715354215568469385">"เวอร์ชัน <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"เพิ่ม"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"เพิ่มในพจนานุกรม"</string> diff --git a/java/res/values-tl/strings-config-important-notice.xml b/java/res/values-tl/strings-config-important-notice.xml new file mode 100644 index 000000000..d8dd9194a --- /dev/null +++ b/java/res/values-tl/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Pahusayin ang suhestiyon batay sa iyong pag-uusap at na-type na data"</string> +</resources> diff --git a/java/res/values-tl/strings-talkback-descriptions.xml b/java/res/values-tl/strings-talkback-descriptions.xml new file mode 100644 index 000000000..fbf276be8 --- /dev/null +++ b/java/res/values-tl/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Mag-plug in ng headset upang marinig ang mga password key na binabanggit nang malakas."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Ang kasalukuyang teksto ay %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Walang tekstong inilagay"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"Itinatama ng <xliff:g id="KEY_NAME">%1$s</xliff:g> ang <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> sa <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"Nagsasagawa ang <xliff:g id="KEY_NAME">%1$s</xliff:g> ng auto-correction"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Key code %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Naka-on ang shift (i-tap upang i-disable)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Naka-on ang caps lock (i-tap upang i-disable)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Tanggalin"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Mga Simbolo"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Mga Titik"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Mga Numero"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Mga Setting"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Space"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Input ng boses"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Bumalik"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Maghanap"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Tuldok"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Magpalit ng wika"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Sunod"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Nauna"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Naka-enable ang shift"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Naka-enable ang caps lock"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Naka-disable ang shift"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Symbols mode"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Letters mode"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Phone mode"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Phone symbols mode"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Nakatago ang keyboard"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Ipinapakita ang keyboard na <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"petsa"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"petsa at oras"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"pagmemensahe"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"numero"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telepono"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"teksto"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"oras"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Mga Kamakailang Ginamit"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Mga Tao"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Mga Bagay"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Kalikasan"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Mga Lugar"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Mga Simbolo"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Mga Emoticon"</string> +</resources> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index df6bda09b..ce1207a5f 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Default ng system"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Mungkahi pangalan Contact"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gamitin pangalan mula Mga Contact sa mga mungkahi\'t pagwawasto"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Personalized suggestions"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Double-space period"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Naglalagay ng tuldok na may puwang ang pag-double tap sa spacebar"</string> <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalization"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Ipakita ang trail ng galaw"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dynamic na floating preview"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Tingnan ang iminungkahing salita habang gumagalaw"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Mag-plug in ng headset upang marinig ang mga password key na binabanggit nang malakas."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Ang kasalukuyang teksto ay %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Walang tekstong inilagay"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"Itatama at gagawing <xliff:g id="CORRECTED">%3$s</xliff:g> ng <xliff:g id="KEY">%1$s</xliff:g> ang <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Magsasagawa ng auto-correction ang <xliff:g id="KEY">%1$s</xliff:g>"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Code ng key %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Naka-on ang shift (i-tap upang huwag paganahin)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Naka-on ang caps lock (i-tap upang huwag paganahin)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Tanggalin"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Mga Simbolo"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Mga Titik"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Mga Numero"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Mga Setting"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Puwang"</string> - <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_search" msgid="1247236163755920808">"Paghahanap"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Tuldok"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Magpalit ng wika"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Susunod"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Nakaraan"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Pinagana ang shift"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Pinagana ang caps lock"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Hindi pinagana ang shift"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode ng mga simbolo"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode ng mga titik"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode ng telepono"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode ng mga simbolo ng telepono"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Nakatago ang keyboard"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Ipinapakita ang <xliff:g id="MODE">%s</xliff:g> keyboard"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"petsa"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"petsa at oras"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"pagmemensahe"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"numero"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telepono"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"teksto"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"oras"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Phrase gesture"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Maglagay ng espasyo sa pamamagitan ng pag-glide sa space key"</string> <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sa pangunahing keyboard"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sa keyboard ng mga simbolo"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Naka-off"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic sa pangunahing keyboard"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic sa keyboard ng mga simbolo"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hindi pinagana ang voice input"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Walang naka-enable na pamamaraan ng pag-input ng boses. Suriin ang mga setting ng Pag-input ng wika."</string> <string name="configure_input_method" msgid="373356270290742459">"I-configure ang mga pamamaraan ng pag-input"</string> <string name="language_selection_title" msgid="1651299598555326750">"Mag-input ng mga wika"</string> <string name="send_feedback" msgid="1780431884109392046">"Magpadala ng feedback"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Ingles (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Ingles (Estados Unidos)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"Spanish (US)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Ingles (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Ingles (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Spanish (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Traditional)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Ingles (UK) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Ingles (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Spanish (US) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Traditional)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Cyrillic)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Walang wika (Alpabeto)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alpabeto (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alpabeto (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Magbasa ng panlabas na file ng diksyunaryo"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Walang mga file ng diksyunaryo sa folder na Mga Download"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Pumili ng file ng diksyunaryo na ii-install"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"I-install talaga ang file na ito para sa <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Talagang ii-install ang file na ito para sa <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Nagkaroon ng error"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Diksyunaryo ng contacts ng Dump"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Personal na diksyunaryo ng Dump"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Diksyunaryo ng user history ng Dump"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Personalization dictionary ng Dump"</string> <string name="button_default" msgid="3988017840431881491">"Default"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Maligayang pagdating sa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"gamit ang Gesture na Pag-type"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"I-refresh"</string> <string name="last_update" msgid="730467549913588780">"Huling na-update"</string> <string name="message_updating" msgid="4457761393932375219">"Tumitingin ng mga update"</string> - <string name="message_loading" msgid="8689096636874758814">"Naglo-load..."</string> + <string name="message_loading" msgid="5638680861387748936">"Naglo-load…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Pangunahing diksyunaryo"</string> <string name="cancel" msgid="6830980399865683324">"Kanselahin"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Mga Setting"</string> <string name="install_dict" msgid="180852772562189365">"I-install"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Kanselahin"</string> <string name="delete_dict" msgid="756853268088330054">"Tanggalin"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"May available na diksyunaryo ang piniling wika sa iyong mobile device.<br/> Inirerekomenda namin ang <b>pag-download</b> sa diksyunaryong <xliff:g id="LANGUAGE">%1$s</xliff:g> upang mapabuti ang iyong karanasan sa pag-type.<br/> <br/> Maaaring umabot ng isa hanggang dalawang minuto ang pag-download gamit ang 3G. Maaaring may malapat na mga pagsingil kung wala kang <b>data plan na walang limitasyon</b>.<br/> Kung hindi ka sigurado kung aling data plan ang mayroon ka, inirerekomenda naming maghanap ng koneksyon sa Wi-Fi upang awtomatikong simulan ang pag-download.<br/> <br/> Tip: Maaari kang mag-download at mag-alis ng mga diksyunaryo sa pamamagitan ng pagpunta sa <b>Wika at input</b> sa menu na <b>Mga Setting</b> ng iyong mobile device."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"May available na diksyunaryo ang napiling wika sa iyong mobile device.<br/> Inirerekomenda naming <b>i-download</b> ang diksyunaryo ng <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> upang pagbutihin ang iyong karanasan sa pagta-type.<br/> <br/> Maaaring magtagal nang ilang minuto ang pag-download sa 3G. Maaaring magkaroon ng mga pagsingil kung wala kang <b>unlimited data plan</b>.<br/> Kung hindi ka sigurado kung anong data plan ang mayroon ka, inirerekomenda naming maghanap ng koneksyon sa Wi-Fi upang awtomatikong masimulan ang pag-download.<br/> <br/> Tip: Maaari kang mag-download at mag-alis ng mga diksyunaryo sa pamamagitan ng pagpunta sa <b>Wika & input</b> sa menu ng <b>Mga Setting</b> ng iyong mobile device."</string> <string name="download_over_metered" msgid="1643065851159409546">"I-download ngayon (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"I-download gamit ang Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"May available na diksyunaryo para sa <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"May available na diksyunaryo para sa <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Pindutin upang suriin at i-download"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Dina-download: malapit nang maging handa ang mga suhestiyon para sa <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Nagda-download: magkakaron ng mga suhestiyon para sa <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sa lalong madaling panahon."</string> <string name="version_text" msgid="2715354215568469385">"Bersyon <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Idagdag"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Idagdag sa diksyunaryo"</string> diff --git a/java/res/values-tr/strings-config-important-notice.xml b/java/res/values-tr/strings-config-important-notice.xml new file mode 100644 index 000000000..7d9f6ab12 --- /dev/null +++ b/java/res/values-tr/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Önerileri iyileştirmek için iletşmlrmdn. ve yazılan verilerden öğren"</string> +</resources> diff --git a/java/res/values-tr/strings-talkback-descriptions.xml b/java/res/values-tr/strings-talkback-descriptions.xml new file mode 100644 index 000000000..d06c9009c --- /dev/null +++ b/java/res/values-tr/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Şifre tuşlarının sesli okunmasını dinlemek için kulaklık takın."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Mevcut metin: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Metin girilmedi"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g>, <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> kelimesini <xliff:g id="CORRECTED_WORD">%3$s</xliff:g> olarak düzeltir"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> otomatik düzeltme yapar"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Tuş kodu: %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Üst karakter"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Üst karakter açık (devre dışı bırakmak için hafifçe vurun)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Büyük harf kilidi açık (devre dışı bırakmak için hafifçe vurun)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Sil"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Simgeler"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Harfler"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Rakamlar"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Ayarlar"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Sekme"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Boşluk çubuğu"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Ses girişi"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Enter"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Arama"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Nokta"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Dili değiştir"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Sonraki"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Önceki"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Üst karakter etkin"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Büyük harf etkin"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Üst karakter devre dışı"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Sembol modu"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Harf modu"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Telefon modu"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Telefon sembolleri modu"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Klavye gizli"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> klavyesi görüntüleniyor"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"tarih"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"tarih ve saat"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"e-posta"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"mesajlaşma"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"rakam"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"telefon"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"metin"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"saat"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Son Kullanılanlar"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Kişiler"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Nesneler"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Doğa"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Yerler"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Simgeler"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"İfadeler"</string> +</resources> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index a14295153..3584ec5db 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Sistem varsayılanı"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Kişisel öneriler"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Boşluk çubuğuna iki kez vurmak nokta ve ardından bir boşluk ekler"</string> <string name="auto_cap" msgid="1719746674854628252">"Otomatik olarak büyük harf yap"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Hareket izini göster"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Dinamik kayan önizleme"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Hareket sırasında önerilen kelimeyi göster"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Şifre tuşlarının sesli okunmasını dinlemek için mikrofonlu kulaklık takın."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Mevcut metin: %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Hiç metin girilmedi"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> tuşu <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> kelimesini <xliff:g id="CORRECTED">%3$s</xliff:g> olarak düzeltir"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> tuşu otomatik düzeltme gerçekleştirir"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Tuş kodu: %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Üst Karakter"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Üst karakter açık (devre dışı bırakmak için hafifçe vurun)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Büyük harf kilidi açık (devre dışı bırakmak içinn hafifçe vurun)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simgeler"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Harfler"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Rakamlar"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Ayarlar"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Sekme"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Boşluk"</string> - <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_search" msgid="1247236163755920808">"Ara"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Nokta"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Dili değiştir"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Sonraki"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Önceki"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Üst karakter etkin"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Büyük harf kilidi etkin"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Üst karakter devre dışı"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Sembol modu"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Harf modu"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefon modu"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefon sembolleri modu"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klavye gizli"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> klavyesi gösteriliyor"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"tarih"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"tarih ve saat"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"e-posta"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"mesajlaşma"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"rakam"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"metin"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"saat"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Kelime öbeği hareketi"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Hareketle girişte boşlukları, boşluk tuşuna kaydırarak girin"</string> <string name="voice_input" msgid="3583258583521397548">"Ses girişi tuşu"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Ana klavyede"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simge klavyesinde"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Kapalı"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Ana klavyedeki mikrofon"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Simge klavysnd mikrf"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Sesle grş devre dışı"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Hiçbir ses girişi yöntemi etkinleştirilmedi. Dil ve giriş ayarlarını kontrol edin."</string> <string name="configure_input_method" msgid="373356270290742459">"Giriş yöntemlerini yapılandır"</string> <string name="language_selection_title" msgid="1651299598555326750">"Giriş dilleri"</string> <string name="send_feedback" msgid="1780431884109392046">"Geri bildirim gönder"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"İngilizce (BK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"İngilizce (ABD)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"İspanyolca (ABD)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"İngilizce (İngiltere) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"İngilizce (ABD) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"İspanyolca (ABD) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Geleneksel)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"İngilizce (İngiltere) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"İngilizce (ABD) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"İspanyolca (ABD) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Geleneksel)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Kiril)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Dil yok (Alfabe)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabe (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabe (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Harici sözlük dosyasını oku"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"İndirilenler klasöründe sözlük dosyası yok"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Yüklemek için bir sözlük dosyası seçin"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"<xliff:g id="LOCALE_NAME">%s</xliff:g> için bu dosya gerçekten yüklensin mi?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> için bu dosya gerçekten yüklensin mi?"</string> <string name="error" msgid="8940763624668513648">"Bir hata oluştu"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Kişiler sözlüğünün dökümünü al"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Kişisel sözlüğün dökümünü al"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Kullanıcı geçmişi sözlüğünün dökümünü al"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Kişiselleştirme sözlüğünün dökümünü al"</string> <string name="button_default" msgid="3988017840431881491">"Varsayılan"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> uygulamasına hoş geldiniz"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"Hareketle Yazmayı içerir"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Yenile"</string> <string name="last_update" msgid="730467549913588780">"Son güncelleme tarihi"</string> <string name="message_updating" msgid="4457761393932375219">"Güncellemeler denetleniyor"</string> - <string name="message_loading" msgid="8689096636874758814">"Yükleniyor..."</string> + <string name="message_loading" msgid="5638680861387748936">"Yükleniyor…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Ana sözlük"</string> <string name="cancel" msgid="6830980399865683324">"İptal"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Ayarlar"</string> <string name="install_dict" msgid="180852772562189365">"Yükle"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"İptal"</string> <string name="delete_dict" msgid="756853268088330054">"Sil"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Mobil cihazınızda seçili dile ait kullanılabilir bir sözlük mevcut.<br/> Daha iyi yazabilmek için bu <xliff:g id="LANGUAGE">%1$s</xliff:g> sözlüğü <b>indirmenizi</b> öneririz.<br/> <br/> İndirme işlemi 3G üzerinden bir veya iki dakika sürebilir. <b>Sınırsız veri planınız</b> yoksa ücret alınabilir.<br/> Ne tür bir veri planına sahip olduğunuzdan emin değilseniz, otomatik olarak indirmeye başlamak için bir Kablosuz bağlantı bulmanızı öneririz.<br/> <br/> İpucu: Sözlükleri, mobil cihazınızın <b>Ayarlar</b> menüsünde <b>Dil ve giriş</b> seçeneğine giderek indirebilir ve silebilirsiniz."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobil cihazınızda seçili dile ait kullanılabilir bir sözlük var.<br/> Daha iyi yazabilmek için bu <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sözlüğü <b>indirmenizi</b> öneririz.<br/> <br/> İndirme işlemi 3G üzerinden bir veya iki dakika sürebilir. <b>Sınırsız veri planınız </b>yoksa ücret alınabilir.<br/> Ne tür bir veri planına sahip olduğunuzdan emin değilseniz, otomatik olarak indirmeye başlamak için bir Kablosuz bağlantı bulmanızı öneririz.<br/> <br/> İpucu: Sözlükleri, mobil cihazınızın <b>Ayarlar</b> menüsünde <b>Dil ve giriş</b> seçeneğine giderek indirebilir ve silebilirsiniz."</string> <string name="download_over_metered" msgid="1643065851159409546">"Hemen indir (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Kablosuz üzerinden indir"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> için kullanılabilecek bir sözlük mevcut"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> için kullanılabilir bir sözlük var"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"İncelemek ve indirmek için basın"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"<xliff:g id="LANGUAGE">%1$s</xliff:g> için önerilerin indirilmesine kısa süre içinde başlanacak."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> için önerilerin indirilmesine kısa süre içinde başlanacak."</string> <string name="version_text" msgid="2715354215568469385">"Sürüm <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Ekle"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Sözlüğe ekle"</string> diff --git a/java/res/values-uk/strings-config-important-notice.xml b/java/res/values-uk/strings-config-important-notice.xml new file mode 100644 index 000000000..b95b72cd4 --- /dev/null +++ b/java/res/values-uk/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Пристрій буде запам’ятовувати, що ви пишете, надсилаєте й отримуєте"</string> +</resources> diff --git a/java/res/values-uk/strings-talkback-descriptions.xml b/java/res/values-uk/strings-talkback-descriptions.xml new file mode 100644 index 000000000..9b6d1142d --- /dev/null +++ b/java/res/values-uk/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Підключіть гарнітуру, щоб слухати озвучені символи пароля."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Поточний текст: %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Текст не введено"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> виправляє слово \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" на \"<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>\""</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> автоматично виправляє"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Код клавіші – %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift увімкнено (торкніться, щоб вимкнути)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps Lock увімкнено (торкніться, щоб вимкнути)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Видалити"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Символи"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Літери"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Цифри"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Налаштування"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Пробіл"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Голосовий ввід"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Cмайли Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Повернутися"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Пошук"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Крапка"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Змінити мову"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Далі"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Назад"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift увімкнено"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Caps Lock увімкнено"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift вимкнено"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Режим символів"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Режим літер"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Режим номерів телефону"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Режим телефонних символів"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Клавіатуру сховано"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Режим клавіатури: <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"дата"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"дата й час"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"електронні адреси"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"повідомлення"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"цифри"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"номери телефону"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"текст"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"час"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL-адреси"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Останні"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Люди"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Об’єкти"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Природа"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Місця"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Символи"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Смайли"</string> +</resources> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index da26d5005..15a30805e 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"За умовчанням"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Персональні пропозиції"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Подвійне натискання пробілу вставляє крапку з пробілом після неї"</string> <string name="auto_cap" msgid="1719746674854628252">"Авто викор. вел. літер"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Показувати слід жестів"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Динамічний спливаючий перегляд"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Показувати пропоноване слово під час введення тексту жестами"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Підключіть гарнітуру, щоб прослухати відтворені вголос символи пароля."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Поточний текст – %s."</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Текст не введено"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> виправляє <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> на <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> здійснює автоматичне виправлення"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Код клавіші – %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Клавіша Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift увімкнено (швидко торкніться, щоб вимкнути)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock увімкнено (швидко торкніться, щоб вимкнути)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Клавіша Delete"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Символи"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Літери"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Цифри"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Налаштування"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Вкладка"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Пробіл"</string> - <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_search" msgid="1247236163755920808">"Пошук"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Крапка"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Змінити мову"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Далі"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Назад"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift увімкнено"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock увімкнено"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift вимкнено"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Режим символів"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Режим букв і цифр"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Режим набору номера"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Режим набору символів"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Клавіатуру сховано"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Режим клавіатури: <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"дата"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"дата й час"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"електронні адреси"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"повідомлення"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"цифри"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"номери телефонів"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"текст"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"час"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL-адреси"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Безперервний ввід фраз"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Вставляйте пробіли, проводячи пальцем по клавіші пробілу"</string> <string name="voice_input" msgid="3583258583521397548">"Ключ голосового вводу"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На основ. клавіатурі"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Символьна клавіатура"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Вимк."</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Мікрофон на основній клавіатурі"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Miкр. на симв. клавіат."</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Голос. ввід вимкнено"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Способи голосового вводу не ввімкнено. Перейдіть у налаштування \"Мова та введення\"."</string> <string name="configure_input_method" msgid="373356270290742459">"Налаштування методів введення"</string> <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string> <string name="send_feedback" msgid="1780431884109392046">"Надіслати відгук"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Англійська (Великобританія)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Англійська (США)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"іспанська (США)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Англійська (Великобр.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Англійська (США) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"іспанська (США) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (традиційна)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Англійська (Британія) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Англійська (США) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Іспанська (США) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (традиційна)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (кирилиця)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (латиниця)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Стандартна (латиниця)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Латиниця (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Латиниця (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Читати файл зовнішнього словника"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"У папці \"Завантаження\" немає файлів словника"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Вибрати файл словника, який потрібно встановити"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Справді встановити цей файл для такої мови: <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Справді встановити цей файл для такої мови: <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Сталася помилка"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Вивантаження словника контактів"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Вивантаження особистого словника"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Вивантаж. словника користув. історії"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Вивантаження словника персоналізації"</string> <string name="button_default" msgid="3988017840431881491">"За умовчанням"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Вітаємо в програмі <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"з функцією Ввід жестами"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Оновити"</string> <string name="last_update" msgid="730467549913588780">"Останнє оновлення"</string> <string name="message_updating" msgid="4457761393932375219">"Перевірка наявності оновлень"</string> - <string name="message_loading" msgid="8689096636874758814">"Завантаження…"</string> + <string name="message_loading" msgid="5638680861387748936">"Завантаження…"</string> <string name="main_dict_description" msgid="3072821352793492143">"Основний словник"</string> <string name="cancel" msgid="6830980399865683324">"Скасувати"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Налаштування"</string> <string name="install_dict" msgid="180852772562189365">"Установити"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Скасувати"</string> <string name="delete_dict" msgid="756853268088330054">"Видалити"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Для вибраної на вашому мобільному пристрої мови доступний словник.<br/> Радимо <b>завантажити</b> словник для цієї мови (<xliff:g id="LANGUAGE">%1$s</xliff:g>), щоб покращити введення тексту.<br/> <br/> У мережі 3G завантаження триває 1–2 хвилини. Якщо у вас не <b>безлімітний тарифний план Інтернету</b>, може стягуватися плата.<br/> Якщо ви не впевнені щодо тарифного плану, радимо скористатися з’єднанням Wi-Fi, щоб автоматично почати завантаження.<br/> <br/> Порада: завантажувати та вилучати словники можна в меню <b>Налаштування</b> в розділі <b>Мова та введення</b> вашого мобільного пристрою."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Для вибраної на вашому мобільному пристрої мови доступний словник.<br/> Радимо <b>завантажити</b> словник для цієї мови (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>), щоб покращити введення тексту.<br/> <br/> У мережі 3G завантаження триває 1–2 хвилини. Якщо у вас не <b>безлімітний тарифний план Інтернету</b>, може стягуватися плата.<br/> Якщо ви не впевнені щодо тарифного плану, радимо скористатися з’єднанням Wi-Fi, щоб автоматично почати завантаження.<br/> <br/> Порада: завантажувати та видаляти словники можна в меню <b>Налаштування</b> в розділі <b>Мова та введення</b> вашого мобільного пристрою."</string> <string name="download_over_metered" msgid="1643065851159409546">"Завантажити зараз (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> Mб)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Завантажити через Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Доступний словник для такої мови: <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Доступний словник для такої мови: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Натисніть, щоб переглянути та завантажити"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Скоро почнеться завантаження пропозицій для такої мови: <xliff:g id="LANGUAGE">%1$s</xliff:g>."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Завантаження. Скоро будуть готові пропозиції для такої мови: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>."</string> <string name="version_text" msgid="2715354215568469385">"Версія <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Додати"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Додати в словник"</string> diff --git a/java/res/values-v20/platform-theme.xml b/java/res/values-v20/platform-theme.xml new file mode 100644 index 000000000..06062047b --- /dev/null +++ b/java/res/values-v20/platform-theme.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<!-- TODO: This file is temporarily placed under values-v20. --> +<!-- TODO: It might be moved under values-v21. --> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <style name="platformActivityTheme" parent="@android:style/Theme.Quantum.Light" /> + <style name="platformDialogTheme" parent="@android:style/Theme.Quantum.Light.Dialog" /> +</resources> diff --git a/java/res/values-vi/strings-config-important-notice.xml b/java/res/values-vi/strings-config-important-notice.xml new file mode 100644 index 000000000..828f0b603 --- /dev/null +++ b/java/res/values-vi/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Tìm hiểu từ thư từ trao đổi và dữ liệu đã nhập của bạn để cải tiến đề xuất"</string> +</resources> diff --git a/java/res/values-vi/strings-talkback-descriptions.xml b/java/res/values-vi/strings-talkback-descriptions.xml new file mode 100644 index 000000000..9202883c8 --- /dev/null +++ b/java/res/values-vi/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Cắm tai nghe để nghe mật khẩu được đọc to."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Ký tự hiện tại là %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Không có ký tự nào được nhập"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"<xliff:g id="KEY_NAME">%1$s</xliff:g> sửa <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> thành <xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"<xliff:g id="KEY_NAME">%1$s</xliff:g> tự động sửa"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Mã phím %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift đang bật (nhấn để tắt)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Caps lock đang bật (nhấn để tắt)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Xóa"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Biểu tượng"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Chữ cái"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Số"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Cài đặt"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Dấu cách"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Nhập bằng giọng nói"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"Biểu tượng cảm xúc"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Quay lại"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Tìm kiếm"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Dấu chấm"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Chuyển ngôn ngữ"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Tiếp theo"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Trước"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Đã bật Shift"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Đã bật Caps lock"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Đã tắt Shift"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Chế độ biểu tượng"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Chế độ chữ cái"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Chế độ điện thoại"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Chế độ biểu tượng điện thoại"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Bàn phím bị ẩn"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Hiển thị bàn phím <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"ngày"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"ngày và giờ"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"email"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"nhắn tin"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"số"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"điện thoại"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"văn bản"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"giờ"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Gần đây"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Con người"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Đồ vật"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Tự nhiên"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Địa điểm"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Biểu tượng"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Biểu tượng cảm xúc"</string> +</resources> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index 81cd373e4..529dcec17 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Mặc định của hệ thống"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Đề xuất tên liên hệ"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Sử dụng tên từ Danh bạ cho các đề xuất và chỉnh sửa"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Đề xuất được cá nhân hóa"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Dấu cách đôi"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Nhấn đúp vào phím cách sẽ chèn thêm một dấu sau dấu cách"</string> <string name="auto_cap" msgid="1719746674854628252">"Tự động viết hoa"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Hiển thị vệt cử chỉ"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Xem trước nổi động"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Xem từ được đề xuất trong khi dùng cử chỉ"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Cắm tai nghe để nghe mật khẩu."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Ký tự hiện tại là %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Không có ký tự nào được nhập"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> sửa <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> thành <xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> thực hiện tự động sửa"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Mã phím %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift đang bật (bấm để tắt)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock đang bật (bấm để tắt)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Xóa"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Biểu tượng"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Chữ cái"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Số"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Cài đặt"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Dấu cách"</string> - <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_search" msgid="1247236163755920808">"Tìm kiếm"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Dấu chấm"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Chuyển ngôn ngữ"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Tiếp theo"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Trước"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Đã bật Shift"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Đã bật Caps lock"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Đã tắt Shift"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Chế độ biểu tượng"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Chế độ chữ cái"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Chế độ điện thoại"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Chế độ biểu tượng điện thoại"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Bàn phím bị ẩn"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Hiển thị bàn phím <xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"ngày"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"ngày và giờ"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"nhắn tin"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"số"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"điện thoại"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"văn bản"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"giờ"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Cử chỉ nhập cụm từ"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Nhập dấu cách khi thực hiện cử chỉ bằng cách trượt tới phím cách"</string> <string name="voice_input" msgid="3583258583521397548">"Khóa nhập giọng nói"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Trên bàn phím chính"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Trên bàn phím biểu tượng"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"Tắt"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micrô trên bàn phím chính"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micrô trên bàn phím biểu tượng"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Nhập liệu bằng giọng nói đã bị tắt"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Không có phương thức nhập bằng giọng nói nào được bật. Kiểm tra cài đặt Ngôn ngữ và phương thức nhập."</string> <string name="configure_input_method" msgid="373356270290742459">"Định cấu hình phương thức nhập"</string> <string name="language_selection_title" msgid="1651299598555326750">"Ngôn ngữ nhập"</string> <string name="send_feedback" msgid="1780431884109392046">"Gửi phản hồi"</string> @@ -135,10 +90,12 @@ <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="subtype_es_US" msgid="5583145191430180200">"Tiếng Tây Ban Nha (Mỹ)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Tiếng Anh (Anh) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Tiếng Anh (Mỹ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"Tiếng Tây Ban Nha (Mỹ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Truyền thống)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"Tiếng Anh (Anh) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"Tiếng Anh (Mỹ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Tiếng Tây Ban Nha (Mỹ) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Truyền thống)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tiếng Kirin)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tiếng Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Không ngôn ngữ nào (Bảng chữ cái)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Bảng chữ cái (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Bảng chữ cái (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Đọc tệp từ điển bên ngoài"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Không có tệp từ điển nào trong thư mục Nội dung tải xuống"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Chọn tệp từ điển để cài đặt"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Thực sự cài đặt tệp này cho <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Thực sự cài đặt tệp này cho <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Đã xảy ra lỗi"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Tạo từ điển danh bạ"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Lưu vào từ điển cá nhân"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Lưu vào từ điển lịch sử người dùng"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Lưu vào từ điển cá nhân hóa"</string> <string name="button_default" msgid="3988017840431881491">"Mặc định"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Chào mừng bạn đến với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"với Nhập bằng cử chỉ"</string> @@ -188,7 +149,7 @@ <string name="setup_step3_action" msgid="600879797256942259">"Định cấu hình các ngôn ngữ khác"</string> <string name="setup_finish_action" msgid="276559243409465389">"Đã xong"</string> <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Hiển thị biểu tượng ứng dụng"</string> - <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Hiển thị biểu tượng ứng dụng trong trình khởi chạy"</string> + <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Hiển thị biểu tượng ứng dụng trong trình chạy"</string> <string name="app_name" msgid="6320102637491234792">"Nhà cung cấp từ điển"</string> <string name="dictionary_provider_name" msgid="3027315045397363079">"Nhà cung cấp từ điển"</string> <string name="dictionary_service_name" msgid="6237472350693511448">"Dịch vụ từ điển"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Làm mới"</string> <string name="last_update" msgid="730467549913588780">"Cập nhật lần cuối"</string> <string name="message_updating" msgid="4457761393932375219">"Đang kiểm tra cập nhật"</string> - <string name="message_loading" msgid="8689096636874758814">"Đang tải..."</string> + <string name="message_loading" msgid="5638680861387748936">"Đang tải..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Từ điển chính"</string> <string name="cancel" msgid="6830980399865683324">"Hủy"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Cài đặt"</string> <string name="install_dict" msgid="180852772562189365">"Cài đặt"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Hủy"</string> <string name="delete_dict" msgid="756853268088330054">"Xóa"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Ngôn ngữ đã chọn trên thiết bị di động của bạn hiện có từ điển.<br/> Bạn nên <b>tải xuống</b> từ điển <xliff:g id="LANGUAGE">%1$s</xliff:g> để cải thiện trải nghiệm nhập của mình.<br/> <br/> Quá trình tải xuống có thể mất vài phút qua 3G. Có thể mất phí nếu bạn không có <b>gói dữ liệu không giới hạn</b>.<br/> Nếu bạn không chắc mình có gói dữ liệu nào, bạn nên tìm kết nối Wi-Fi để bắt đầu tải xuống tự động.<br/> <br/> Mẹo: Bạn có thể tải xuống và xóa từ điển bằng cách đi tới <b>Ngôn ngữ và nhập</b> trong trình đơn <b>Cài đặt</b> trên thiết bị di động của mình."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Ngôn ngữ đã chọn trên thiết bị di động của bạn hiện có từ điển.<br/> Bạn nên <b>tải xuống</b> từ điển <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> để cải thiện trải nghiệm nhập của mình.<br/> <br/> Quá trình tải xuống có thể mất vài phút qua 3G. Có thể mất phí nếu bạn không có <b>gói dữ liệu không giới hạn</b>.<br/> Nếu bạn không chắc mình có gói dữ liệu nào, bạn nên tìm kết nối Wi-Fi để bắt đầu tải xuống tự động.<br/> <br/> Mẹo: Bạn có thể tải xuống và xóa từ điển bằng cách đi tới <b>Ngôn ngữ và nhập</b> trong trình đơn <b>Cài đặt</b> trên thiết bị di động của mình."</string> <string name="download_over_metered" msgid="1643065851159409546">"Tải xuống bây giờ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Tải xuống qua Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Có sẵn từ điển cho <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Hiện có từ điển cho <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Nhấn để xem lại và tải xuống"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Tải xuống: đề xuất đối với <xliff:g id="LANGUAGE">%1$s</xliff:g> sẽ sớm sẵn sàng."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Đang tải xuống: đề xuất cho <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sẽ sớm sẵn sàng."</string> <string name="version_text" msgid="2715354215568469385">"Phiên bản <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Thêm"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Thêm vào từ điển"</string> diff --git a/java/res/values-zh-rCN/strings-config-important-notice.xml b/java/res/values-zh-rCN/strings-config-important-notice.xml new file mode 100644 index 000000000..6013af78d --- /dev/null +++ b/java/res/values-zh-rCN/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根据您的通信记录和以往输入的数据来完善建议"</string> +</resources> diff --git a/java/res/values-zh-rCN/strings-talkback-descriptions.xml b/java/res/values-zh-rCN/strings-talkback-descriptions.xml new file mode 100644 index 000000000..93f89e091 --- /dev/null +++ b/java/res/values-zh-rCN/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"插入耳机可听到输入密码时的按键提示音。"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"当前文字为%s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"未输入文字"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"按<xliff:g id="KEY_NAME">%1$s</xliff:g>键可将<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>更正为<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"按<xliff:g id="KEY_NAME">%1$s</xliff:g>键可进行自动更正"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"键码为%d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"已开启Shift模式(点按即可关闭)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"已锁定大写模式(点按即可关闭)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"删除"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"符号"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"字母"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"数字"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"设置"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"空格"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"语音输入"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"表情符号"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"回车"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"搜索"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"点"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"切换语言"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"下一个"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"上一个"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"已开启Shift模式"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"已锁定大写模式"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"已关闭Shift模式"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"符号模式"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"字母模式"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"电话模式"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"电话符号模式"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"键盘已隐藏"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"当前显示的是<xliff:g id="KEYBOARD_MODE">%s</xliff:g>键盘"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"日期"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"日期和时间"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"电子邮件地址"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"消息"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"数字"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"电话号码"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"文字"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"时间"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"网址"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"最近用过"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"人物"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"物件"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"自然"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"地点"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"符号"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"表情图标"</string> +</resources> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index d347c9ce8..41fe0bfb6 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"系统默认值"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"联系人姓名建议"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根据通讯录中的姓名提供建议和更正"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"个性化建议"</string> <string name="use_double_space_period" msgid="8781529969425082860">"双击空格插入句号"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"双击空格键可插入句号并后跟空格"</string> <string name="auto_cap" msgid="1719746674854628252">"自动大写"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"显示滑行输入轨迹"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"动态漂浮预览"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"在滑行输入过程中显示建议字词"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"需要插入耳机才能听到密码的按键声。"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"当前文本为%s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"未输入文字"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"按<xliff:g id="KEY">%1$s</xliff:g>可将<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>更正为<xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"按<xliff:g id="KEY">%1$s</xliff:g>可执行自动更正"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"键码为 %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 模式已启用(点按即可停用)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"大写锁定已启用(点按即可停用)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"删除"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"符号"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"字母"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"数字"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"设置"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"空格"</string> - <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_search" msgid="1247236163755920808">"搜索"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"点"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"切换语言"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"下一个"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"上一个"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 模式已启用"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大写锁定已启用"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 模式已停用"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"符号模式"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"字母模式"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"电话模式"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"电话符号模式"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"键盘已隐藏"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"目前显示的是<xliff:g id="MODE">%s</xliff:g>键盘"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"日期"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"日期和时间"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"电子邮件"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"短信"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"数字"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"电话"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"文字"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"时间"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"网址"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"词组滑行输入"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"滑行输入时,滑过空格键即可输入空格"</string> <string name="voice_input" msgid="3583258583521397548">"语音输入键"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"主键盘上"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"符号键盘上"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"关闭"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"主键盘上的麦克风"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"符号键盘上的麦克风"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"语音输入功能已停用"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"未启用任何语音输入法。请检查“语言和输入法”设置。"</string> <string name="configure_input_method" msgid="373356270290742459">"配置输入法"</string> <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string> <string name="send_feedback" msgid="1780431884109392046">"发送反馈"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"英语(英国)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英语(美国)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"西班牙语(美国)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"英语(英国)(<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"英语(美国)(<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"西班牙语(美国)(<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g>(传统)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"英式英语(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"美式英语(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"美式西班牙语(<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(传统)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(西里尔文)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g>(拉丁文)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"无语言(字母)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"字母 (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"字母 (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"读取外部词典文件"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"“下载内容”文件夹中没有词典文件"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"选择要安装的词典文件"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"确定要为<xliff:g id="LOCALE_NAME">%s</xliff:g>安装此文件吗?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"确定要安装这个<xliff:g id="LANGUAGE_NAME">%s</xliff:g>词典吗?"</string> <string name="error" msgid="8940763624668513648">"出现错误"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"转储联系人词典"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"转储个人词典"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"转储用户历史记录词典"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"转储个性化词典"</string> <string name="button_default" msgid="3988017840431881491">"默认"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"欢迎使用 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"体验顺畅的滑行输入体验"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"刷新"</string> <string name="last_update" msgid="730467549913588780">"上次更新时间"</string> <string name="message_updating" msgid="4457761393932375219">"正在检查更新"</string> - <string name="message_loading" msgid="8689096636874758814">"正在加载..."</string> + <string name="message_loading" msgid="5638680861387748936">"正在加载…"</string> <string name="main_dict_description" msgid="3072821352793492143">"主词典"</string> <string name="cancel" msgid="6830980399865683324">"取消"</string> + <string name="go_to_settings" msgid="3876892339342569259">"设置"</string> <string name="install_dict" msgid="180852772562189365">"安装"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"取消"</string> <string name="delete_dict" msgid="756853268088330054">"删除"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"支持您移动设备上所选语言的词典现已可供下载啦!<br/>建议您<b>下载</b>这部<xliff:g id="LANGUAGE">%1$s</xliff:g>词典,以享受更好的输入体验。<br/><br/>通过 3G 进行下载可能需要 1 到 2 分钟的时间。如果您使用的不是<b>无流量限制的套餐</b>,则可能需要支付一定的费用。<br/>如果您不确定自己使用的是哪种流量套餐,建议您使用 WLAN 连接自动开始下载。<br/><br/>提示:您可以访问移动设备的<b>设置</b>菜单中的<b>语言和输入法</b>,来下载和删除词典。"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的移动设备上选择的语言有一个词典可供下载。<br/>我们建议您<b>下载</b>这个<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>词典,以便获得更好的输入体验。<br/><br/>通过3G网络下载可能需要一两分钟的时间。如果您使用的不是<b>无流量限制的套餐</b>,则可能产生一定的流量费。<br/>如果您不确定自己使用的是哪种流量套餐,我们建议您连接到WLAN网络以便自动开始下载。<br/><br/>提示:您可以在移动设备上的<b>语言和输入法</b>部分(位于<b>设置</b>菜单中)下载和删除词典。"</string> <string name="download_over_metered" msgid="1643065851159409546">"立即下载 (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"通过 WLAN 下载"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g>词典可供下载"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"有一个<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>词典可供下载"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"按此通知即可查看和下载"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"下载中:很快就能启用<xliff:g id="LANGUAGE">%1$s</xliff:g>的词典建议服务了!"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"正在下载:<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>输入建议功能马上就可以使用了!"</string> <string name="version_text" msgid="2715354215568469385">"版本<xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"添加"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"添加到词典"</string> diff --git a/java/res/values-zh-rHK/strings-config-important-notice.xml b/java/res/values-zh-rHK/strings-config-important-notice.xml new file mode 100644 index 000000000..a21b24388 --- /dev/null +++ b/java/res/values-zh-rHK/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根據您的通訊記錄和已輸入的資料改善建議"</string> +</resources> diff --git a/java/res/values-zh-rHK/strings-talkback-descriptions.xml b/java/res/values-zh-rHK/strings-talkback-descriptions.xml new file mode 100644 index 000000000..8b60504d9 --- /dev/null +++ b/java/res/values-zh-rHK/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"插上耳機即可聽到系統朗讀密碼鍵。"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"目前文字為 %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"未輸入文字"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"按「<xliff:g id="KEY_NAME">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>」"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"按「<xliff:g id="KEY_NAME">%1$s</xliff:g>」可自動修正"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"按鍵代碼 %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift 鍵"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift 鍵已開啟 (輕按即可停用)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"大寫鎖定已開啟 (輕按即可停用)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"刪除"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"符號"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"字母"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"數字"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"設定"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab 鍵"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"空白鍵"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"語音輸入"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"表情圖案"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Return 鍵"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"搜尋"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"分點符號"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"切換語言"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"下一個"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"上一個"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift 鍵已啟用"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"大寫鎖定已啟用"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift 鍵已停用"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"符號模式"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"字母模式"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"撥號模式"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"符號撥號模式"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"鍵盤已隱藏"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"目前顯示的是<xliff:g id="KEYBOARD_MODE">%s</xliff:g>鍵盤"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"日期"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"日期和時間"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"電郵"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"短訊"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"數字"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"電話"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"文字"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"時間"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"網址"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"最近使用過"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"人物"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"物件"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"大自然"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"地點"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"符號"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"表情符號"</string> +</resources> diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml index 306045591..34fa9c037 100644 --- a/java/res/values-zh-rHK/strings.xml +++ b/java/res/values-zh-rHK/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"系統預設"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人名稱"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"使用「聯絡人」的名稱提供建議與修正"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"個人化建議"</string> <string name="use_double_space_period" msgid="8781529969425082860">"按兩下空格鍵插入句號"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"只要輕按兩下空格鍵,即可插入句號並在後面加上一個空格"</string> <string name="auto_cap" msgid="1719746674854628252">"自動大寫"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"顯示手勢軌跡"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"動態浮動預覽"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"在啟用手勢輸入時顯示建議的字詞"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"插上耳機即可聽到系統朗讀密碼鍵。"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"目前文字為 %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"未輸入文字"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"按「<xliff:g id="KEY">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED">%3$s</xliff:g>」"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"按「<xliff:g id="KEY">%1$s</xliff:g>」可自動修正"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"按鍵代碼 %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift 鍵"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 鍵已開啟 (輕按即可停用)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"大寫鎖定已開啟 (輕按即可停用)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"刪除"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"符號"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"字母"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"數字"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"設定"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab 鍵"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"空白鍵"</string> - <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_search" msgid="1247236163755920808">"搜尋"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"點"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"切換語言"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"下一步"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"上一步"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 鍵已啟用"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大寫鎖定已啟用"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 鍵已停用"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"符號模式"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"字母模式"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"撥號模式"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"符號撥號模式"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"鍵盤已隱藏"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"目前顯示的是<xliff:g id="MODE">%s</xliff:g>鍵盤"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"日期"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"日期和時間"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"電郵"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"短訊"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"數字"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"電話"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"文字"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"詞組手勢"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"在手勢輸入過程中,滑過空白鍵即可輸入空格"</string> <string name="voice_input" msgid="3583258583521397548">"語音輸入鍵"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"於主鍵盤"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"符號鍵盤上"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"關閉"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"主鍵盤上的麥克風"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"符號鍵盤上的麥克風"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"語音輸入已停用"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟用語音輸入法,請檢查語言和輸入設定。"</string> <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string> <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string> <string name="send_feedback" msgid="1780431884109392046">"傳送意見"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"英文 (英國)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英文 (美國)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"西班牙文 (美國)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"英文 (英國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"英文 (美國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"西班牙文 (美國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (傳統)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"英文 (英國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"英文 (美國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"西班牙文 (美國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (傳統)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (西里爾文)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (拉丁文)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"無語言 (字母)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"字母 (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"字母 (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"讀取外部字典檔案"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"「下載」資料夾中沒有任何字典檔案"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"選取要安裝的字典檔案"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"準備好要為<xliff:g id="LOCALE_NAME">%s</xliff:g>版本安裝這個檔案嗎?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"準備為<xliff:g id="LANGUAGE_NAME">%s</xliff:g>版本安裝這個檔案嗎?"</string> <string name="error" msgid="8940763624668513648">"發生錯誤"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"傾印聯絡人字典"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"傾印個人字典"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"傾印使用者記錄字典"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"傾印個人化字典"</string> <string name="button_default" msgid="3988017840431881491">"預設"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"歡迎使用「<xliff:g id="APPLICATION_NAME">%s</xliff:g>」"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"配備觸控輸入功能"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"重新整理"</string> <string name="last_update" msgid="730467549913588780">"上次更新日期"</string> <string name="message_updating" msgid="4457761393932375219">"正在查看更新"</string> - <string name="message_loading" msgid="8689096636874758814">"正在載入..."</string> + <string name="message_loading" msgid="5638680861387748936">"正在載入…"</string> <string name="main_dict_description" msgid="3072821352793492143">"主要字典"</string> <string name="cancel" msgid="6830980399865683324">"取消"</string> + <string name="go_to_settings" msgid="3876892339342569259">"設定"</string> <string name="install_dict" msgid="180852772562189365">"安裝"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"取消"</string> <string name="delete_dict" msgid="756853268088330054">"刪除"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"您的流動裝置所選取的語言現有字典可供使用。<br/>建議您<b>下載</b><xliff:g id="LANGUAGE">%1$s</xliff:g>字典,讓您輸入時更方便。<br/><br/>經由 3G 網絡下載需時一兩分鐘。如果您未使用<b>無限上網計劃</b>,可能須另外付費。<br/>如果您不確定自己使用哪種上網計劃,建議您在連接 Wi-Fi 網絡後才開始自動下載。<br/><br/>提示:您可以前往流動裝置的 [設定] <b></b>選單,透過其中的 [語言和輸入] <b></b>下載和移除字典。"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的流動裝置所選取的語言現有字典可供使用。<br/>我們建議您<b>下載</b><xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典,讓您輸入時更方便。<br/><br/>經由 3G 網絡下載需時一、兩分鐘。如果您未使用<b>無限上網計劃</b>,可能須另外付費。<br/>如果您不確定自己使用哪種上網計劃,我們建議您在連接 Wi-Fi 網絡後才開始自動下載。<br/><br/>提示:您可以前往流動裝置的 [設定] <b></b>選單,透過其中的 [語言和輸入] <b></b>下載和移除字典。"</string> <string name="download_over_metered" msgid="1643065851159409546">"立即下載 (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"經由 Wi-Fi 下載"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"可使用<xliff:g id="LANGUAGE">%1$s</xliff:g>字典"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"可使用<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"按下即可查看並下載"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"下載中:很快就能提供<xliff:g id="LANGUAGE">%1$s</xliff:g>字詞建議。"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"下載中:<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字詞建議服務即將啟用。"</string> <string name="version_text" msgid="2715354215568469385">"版本 <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"新增"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"加入字典"</string> diff --git a/java/res/values-zh-rTW/strings-config-important-notice.xml b/java/res/values-zh-rTW/strings-config-important-notice.xml new file mode 100644 index 000000000..dfffa69cf --- /dev/null +++ b/java/res/values-zh-rTW/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根據您的通訊紀錄和以往輸入的資料改善建議項目"</string> +</resources> diff --git a/java/res/values-zh-rTW/strings-talkback-descriptions.xml b/java/res/values-zh-rTW/strings-talkback-descriptions.xml new file mode 100644 index 000000000..6351a985a --- /dev/null +++ b/java/res/values-zh-rTW/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"連接耳機即可聽取系統朗讀密碼按鍵。"</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"目前文字為 %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"未輸入文字"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"按下「<xliff:g id="KEY_NAME">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>」"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"按下「<xliff:g id="KEY_NAME">%1$s</xliff:g>」可執行自動修正"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"按鍵代碼 %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"Shift 鍵"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"Shift 鍵已開啟 (輕按即可停用)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"大寫鎖定已開啟 (輕按即可停用)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"刪除"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"符號"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"字母"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"數字"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"設定"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Tab 鍵"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"空格鍵"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"語音輸入"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"表情符號"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"返回"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"搜尋"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"圓點符號"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"切換語言"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"下一個"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"上一個"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"Shift 鍵已啟用"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"大寫鎖定已啟用"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"Shift 鍵已停用"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"符號模式"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"字母模式"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"撥號模式"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"撥號符號模式"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"鍵盤已隱藏"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"目前顯示的是<xliff:g id="KEYBOARD_MODE">%s</xliff:g>鍵盤"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"日期"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"日期和時間"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"電子郵件"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"簡訊"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"數字"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"電話號碼"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"文字"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"時間"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"網址"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"最近使用過"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"人物"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"物體"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"自然"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"地點"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"符號"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"表情"</string> +</resources> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 2c474b79e..9c9f5e052 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"系統預設"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"聯絡人姓名建議"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"個人化建議"</string> <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"輕按兩下空格鍵可插入句號另加一個空格"</string> <string name="auto_cap" msgid="1719746674854628252">"自動大寫"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"顯示手勢軌跡"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"動態浮動預覽"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"使用滑行輸入時顯示建議字詞"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"連接耳機即可聽取系統朗讀密碼按鍵。"</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"目前文字為 %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"未輸入文字"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"按下「<xliff:g id="KEY">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED">%3$s</xliff:g>」"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"按下「<xliff:g id="KEY">%1$s</xliff:g>」可執行自動修正"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"按鍵代碼 %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift 鍵"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 鍵已開啟 (輕按即可停用)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"大寫鎖定已開啟 (輕按即可停用)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"刪除"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"符號"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"字母"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"數字"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"設定"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab 鍵"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"空白鍵"</string> - <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_search" msgid="1247236163755920808">"搜尋"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"點"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"切換語言"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"下一頁"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"上一頁"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 鍵已啟用"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大寫鎖定已啟用"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 鍵已停用"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"符號模式"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"字母模式"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"撥號模式"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"撥號符號模式"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"鍵盤已隱藏"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"目前顯示的是<xliff:g id="MODE">%s</xliff:g>鍵盤"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"日期"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"日期和時間"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"電子郵件"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"簡訊"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"數字"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"電話號碼"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"文字"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"詞組手勢"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"手勢輸入時,滑過空格鍵即可輸入空格"</string> <string name="voice_input" msgid="3583258583521397548">"語音輸入按鍵"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"主鍵盤上"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"符號鍵盤上"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"關閉"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"主鍵盤上的麥克風"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"符號鍵盤上的麥克風"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"語音輸入已停用"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟動語音輸入法,請檢查語言與輸入設定。"</string> <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string> <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string> <string name="send_feedback" msgid="1780431884109392046">"提供意見"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"英文 (英國)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英文 (美國)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"西班牙文 (美國)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"英文 (英國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"英文 (美國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"西班牙文 (美國) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (傳統)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"英文 (英國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"英文 (美國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"西班牙文 (美國) (<xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g>)"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (傳統)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (斯拉夫文)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (拉丁文)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"無語言 (字母)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"字母 (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"字母 (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"讀取外部字典檔案"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"「下載」資料夾中沒有任何字典檔案"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"選取要安裝的字典檔案"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"準備為<xliff:g id="LOCALE_NAME">%s</xliff:g>版本安裝這個檔案嗎?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"確定要安裝這個<xliff:g id="LANGUAGE_NAME">%s</xliff:g>檔案嗎?"</string> <string name="error" msgid="8940763624668513648">"發生錯誤"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"傾印聯絡人字典"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"捨棄個人字典"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"捨棄使用者紀錄字典"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"捨棄個人化字典"</string> <string name="button_default" msgid="3988017840431881491">"預設"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"歡迎使用 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"含滑行輸入功能"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"重新整理"</string> <string name="last_update" msgid="730467549913588780">"上次更新時間:"</string> <string name="message_updating" msgid="4457761393932375219">"正在檢查更新"</string> - <string name="message_loading" msgid="8689096636874758814">"載入中..."</string> + <string name="message_loading" msgid="5638680861387748936">"載入中…"</string> <string name="main_dict_description" msgid="3072821352793492143">"主要字典"</string> <string name="cancel" msgid="6830980399865683324">"取消"</string> + <string name="go_to_settings" msgid="3876892339342569259">"設定"</string> <string name="install_dict" msgid="180852772562189365">"安裝"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"取消"</string> <string name="delete_dict" msgid="756853268088330054">"刪除"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"您的行動裝置設定的語言,現有字典可供使用。<br/> 建議您<b>下載</b><xliff:g id="LANGUAGE">%1$s</xliff:g>字典,加強輸入功能。<br/> <br/> 透過 3G 網路下載約需一兩分鐘。若無<b>無限行動上網資費方案</b>,可能必須另外付費。<br/>若不確定行動上網資費方案為何,可以等連上 Wi-Fi 網路後再自動下載。<br/> <br/>提示:進入行動裝置的 [設定] 選單,選擇 [語言和輸入] 即可下載及移除字典。<b></b><b></b>"</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的行動裝置選用的語言現有字典可供使用。<br/>建議您<b>下載</b><xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典,藉此強化輸入功能。<br/><br/>透過 3G 網路下載約需一兩分鐘。如果沒有<b>無限行動上網資費方案</b>,可能必須另外付費。<br/>若不確定行動上網資費方案為何,可以等連上 Wi-Fi 網路後再自動下載。<br/><br/>提示:前往行動裝置的 [設定] 選單,選擇 [語言和輸入] 即可下載及移除字典。<b></b><b></b>"</string> <string name="download_over_metered" msgid="1643065851159409546">"立即下載 (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"透過 Wi-Fi 下載"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"支援<xliff:g id="LANGUAGE">%1$s</xliff:g>字典"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"支援<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"按下即可查看並下載"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"下載中:即將啟用<xliff:g id="LANGUAGE">%1$s</xliff:g>字詞建議服務。"</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"下載中:即將啟用<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字詞建議服務。"</string> <string name="version_text" msgid="2715354215568469385">"版本 <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"新增"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"加入字典"</string> diff --git a/java/res/values-zu/strings-config-important-notice.xml b/java/res/values-zu/strings-config-important-notice.xml new file mode 100644 index 000000000..0d352006c --- /dev/null +++ b/java/res/values-zu/strings-config-important-notice.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Funda kusukela kwezokuxhumana zakho nedatha ethayiphiwe ukuze uthuthukise iziphakamiso"</string> +</resources> diff --git a/java/res/values-zu/strings-talkback-descriptions.xml b/java/res/values-zu/strings-talkback-descriptions.xml new file mode 100644 index 000000000..e01f7347d --- /dev/null +++ b/java/res/values-zu/strings-talkback-descriptions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="spoken_use_headphones" msgid="4313642710742229868">"Plaka ku-headset ukuze uzwe okhiye bephasiwedi ezindlebeni zakho bezwakala kakhulu."</string> + <string name="spoken_current_text_is" msgid="4240549866156675799">"Umbhalo wamanje ngu %s"</string> + <string name="spoken_no_text_entered" msgid="1711276837961785646">"Awukho umbhalo ofakiwe"</string> + <string name="spoken_auto_correct" msgid="8989324692167993804">"I-<xliff:g id="KEY_NAME">%1$s</xliff:g> ilungisa i-<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> kube yi-<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>"</string> + <string name="spoken_auto_correct_obscured" msgid="7769449372355268412">"I-<xliff:g id="KEY_NAME">%1$s</xliff:g> yenza ukulungisa okuzenzakalelayo"</string> + <string name="spoken_description_unknown" msgid="2382510329910793539">"Ikhodi yokhiye %d"</string> + <string name="spoken_description_shift" msgid="7209798151676638728">"U-Shift"</string> + <string name="spoken_description_shift_shifted" msgid="1609924271343916689">"U-Shift uvuliwe (thepha ukuwuvimbela)"</string> + <string name="spoken_description_caps_lock" msgid="5020582161133170892">"Ofeleba bavuliwe (thepha ukubavimbela)"</string> + <string name="spoken_description_delete" msgid="3878902286264983302">"Susa"</string> + <string name="spoken_description_to_symbol" msgid="8244903740201126590">"Amasimbuli"</string> + <string name="spoken_description_to_alpha" msgid="4081215210530031950">"Izinhlamvu"</string> + <string name="spoken_description_to_numeric" msgid="4560261331530795682">"Izinombolo"</string> + <string name="spoken_description_settings" msgid="7281251004003143204">"Izilungiselelo"</string> + <string name="spoken_description_tab" msgid="8210782459446866716">"Ithebhu"</string> + <string name="spoken_description_space" msgid="5908716896642059145">"Isikhala"</string> + <string name="spoken_description_mic" msgid="6153138783813452464">"Okungenayo kwezwi"</string> + <string name="spoken_description_emoji" msgid="7990051553008088470">"I-Emoji"</string> + <string name="spoken_description_return" msgid="3183692287397645708">"Buyela"</string> + <string name="spoken_description_search" msgid="5099937658231911288">"Sesha"</string> + <string name="spoken_description_dot" msgid="5644176501632325560">"Icashazi"</string> + <string name="spoken_description_language_switch" msgid="6818666779313544553">"Shintsha ulimi"</string> + <string name="spoken_description_action_next" msgid="431761808119616962">"Okulandelayo"</string> + <string name="spoken_description_action_previous" msgid="2919072174697865110">"Okwangaphambilini"</string> + <string name="spoken_description_shiftmode_on" msgid="5107180516341258979">"U-Shift uvunyelwe"</string> + <string name="spoken_description_shiftmode_locked" msgid="7307477738053606881">"Ofeleba bavunyelwe"</string> + <string name="spoken_description_shiftmode_off" msgid="5039126122829961331">"U-Shift uvimbelwe"</string> + <string name="spoken_description_mode_symbol" msgid="111186851131446691">"Imodi yezimpawu"</string> + <string name="spoken_description_mode_alpha" msgid="4676004119618778911">"Imodi yezinhlamvu"</string> + <string name="spoken_description_mode_phone" msgid="2061220553756692903">"Imodi yefoni"</string> + <string name="spoken_description_mode_phone_shift" msgid="7879963803547701090">"Imodi yezimpawu zefoni"</string> + <string name="announce_keyboard_hidden" msgid="2313574218950517779">"Ikhibhodi ifihliwe"</string> + <string name="announce_keyboard_mode" msgid="6698257917367823205">"Ibonisa ikhibhodi ye-<xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string> + <string name="keyboard_mode_date" msgid="6597407244976713364">"idethi"</string> + <string name="keyboard_mode_date_time" msgid="3642804408726668808">"idethi nesikhathi"</string> + <string name="keyboard_mode_email" msgid="1239682082047693644">"i-imeyili"</string> + <string name="keyboard_mode_im" msgid="3812086215529493501">"imilayezo"</string> + <string name="keyboard_mode_number" msgid="5395042245837996809">"inombolo"</string> + <string name="keyboard_mode_phone" msgid="2486230278064523665">"ifoni"</string> + <string name="keyboard_mode_text" msgid="9138789594969187494">"umbhalo"</string> + <string name="keyboard_mode_time" msgid="8558297845514402675">"isikhathi"</string> + <string name="keyboard_mode_url" msgid="8072011652949962550">"I-URL"</string> + <string name="spoken_descrption_emoji_category_recents" msgid="4185344945205590692">"Okwakamuva"</string> + <string name="spoken_descrption_emoji_category_people" msgid="8414196269847492817">"Abantu"</string> + <string name="spoken_descrption_emoji_category_objects" msgid="6116297906606195278">"Izinto"</string> + <string name="spoken_descrption_emoji_category_nature" msgid="5018340512472354640">"Indalo"</string> + <string name="spoken_descrption_emoji_category_places" msgid="1163315840948545317">"Izindawo"</string> + <string name="spoken_descrption_emoji_category_symbols" msgid="474680659024880601">"Amasimbuli"</string> + <string name="spoken_descrption_emoji_category_emoticons" msgid="456737544787823539">"Izithombe-mzwelo"</string> +</resources> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 27d11316c..c79d81dcc 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -46,6 +46,7 @@ <string name="settings_system_default" msgid="6268225104743331821">"Okuzenzakalelayo kwesistimu"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sikisela amagama Othintana nabo"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Amagama abasebenzisi kusuka Kothintana nabo bokusikisela nokulungisa"</string> + <string name="use_personalized_dicts" msgid="5167396352105467626">"Iziphakamiso ezenziwe okomuntu siqu"</string> <string name="use_double_space_period" msgid="8781529969425082860">"Isikhathi se-Double-space"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"Ukuthepha kabili kubha yesikhala kufaka isikhathi esilandelwa yisikhala"</string> <string name="auto_cap" msgid="1719746674854628252">"Ukwenza ofeleba okuzenzakalelayo"</string> @@ -73,56 +74,10 @@ <string name="gesture_preview_trail" msgid="3802333369335722221">"Bonisa i-trail yokuthinta"</string> <string name="gesture_floating_preview_text" msgid="4443240334739381053">"Ukuhlola kuqala okuntantayo okunamandla"</string> <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Bona igama eliphakanyisiwe ngenkathi uthinta"</string> - <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kulondoloziwe"</string> - <string name="spoken_use_headphones" msgid="896961781287283493">"Plaka ku-headset ukuze uzwe okhiye bephasiwedi ezindlebeni zakho bezwakala kakhulu."</string> - <string name="spoken_current_text_is" msgid="2485723011272583845">"Umbhalo wamanje ngu %s"</string> - <string name="spoken_no_text_entered" msgid="7479685225597344496">"Awukho umbhalo ofakiwe"</string> - <string name="spoken_auto_correct" msgid="8005997889020109763">"I-<xliff:g id="KEY">%1$s</xliff:g> ilungisa i-<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ibe yi-<xliff:g id="CORRECTED">%3$s</xliff:g>"</string> - <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"I-<xliff:g id="KEY">%1$s</xliff:g> yenza ukulungiswa kokuzenzakalela"</string> - <string name="spoken_description_unknown" msgid="3197434010402179157">"Ikhodi yokhiye %d"</string> - <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string> - <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"U-Shift uvuliwe (thepha ukuwuvimbela)"</string> - <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Ofeleba bavuliwe (thepha ukubavimbela)"</string> - <string name="spoken_description_delete" msgid="8740376944276199801">"Susa"</string> - <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Amasimbuli"</string> - <string name="spoken_description_to_alpha" msgid="23129338819771807">"Imbhalo"</string> - <string name="spoken_description_to_numeric" msgid="591752092685161732">"Izinombolo"</string> - <string name="spoken_description_settings" msgid="4627462689603838099">"Izilungiselelo"</string> - <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string> - <string name="spoken_description_space" msgid="2582521050049860859">"Isikhala"</string> - <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_search" msgid="1247236163755920808">"Sesha"</string> - <string name="spoken_description_dot" msgid="40711082435231673">"Icashazi"</string> - <string name="spoken_description_language_switch" msgid="5507091328222331316">"Shintsha ulimi"</string> - <string name="spoken_description_action_next" msgid="8636078276664150324">"Okulandelayo"</string> - <string name="spoken_description_action_previous" msgid="800872415009336208">"Okwandulele"</string> - <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"U-Shift uvunyelwe"</string> - <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Ofeleba bavunyelwe"</string> - <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"U-Shift uvimbelwe"</string> - <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Imodi yezimpawu"</string> - <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Imodi yezinhlamvu"</string> - <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Imodi yefoni"</string> - <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Imodi yezimpawu zefoni"</string> - <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Ikhibhodi ifihliwe"</string> - <string name="announce_keyboard_mode" msgid="4729081055438508321">"Kuboniswa ikhibhodi engu-<xliff:g id="MODE">%s</xliff:g>"</string> - <string name="keyboard_mode_date" msgid="3137520166817128102">"idethi"</string> - <string name="keyboard_mode_date_time" msgid="339593358488851072">"idethi nesikhathi"</string> - <string name="keyboard_mode_email" msgid="6216248078128294262">"i-imeyili"</string> - <string name="keyboard_mode_im" msgid="1137405089766557048">"imilayezo"</string> - <string name="keyboard_mode_number" msgid="7991623440699957069">"inombolo"</string> - <string name="keyboard_mode_phone" msgid="6851627527401433229">"ifoni"</string> - <string name="keyboard_mode_text" msgid="6479436687899701619">"umbhalo"</string> - <string name="keyboard_mode_time" msgid="4381856885582143277">"isikhathi"</string> - <string name="keyboard_mode_url" msgid="1519819835514911218">"I-URL"</string> + <string name="gesture_space_aware" msgid="2078291600664682496">"Igama lokuthinta"</string> + <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Faka izikhala ngesikhathi sokuthinta ngokushelelela kukhiye wesikhala"</string> <string name="voice_input" msgid="3583258583521397548">"Inkinobho yokufaka izwi"</string> - <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Kwikhibhodi eyisisekelo"</string> - <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Ikhibhodi yezimpawu"</string> - <string name="voice_input_modes_off" msgid="3745699748218082014">"VALIWE"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"I-mic kwikhibhodi eyisisekelo"</string> - <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Ikhibhodi yezimpawu ze-mic"</string> - <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Okufakwayo ngezwi kuvinjelwe"</string> + <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Azikho izindlela zokufaka zezwi ezinikwe amandla. Hlola izilungiselelo zolimi kanye nezokufaka."</string> <string name="configure_input_method" msgid="373356270290742459">"Misa izindlela zokufakwayo"</string> <string name="language_selection_title" msgid="1651299598555326750">"Izilimi zokufakwayo"</string> <string name="send_feedback" msgid="1780431884109392046">"Thumela impendulo"</string> @@ -135,10 +90,12 @@ <string name="subtype_en_GB" msgid="88170601942311355">"i-English(UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"i-English (US)"</string> <string name="subtype_es_US" msgid="5583145191430180200">"I-Spanish (US)"</string> - <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"I-English (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"I-English (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"I-Spanish (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string> - <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%s</xliff:g> (Ezosiko)"</string> + <string name="subtype_with_layout_en_GB" msgid="1931018968641592304">"I-English (UK) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_with_layout_en_US" msgid="8809311287529805422">"I-English (US) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_with_layout_es_US" msgid="510930471167541338">"Isi-Spanish (US) ( <xliff:g id="KEYBOARD_LAYOUT">%s</xliff:g> )"</string> + <string name="subtype_generic_traditional" msgid="8584594350973800586">"Isi-<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradition)"</string> + <string name="subtype_generic_cyrillic" msgid="7486451947618138947">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Isi-Cyrillic)"</string> + <string name="subtype_generic_latin" msgid="9128716486310604145">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Isi-Latin)"</string> <string name="subtype_no_language" msgid="7137390094240139495">"Alikho ulimi (Alfabhethi)"</string> <string name="subtype_no_language_qwerty" msgid="244337630616742604">"Alfabhethi (QWERTY)"</string> <string name="subtype_no_language_qwertz" msgid="443066912507547976">"Alfabhethi (QWERTZ)"</string> @@ -168,8 +125,12 @@ <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Funda ifayela elangaphandle lesichazamazwi"</string> <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Awekho amafayela wesichazamazwi kufolda yokulandiwe"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Khetha ifayela lesichazamazwi ukuze ulifake"</string> - <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Ufuna ukufakela i-<xliff:g id="LOCALE_NAME">%s</xliff:g> leli fayela ngokweqiniso?"</string> + <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"Fakela ngempela leli fayela i-<xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"Kube nephutha"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"Yenza uhlu isichazamazwi soxhumana nabo"</string> + <string name="prefs_dump_user_dict" msgid="294870685041741951">"Lahla isichazamazwi somuntu siqu"</string> + <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Lahla isichazamazwi somlando womsebenzisi"</string> + <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Lahla isichazamazwi sokwenza kube ngokwakho"</string> <string name="button_default" msgid="3988017840431881491">"Okuzenzakalelayo"</string> <string name="setup_welcome_title" msgid="6112821709832031715">"Siyakwamukela ku-<xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="setup_welcome_additional_description" msgid="8150252008545768953">"nokuthayipha ngokuthinta"</string> @@ -207,18 +168,19 @@ <string name="check_for_updates_now" msgid="8087688440916388581">"Qala kabusha"</string> <string name="last_update" msgid="730467549913588780">"Igcine ukulungiswa"</string> <string name="message_updating" msgid="4457761393932375219">"Ihlola izibuyekezo"</string> - <string name="message_loading" msgid="8689096636874758814">"Iyalayisha..."</string> + <string name="message_loading" msgid="5638680861387748936">"Iyalayisha..."</string> <string name="main_dict_description" msgid="3072821352793492143">"Isichazamazwi sakho esisemqoka"</string> <string name="cancel" msgid="6830980399865683324">"Khansela"</string> + <string name="go_to_settings" msgid="3876892339342569259">"Izilungiselelo"</string> <string name="install_dict" msgid="180852772562189365">"Faka"</string> <string name="cancel_download_dict" msgid="7843340278507019303">"Khansela"</string> <string name="delete_dict" msgid="756853268088330054">"Susa"</string> - <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Ulimi olukhethiwe kudivayisi yakho yeselula linesichazamazwi esitholakalayo.<br/> Sincoma <b>ukulanda</b> isichazamazwi sesi-<xliff:g id="LANGUAGE">%1$s</xliff:g> ukwenza kangcono isipiliyoni sakho sokuthayipha.<br/> <br/> Ukulanda ukungathatha iminithi noma amaminithi amabili nge-3G. Amashaja angasebenza uma ungenalo <b>icebo ledatha elinganqunyelwe</b>.<br/> Uma ungenasiqinisekiso sokuthi iliphi icebo ledatha onalo, sincoma ukuthola uxhumo lwe-Wi-Fi ukuze uqale ukulanda ngokuzenzakalelayo.<br/> <br/> Ithiphu: Ungalanda futhi ususe izichazamazwi ngokuya ku-<b>Ulimi nokungenayo</b> kumenyu ye-<b>Izilungiselelo</b> yedivayisi yakho yeselula."</string> + <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Ulimi olukhethiwe kudivayisi yakho yeselula lunesichazamazwi esitholakalayo.<br/> Sincoma <b>ukulanda</b> isichazamazwi se-<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ukuze sithuthukise umuzwa wakho wokuthayipha.<br/> <br/> Ukulanda kungathatha iminithi noma amabili ngaphezulu kwe-3G. Ukukhokhiswa kungasebenza uma unganalo <b>uhlelo lwedatha elingenamkhawulo</b>.<br/> Uma ungenaso isiqiniseko sokuthi ukuliphi uhlelo lwedatha, sincoma ukuthi uthole ukuxhumeka kwe-Wi-Fi ukuze uqale ukulanda ngokuzenzakalela.<br/> <br/> Ithiphu: Ungalanda uphinde ususe izichazamazwi ngokuya ku-<b>Ulimi nokokufaka</b> kumenyu ye-<b>Izilungiselelo</b> zedivayisi yakho yeselula."</string> <string name="download_over_metered" msgid="1643065851159409546">"Landa manje (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string> <string name="do_not_download_over_metered" msgid="2176209579313941583">"Landa nge-Wi-Fi"</string> - <string name="dict_available_notification_title" msgid="6514288591959117288">"Isichazamazwi se-<xliff:g id="LANGUAGE">%1$s</xliff:g> siyatholakala"</string> + <string name="dict_available_notification_title" msgid="4583842811218581658">"Isichazamazwi sitholakalela i-<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>"</string> <string name="dict_available_notification_description" msgid="1075194169443163487">"Cindezela ukuze ubuyekeze uphinde ulande"</string> - <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Ukulanda: iziphakamiso ze-<xliff:g id="LANGUAGE">%1$s</xliff:g> zizolunga maduze."</string> + <string name="toast_downloading_suggestions" msgid="6128155879830851739">"Ukulanda: iziphakamiso ze-<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> zizolunga maduze."</string> <string name="version_text" msgid="2715354215568469385">"Inguqulo engu-<xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string> <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Engeza"</string> <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Faka kusichazamazwi"</string> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 31945d020..475e92f2e 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -26,14 +26,14 @@ <attr name="keyboardViewStyle" format="reference" /> <!-- MainKeyboardView style --> <attr name="mainKeyboardViewStyle" format="reference" /> + <!-- Key preview text view style --> + <attr name="keyPreviewTextViewStyle" format="reference"/> <!-- EmojiPalettesView style --> <attr name="emojiPalettesViewStyle" format="reference" /> <!-- MoreKeysKeyboard style --> <attr name="moreKeysKeyboardStyle" format="reference" /> <!-- MoreKeysKeyboardView style --> <attr name="moreKeysKeyboardViewStyle" format="reference" /> - <!-- MoreKeysKeyboardView container style --> - <attr name="moreKeysKeyboardContainerStyle" format="reference" /> <!-- Suggestions strip style --> <attr name="suggestionStripViewStyle" format="reference" /> <!-- Suggestion word style --> @@ -41,9 +41,9 @@ </declare-styleable> <declare-styleable name="KeyboardView"> - <!-- Image for the key. This image needs to be a StateListDrawable, with the following - possible states: normal, pressed, checkable, checkable+pressed, checkable+checked, - checkable+checked+pressed. --> + <!-- Image for the key. This image needs to be a {@link StateListDrawable}, with the + following possible states: normal, pressed, checkable, checkable+pressed, + checkable+checked, checkable+checked+pressed. --> <attr name="keyBackground" format="reference" /> <!-- Image for the functional key used in Emoji layout. --> <attr name="keyBackgroundEmojiFunctional" format="reference" /> @@ -72,9 +72,11 @@ <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" /> + <attr name="languageOnSpacebarTextRatio" format="fraction" /> + <attr name="languageOnSpacebarTextColor" format="color" /> + <attr name="languageOnSpacebarTextShadowColor" format="color" /> + <!-- Background image for the spacebar. --> + <attr name="spacebarBackground" format="reference" /> <!-- Fadeout animator for spacebar language label. --> <attr name="languageOnSpacebarFinalAlpha" format="integer" /> <attr name="languageOnSpacebarFadeoutAnimator" format="reference" /> @@ -89,8 +91,8 @@ <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" /> + <!-- Enable key selection by dragging finger --> + <attr name="keySelectionByDraggingFinger" format="boolean" /> <attr name="slidingKeyInputPreviewColor" format="color" /> <attr name="slidingKeyInputPreviewWidth" format="dimension" /> <attr name="slidingKeyInputPreviewBodyRatio" format="integer" /> @@ -109,6 +111,7 @@ <attr name="keyPreviewOffset" format="dimension" /> <!-- Height of the key press feedback popup. --> <attr name="keyPreviewHeight" format="dimension" /> + <!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. --> <!-- Delay after key releasing and key press feedback dismissing in millisecond --> <attr name="keyPreviewLingerTimeout" format="integer" /> <!-- Layout resource for more keys keyboard --> @@ -172,7 +175,7 @@ </declare-styleable> <declare-styleable name="SuggestionStripView"> - <attr name="suggestionStripOption" format="integer"> + <attr name="suggestionStripOptions" format="integer"> <!-- This should be aligned with SuggestionStripLayoutHelper.AUTO_CORRECT_* and etc. --> <flag name="autoCorrectBold" value="0x01" /> <flag name="autoCorrectUnderline" value="0x02" /> @@ -217,7 +220,6 @@ <attr name="iconSearchKey" format="reference" /> <attr name="iconTabKey" format="reference" /> <attr name="iconShortcutKey" format="reference" /> - <attr name="iconShortcutForLabel" format="reference" /> <attr name="iconSpaceKeyForNumberLayout" format="reference" /> <attr name="iconShiftKeyShifted" format="reference" /> <attr name="iconShortcutKeyDisabled" format="reference" /> @@ -235,10 +237,6 @@ </declare-styleable> <declare-styleable name="Keyboard_Key"> - <!-- The unicode value that this key outputs. - Code value represented in hexadecimal prefixed with "0x" or code value reference using - "!code/<code_name>" notation. --> - <attr name="code" format="string" /> <!-- The alternate unicode value that this key outputs while typing. Code value represented in hexadecimal prefixed with "0x" or code value reference using "!code/<code_name>" notation. --> @@ -270,12 +268,12 @@ <flag name="altCodeWhileTyping" value="0x04" /> <flag name="enableLongPress" value="0x08" /> </attr> - <!-- The string of characters to output when this key is pressed. --> - <attr name="keyOutputText" format="string" /> - <!-- The label to display on the key. --> - <attr name="keyLabel" format="string" /> + <!-- The label, icon to display on the key. And code, outputText of the key. --> + <attr name="keySpec" format="string" /> <!-- The hint label to display on the key in conjunction with the label. --> <attr name="keyHintLabel" format="string" /> + <!-- The vertical adjustment of key hint label in proportion to its height. --> + <attr name="keyHintLabelVerticalAdjustment" format="fraction" /> <!-- The key label flags. --> <attr name="keyLabelFlags" format="integer"> <!-- This should be aligned with Key.LABEL_FLAGS__* --> @@ -292,24 +290,25 @@ <flag name="hasPopupHint" value="0x200" /> <flag name="hasShiftedLetterHint" value="0x400" /> <flag name="hasHintLabel" value="0x800" /> + <!-- These two flags are currently unused. Leave these for possible future use. --> <flag name="withIconLeft" value="0x1000" /> <flag name="withIconRight" value="0x2000" /> <flag name="autoXScale" value="0x4000" /> + <!-- The autoScale value implies autoXScale bit on to optimize scaling code path. --> + <flag name="autoScale" value="0xc000" /> <!-- If true, character case of code, altCode, moreKeys, keyOutputText, keyLabel, or keyHintLabel will never be subject to change. --> - <flag name="preserveCase" value="0x8000" /> + <flag name="preserveCase" value="0x10000" /> <!-- If true, use keyShiftedLetterHintActivatedColor for the shifted letter hint and keyTextInactivatedColor for the primary key top label. --> - <flag name="shiftedLetterActivated" value="0x10000" /> + <flag name="shiftedLetterActivated" value="0x20000" /> <!-- If true, use EditorInfo.actionLabel for the key label. --> - <flag name="fromCustomActionLabel" value="0x20000" /> + <flag name="fromCustomActionLabel" value="0x40000" /> <!-- If true, disable keyHintLabel. --> <flag name="disableKeyHintLabel" value="0x40000000" /> <!-- If true, disable additionalMoreKeys. --> <flag name="disableAdditionalMoreKeys" value="0x80000000" /> </attr> - <!-- The icon to display on the key instead of the label. --> - <attr name="keyIcon" format="string" /> <!-- The icon for disabled key --> <attr name="keyIconDisabled" format="string" /> <!-- The icon to show in the popup preview. --> @@ -415,8 +414,7 @@ <attr name="navigatePrevious" format="boolean" /> <attr name="passwordInput" format="boolean" /> <attr name="clobberSettingsKey" format="boolean" /> - <attr name="shortcutKeyEnabled" format="boolean" /> - <attr name="shortcutKeyOnSymbols" format="boolean" /> + <attr name="supportsSwitchingToShortcutIme" format="boolean" /> <attr name="hasShortcutKey" format="boolean" /> <attr name="languageSwitchKeyEnabled" format="boolean" /> <attr name="isMultiLine" format="boolean" /> diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml index 93f25a7f6..824928c6b 100644 --- a/java/res/values/colors.xml +++ b/java/res/values/colors.xml @@ -19,26 +19,13 @@ --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Color resources for Gingerbread theme. --> - <color name="highlight_color_gb">#FFFCAE00</color> - <color name="typed_word_color_gb">@android:color/white</color> - <color name="highlight_translucent_color_gb">#99FCAE00</color> - <color name="key_text_color_gb">@android:color/white</color> - <color name="key_text_shadow_color_gb">#BB000000</color> - <color name="key_text_inactivated_color_gb">#66E0E4E5</color> - <color name="key_hint_letter_color_gb">#80000000</color> - <color name="key_hint_label_color_gb">#E0E0E4E5</color> - <color name="key_shifted_letter_hint_inactivated_color_gb">#66E0E4E5</color> - <color name="key_shifted_letter_hint_activated_color_gb">#CCE0E4E5</color> - <color name="spacebar_text_color_gb">#FFC0C0C0</color> - <color name="spacebar_text_shadow_color_gb">#80000000</color> - <color name="gesture_floating_preview_color_gb">#C0000000</color> <!-- Color resources for IceCreamSandwich theme. Base color = 33B5E5 --> <!-- android:color/holo_blue_light value is #FF33B5E5 --> <color name="highlight_color_ics">#FF33B5E5</color> <color name="typed_word_color_ics">#D833B5E5</color> <color name="suggested_word_color_ics">#B233B5E5</color> <color name="highlight_translucent_color_ics">#9933B5E5</color> + <color name="key_text_color_holo">@android:color/white</color> <color name="key_text_shadow_color_holo">@android:color/transparent</color> <color name="key_text_inactivated_color_holo">#66E0E4E5</color> <color name="key_hint_letter_color_holo">#80000000</color> @@ -65,7 +52,4 @@ <!-- TODO: Color which should be included in the theme --> <color name="emoji_key_background_color">#00000000</color> <color name="emoji_key_pressed_background_color">#30FFFFFF</color> - - <color name="key_text_color_normal_holo">@android:color/white</color> - <color name="key_text_color_functional_holo">@android:color/white</color> </resources> diff --git a/java/res/values/config-auto-correction-thresholds.xml b/java/res/values/config-auto-correction-thresholds.xml new file mode 100644 index 000000000..7d94a42a4 --- /dev/null +++ b/java/res/values/config-auto-correction-thresholds.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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> + <!-- The array of auto correction threshold values. --> + <string-array name="auto_correction_threshold_values" translatable="false"> + <!-- Off, When auto correction setting is Off, this value is not used. --> + <item>floatMaxValue</item> + <!-- Modest : Suggestion whose normalized score is greater than this value + will be subject to auto-correction. --> + <item>0.185</item> + <!-- Aggressive --> + <item>0.067</item> + <!-- Very Aggressive : Suggestion whose normalized score is greater than this value + will be subject to auto-correction. "floatNegativeInfinity" is a special marker + string for Float.NEGATIVE_INFINITY --> + <item>floatNegativeInfinity</item> + </string-array> + + <!-- The index of the auto correction threshold values array. --> + <string name="auto_correction_threshold_mode_index_off" translatable="false">0</string> + <string name="auto_correction_threshold_mode_index_modest" translatable="false">1</string> + <string name="auto_correction_threshold_mode_index_aggressive" translatable="false">2</string> + <string name="auto_correction_threshold_mode_index_very_aggressive" translatable="false">3</string> + + <!-- The array of the auto correction threshold settings values. --> + <string-array name="auto_correction_threshold_mode_indexes" translatable="false"> + <item>@string/auto_correction_threshold_mode_index_off</item> + <item>@string/auto_correction_threshold_mode_index_modest</item> + <item>@string/auto_correction_threshold_mode_index_aggressive</item> + <item>@string/auto_correction_threshold_mode_index_very_aggressive</item> + </string-array> + <!-- The array of the human readable auto correction threshold settings entries. --> + <string-array name="auto_correction_threshold_modes" translatable="false"> + <item>@string/auto_correction_threshold_mode_off</item> + <item>@string/auto_correction_threshold_mode_modest</item> + <item>@string/auto_correction_threshold_mode_aggressive</item> + <item>@string/auto_correction_threshold_mode_very_aggressive</item> + </string-array> +</resources> diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml new file mode 100644 index 000000000..3fe4b947c --- /dev/null +++ b/java/res/values/config-common.xml @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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> + <bool name="config_block_potentially_offensive">true</bool> + <!-- Default value for next word prediction: after entering a word and a space only, should we look + at input history to suggest a hopefully helpful suggestions for the next word? --> + <bool name="config_default_next_word_prediction">true</bool> + + <!-- This configuration must be aligned with {@link KeyboardTheme#DEFAULT_THEME_ID}. --> + <string name="config_default_keyboard_theme_id" translatable="false">2</string> + + <integer name="config_delay_update_shift_state">100</integer> + <integer name="config_double_space_period_timeout">1100</integer> + + <integer name="config_key_repeat_start_timeout">400</integer> + <integer name="config_key_repeat_interval">50</integer> + + <integer name="config_ignore_alt_code_key_timeout">350</integer> + + <integer name="config_key_preview_show_up_duration">17</integer> + <integer name="config_key_preview_dismiss_duration">53</integer> + <fraction name="config_key_preview_show_up_start_scale">98%</fraction> + <fraction name="config_key_preview_dismiss_end_scale">94%</fraction> + <!-- TODO: consolidate key preview linger timeout with the above animation parameters. --> + <integer name="config_key_preview_linger_timeout">70</integer> + <!-- Suppress showing key preview duration after batch input in millisecond --> + <integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer> + + <bool name="config_default_vibration_enabled">true</bool> + <integer name="config_max_vibration_duration">100</integer> + + <integer name="config_default_longpress_key_timeout">300</integer> + <integer name="config_max_longpress_timeout">700</integer> + <integer name="config_min_longpress_timeout">100</integer> + <integer name="config_longpress_timeout_step">10</integer> + <integer name="config_max_more_keys_column">5</integer> + <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer> + <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer> + + <!-- Long pressing shift will invoke caps-lock if > 0, never invoke caps-lock if == 0 --> + <integer name="config_longpress_shift_lock_timeout">1200</integer> + + <!-- Sliding key input preview parameters --> + <dimen name="config_sliding_key_input_preview_width">8.0dp</dimen> + <!-- Percentages of sliding key input preview body and shadow, in proportion to the width. + A negative value of the shadow ratio disables drawing shadow. --> + <!-- TODO: May use the shadow to alleviate rugged trail drawing. --> + <integer name="config_sliding_key_input_preview_body_ratio">100</integer> + <integer name="config_sliding_key_input_preview_shadow_ratio">-1</integer> + <dimen name="config_key_hysteresis_distance_for_sliding_modifier">8.0dp</dimen> + + <integer name="config_language_on_spacebar_final_alpha">128</integer> + <dimen name="config_language_on_spacebar_horizontal_margin">1dp</dimen> + + <integer name="config_gesture_floating_preview_text_linger_timeout">200</integer> + <integer name="config_gesture_trail_fadeout_start_delay">100</integer> + <integer name="config_gesture_trail_fadeout_duration">800</integer> + <integer name="config_gesture_trail_update_interval">20</integer> + <!-- Static threshold for gesture after fast typing (msec) --> + <integer name="config_gesture_static_time_threshold_after_fast_typing">500</integer> + <!-- Static threshold for starting gesture detection (keyWidth%/sec) --> + <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction> + <!-- Dynamic threshold for gesture after fast typing (msec) --> + <integer name="config_gesture_dynamic_threshold_decay_duration">450</integer> + <!-- Time based threshold values for gesture detection (msec) --> + <integer name="config_gesture_dynamic_time_threshold_from">300</integer> + <integer name="config_gesture_dynamic_time_threshold_to">20</integer> + <!-- Distance based threshold values for gesture detection (keyWidth%/sec) --> + <fraction name="config_gesture_dynamic_distance_threshold_from">600%</fraction> + <fraction name="config_gesture_dynamic_distance_threshold_to">50%</fraction> + <!-- Parameter for gesture sampling (keyWidth%/sec) --> + <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction> + <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) --> + <integer name="config_gesture_recognition_minimum_time">100</integer> + <integer name="config_gesture_recognition_update_time">100</integer> + <fraction name="config_gesture_recognition_speed_threshold">550%</fraction> + + <integer name="config_keyboard_grid_width">32</integer> + <integer name="config_keyboard_grid_height">16</integer> + <dimen name="config_touch_noise_threshold_distance">12.6dp</dimen> + <integer name="config_touch_noise_threshold_time">40</integer> + + <!-- Common keyboard configuration. --> + <fraction name="config_keyboard_left_padding">0%p</fraction> + <fraction name="config_keyboard_right_padding">0%p</fraction> + <dimen name="config_keyboard_vertical_correction">0.0dp</dimen> + + <!-- Common key top visual configuration. --> + <dimen name="config_key_popup_hint_letter_padding">2dp</dimen> + + <!-- Common suggestion strip configuration. --> + <integer name="config_suggestions_count_in_strip">3</integer> + <fraction name="config_center_suggestion_percentile">36%</fraction> + <integer name="config_delay_update_suggestions">100</integer> + <integer name="config_delay_update_old_suggestions">300</integer> + + <!-- Common more suggestions configuraion. --> + <dimen name="config_more_suggestions_key_horizontal_padding">12dp</dimen> + <dimen name="config_more_suggestions_bottom_gap">6dp</dimen> + <dimen name="config_more_suggestions_modal_tolerance">32.0dp</dimen> + <fraction name="config_more_suggestions_info_ratio">18%</fraction> + + <!-- Common gesture trail parameters --> + <!-- Minimum distance between gesture trail sampling points. --> + <dimen name="config_gesture_trail_min_sampling_distance">9.6dp</dimen> + <!-- Maximum angular threshold between gesture trails interpolation segments in degree. --> + <integer name="config_gesture_trail_max_interpolation_angular_threshold">15</integer> + <!-- Maximum distance threshold between gesture trails interpolation segments. --> + <dimen name="config_gesture_trail_max_interpolation_distance_threshold">16.0dp</dimen> + <!-- Maximum number of gesture trail interpolation segments. --> + <integer name="config_gesture_trail_max_interpolation_segments">6</integer> + <dimen name="config_gesture_trail_start_width">10.0dp</dimen> + <dimen name="config_gesture_trail_end_width">2.5dp</dimen> + <!-- Percentages of gesture preview taril body and shadow, in proportion to the trail width. + A negative value of the shadow ratio disables drawing shadow. --> + <!-- TODO: May use the shadow to alleviate rugged trail drawing. --> + <integer name="config_gesture_trail_body_ratio">100</integer> + <integer name="config_gesture_trail_shadow_ratio">-1</integer> + + <!-- Common configuration of Emoji keyboard --> + <dimen name="config_emoji_category_page_id_height">3dp</dimen> + + <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. --> + <dimen name="config_accessibility_edge_slop">8dp</dimen> + + <integer name="config_user_dictionary_max_word_length">48</integer> + + <!-- Personalization configuration --> + <!-- -1 means periocical wipe of the personalization dict is disabled. --> + <integer name="config_personalization_dict_wipe_interval_in_days">-1</integer> +</resources> diff --git a/java/res/values/config-dictionary-pack.xml b/java/res/values/config-dictionary-pack.xml new file mode 100644 index 000000000..d076af452 --- /dev/null +++ b/java/res/values/config-dictionary-pack.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- Configuration values for Dictionary pack. --> +<resources> + <!-- Settings for the dictionary pack --> + <bool name="allow_over_metered">false</bool> + <bool name="allow_over_roaming">false</bool> + <bool name="dict_downloads_visible_in_download_UI">false</bool> + <bool name="metadata_downloads_visible_in_download_UI">false</bool> + <bool name="display_notification_for_auto_update">false</bool> + <bool name="display_notification_for_user_requested_update">false</bool> +</resources> diff --git a/java/res/values/config-per-form-factor.xml b/java/res/values/config-per-form-factor.xml new file mode 100644 index 000000000..67fc75134 --- /dev/null +++ b/java/res/values/config-per-form-factor.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- Configuration values for Small Phone. --> +<resources> + <bool name="config_enable_show_key_preview_popup_option">true</bool> + <!-- Whether or not Popup on key press is enabled by default --> + <bool name="config_default_key_preview_popup">true</bool> + <bool name="config_default_sound_enabled">false</bool> + <bool name="config_enable_show_voice_key_option">true</bool> + <bool name="config_key_selection_by_dragging_finger">true</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">false</bool> +</resources> diff --git a/java/res/values/config-screen-metrics.xml b/java/res/values/config-screen-metrics.xml new file mode 100644 index 000000000..99629944a --- /dev/null +++ b/java/res/values/config-screen-metrics.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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> + <!-- Must be aligned with {@link Constants#SCREEN_METRICS_SMALL_PHONE}. --> + <integer name="config_screen_metrics">0</integer> +</resources> diff --git a/java/res/values-hdpi/config.xml b/java/res/values/config-spellchecker-thresholds.xml index 4cf3562fe..e99ba6621 100644 --- a/java/res/values-hdpi/config.xml +++ b/java/res/values/config-spellchecker-thresholds.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2013, 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. @@ -19,12 +19,7 @@ --> <resources> - <!-- Screen metrics for logging. - 0 = "mdpi phone screen" - 1 = "hdpi phone screen" - 2 = "mdpi 11 inch tablet screen" - 3 = "xhdpi phone screen?" - 4 = ? - --> - <integer name="log_screen_metrics">1</integer> + <!-- 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> </resources> diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 61779d4b5..45ea48392 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -18,120 +18,71 @@ */ --> +<!-- Configuration values for Small Phone Portrait. --> <resources> <bool name="config_use_fullscreen_mode">false</bool> - <bool name="config_enable_show_voice_key_option">true</bool> - <bool name="config_enable_show_option_of_key_preview_popup">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_key_preview_popup">true</bool> - <!-- Default value for next word prediction: after entering a word and a space only, should we look - at input history to suggest a hopefully helpful suggestions for the next word? --> - <bool name="config_default_next_word_prediction">true</bool> - <bool name="config_default_sound_enabled">false</bool> - <bool name="config_default_vibration_enabled">true</bool> - <integer name="config_max_vibration_duration">100</integer> <!-- milliseconds --> - <integer name="config_delay_update_suggestions">100</integer> - <integer name="config_delay_update_old_suggestions">300</integer> - <integer name="config_delay_update_shift_state">100</integer> - <integer name="config_language_on_spacebar_final_alpha">128</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_space_period_timeout">1100</integer> - <!-- This configuration is an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. --> - <string name="config_default_keyboard_theme_index" translatable="false">2</string> - <integer name="config_max_more_keys_column">5</integer> - <!-- - Configuration for MainKeyboardView - --> <dimen name="config_key_hysteresis_distance">8.0dp</dimen> - <dimen name="config_key_hysteresis_distance_for_sliding_modifier">8.0dp</dimen> - <integer name="config_touch_noise_threshold_time">40</integer> - <dimen name="config_touch_noise_threshold_distance">12.6dp</dimen> - <integer name="config_key_preview_linger_timeout">70</integer> - <bool name="config_sliding_key_input_enabled">true</bool> - <!-- Sliding key input preview parameters --> - <dimen name="config_sliding_key_input_preview_width">8.0dp</dimen> - <!-- Percentages of sliding key input preview body and shadow, in proportion to the width. - A negative value of the shadow ratio disables drawing shadow. --> - <!-- TODO: May use the shadow to alleviate rugged trail drawing. --> - <integer name="config_sliding_key_input_preview_body_ratio">100</integer> - <integer name="config_sliding_key_input_preview_shadow_ratio">-1</integer> - <integer name="config_key_repeat_start_timeout">400</integer> - <integer name="config_key_repeat_interval">50</integer> - <integer name="config_default_longpress_key_timeout">300</integer> <!-- milliseconds --> - <integer name="config_longpress_timeout_step">10</integer> <!-- milliseconds --> - <integer name="config_min_longpress_timeout">100</integer> <!-- milliseconds --> - <integer name="config_max_longpress_timeout">700</integer> <!-- milliseconds --> - <!-- Long pressing shift will invoke caps-lock if > 0, never invoke caps-lock if == 0 --> - <integer name="config_longpress_shift_lock_timeout">1200</integer> <!-- milliseconds --> - <integer name="config_ignore_alt_code_key_timeout">350</integer> <!-- milliseconds --> - <!-- 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> - <bool name="config_block_potentially_offensive">true</bool> - <integer name="config_gesture_floating_preview_text_linger_timeout">200</integer> - <integer name="config_gesture_trail_fadeout_start_delay">100</integer> - <integer name="config_gesture_trail_fadeout_duration">800</integer> - <integer name="config_gesture_trail_update_interval">20</integer> - <!-- Static threshold for gesture after fast typing (msec) --> - <integer name="config_gesture_static_time_threshold_after_fast_typing">500</integer> - <!-- Static threshold for starting gesture detection (keyWidth%/sec) --> - <fraction name="config_gesture_detect_fast_move_speed_threshold">150%</fraction> - <!-- Dynamic threshold for gesture after fast typing (msec) --> - <integer name="config_gesture_dynamic_threshold_decay_duration">450</integer> - <!-- Time based threshold values for gesture detection (msec) --> - <integer name="config_gesture_dynamic_time_threshold_from">300</integer> - <integer name="config_gesture_dynamic_time_threshold_to">20</integer> - <!-- Distance based threshold values for gesture detection (keyWidth%/sec) --> - <fraction name="config_gesture_dynamic_distance_threshold_from">600%</fraction> - <fraction name="config_gesture_dynamic_distance_threshold_to">50%</fraction> - <!-- Parameter for gesture sampling (keyWidth%/sec) --> - <fraction name="config_gesture_sampling_minimum_distance">16.6666%</fraction> - <!-- Parameters for gesture recognition (msec) and (keyWidth%/sec) --> - <integer name="config_gesture_recognition_minimum_time">100</integer> - <integer name="config_gesture_recognition_update_time">100</integer> - <fraction name="config_gesture_recognition_speed_threshold">550%</fraction> - <!-- Suppress showing key preview duration after batch input in millisecond --> - <integer name="config_suppress_key_preview_after_batch_input_duration">1000</integer> - <!-- - 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>floatMaxValue</item> - <!-- Modest : Suggestion whose normalized score is greater than this value - will be subject to auto-correction. --> - <item>0.185</item> - <!-- Aggressive --> - <item>0.067</item> - <!-- Very Aggressive : Suggestion whose normalized score is greater than this value - will be subject to auto-correction. "floatNegativeInfinity" is a special marker - string for Float.NEGATIVE_INFINITY --> - <item>floatNegativeInfinity</item> - </string-array> - <!-- 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> - <!-- Screen metrics for logging. - 0 = "mdpi phone screen" - 1 = "hdpi phone screen" - 2 = "mdpi 11 inch tablet screen" - 3 = "xhdpi phone screen?" - 4 = ? - --> - <integer name="log_screen_metrics">0</integer> - <!-- Settings for the dictionary pack --> - <bool name="allow_over_metered">false</bool> - <bool name="allow_over_roaming">false</bool> - <bool name="dict_downloads_visible_in_download_UI">false</bool> - <bool name="metadata_downloads_visible_in_download_UI">false</bool> - <bool name="display_notification_for_auto_update">false</bool> - <bool name="display_notification_for_user_requested_update">false</bool> + <!-- Preferable keyboard height in absolute scale: 1.285in --> + <!-- This config_default_keyboard_height value should match with keyboard-heights.xml --> + <dimen name="config_default_keyboard_height">205.6dp</dimen> + <fraction name="config_max_keyboard_height">46%p</fraction> + <fraction name="config_min_keyboard_height">-61.8%p</fraction> + <dimen name="config_more_keys_keyboard_key_height">52.8dp</dimen> + <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> + <!-- config_more_keys_keyboard_key_height x 1.2 --> + <dimen name="config_more_keys_keyboard_slide_allowance">63.36dp</dimen> + <dimen name="config_more_keys_keyboard_key_horizontal_padding">8dp</dimen> + + <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction> + <fraction name="config_keyboard_bottom_padding_holo">4.669%p</fraction> + <fraction name="config_key_vertical_gap_holo">6.127%p</fraction> + <fraction name="config_key_horizontal_gap_holo">1.739%p</fraction> + <!-- config_more_keys_keyboard_key_height x -0.5 --> + <dimen name="config_more_keys_keyboard_vertical_correction_holo">-26.4dp</dimen> + <dimen name="config_key_preview_offset_holo">8.0dp</dimen> + + <dimen name="config_key_preview_height">80dp</dimen> + <fraction name="config_key_preview_text_ratio">82%</fraction> + <fraction name="config_key_letter_ratio">55%</fraction> + <fraction name="config_key_large_letter_ratio">65%</fraction> + <fraction name="config_key_label_ratio">34%</fraction> + <fraction name="config_key_large_label_ratio">40%</fraction> + <fraction name="config_key_hint_letter_ratio">25%</fraction> + <fraction name="config_key_hint_label_ratio">44%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio">35%</fraction> + <fraction name="config_language_on_spacebar_text_ratio">33.735%</fraction> + <dimen name="config_key_label_horizontal_padding">4dp</dimen> + <dimen name="config_key_hint_letter_padding">1dp</dimen> + <dimen name="config_key_shifted_letter_hint_padding">2dp</dimen> + + <!-- For 5-row keyboard --> + <fraction name="config_key_vertical_gap_5row">3.20%p</fraction> + <fraction name="config_key_letter_ratio_5row">64%</fraction> + <fraction name="config_key_shifted_letter_hint_ratio_5row">41%</fraction> + + <dimen name="config_suggestions_strip_height">40dp</dimen> + <dimen name="config_more_suggestions_row_height">40dp</dimen> + <integer name="config_max_more_suggestions_row">6</integer> + <fraction name="config_min_more_suggestions_width">90%</fraction> + <dimen name="config_suggestions_strip_horizontal_padding">0dp</dimen> + <dimen name="config_suggestion_min_width">44dp</dimen> + <dimen name="config_suggestion_text_horizontal_padding">6dp</dimen> + <dimen name="config_suggestion_text_size">18dp</dimen> + <dimen name="config_more_suggestions_hint_text_size">27dp</dimen> + + <!-- Gesture floating preview text parameters --> + <dimen name="config_gesture_floating_preview_text_size">24dp</dimen> + <dimen name="config_gesture_floating_preview_text_offset">73dp</dimen> + <dimen name="config_gesture_floating_preview_horizontal_padding">24dp</dimen> + <dimen name="config_gesture_floating_preview_vertical_padding">16dp</dimen> + <dimen name="config_gesture_floating_preview_round_radius">2dp</dimen> + + <!-- Emoji keyboard --> + <fraction name="config_emoji_keyboard_key_width">14.2857%p</fraction> + <fraction name="config_emoji_keyboard_row_height">33%p</fraction> + <fraction name="config_emoji_keyboard_key_letter_size">68%p</fraction> + <integer name="config_emoji_keyboard_max_page_key_count">21</integer> </resources> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml deleted file mode 100644 index 4588b10eb..000000000 --- a/java/res/values/dimens.xml +++ /dev/null @@ -1,132 +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. -*/ ---> - -<resources> - <!-- Preferable keyboard height in absolute scale: 1.285in --> - <!-- This keyboardHeight value should match with keyboard-heights.xml --> - <dimen name="keyboardHeight">205.6dp</dimen> - <fraction name="maxKeyboardHeight">46%p</fraction> - <fraction name="minKeyboardHeight">-61.8%p</fraction> - - <dimen name="popup_key_height">52.8dp</dimen> - - <dimen name="more_keys_keyboard_key_horizontal_padding">8dp</dimen> - - <fraction name="keyboard_left_padding">0%p</fraction> - <fraction name="keyboard_right_padding">0%p</fraction> - - <fraction name="keyboard_top_padding_gb">1.556%p</fraction> - <fraction name="keyboard_bottom_padding_gb">4.669%p</fraction> - <fraction name="key_bottom_gap_gb">6.495%p</fraction> - <fraction name="key_horizontal_gap_gb">1.971%p</fraction> - - <fraction name="keyboard_top_padding_holo">2.335%p</fraction> - <fraction name="keyboard_bottom_padding_holo">4.669%p</fraction> - <fraction name="key_bottom_gap_holo">6.127%p</fraction> - <fraction name="key_horizontal_gap_holo">1.739%p</fraction> - - <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> - <!-- popup_key_height x 1.2 --> - <dimen name="more_keys_keyboard_slide_allowance">63.36dp</dimen> - <!-- popup_key_height x -1.0 --> - <dimen name="more_keys_keyboard_vertical_correction_gb">-52.8dp</dimen> - <dimen name="keyboard_vertical_correction">0.0dp</dimen> - - <fraction name="key_letter_ratio">55%</fraction> - <fraction name="key_large_letter_ratio">65%</fraction> - <fraction name="key_label_ratio">34%</fraction> - <fraction name="key_large_label_ratio">40%</fraction> - <fraction name="key_hint_letter_ratio">25%</fraction> - <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">80dp</dimen> - <dimen name="key_preview_offset_gb">-8.0dp</dimen> - - <dimen name="key_label_horizontal_padding">4dp</dimen> - <dimen name="key_hint_letter_padding">1dp</dimen> - <dimen name="key_popup_hint_letter_padding">2dp</dimen> - <dimen name="key_uppercase_letter_padding">2dp</dimen> - - <!-- For 5-row keyboard --> - <fraction name="key_bottom_gap_5row">3.20%p</fraction> - <fraction name="key_letter_ratio_5row">64%</fraction> - <fraction name="key_uppercase_letter_ratio_5row">41%</fraction> - - <dimen name="key_preview_offset_holo">8.0dp</dimen> - <!-- popup_key_height x -0.5 --> - <dimen name="more_keys_keyboard_vertical_correction_holo">-26.4dp</dimen> - - <dimen name="suggestions_strip_height">40dp</dimen> - <dimen name="more_suggestions_key_horizontal_padding">12dp</dimen> - <dimen name="more_suggestions_row_height">40dp</dimen> - <dimen name="more_suggestions_bottom_gap">6dp</dimen> - <dimen name="more_suggestions_modal_tolerance">32.0dp</dimen> - <dimen name="more_suggestions_slide_allowance">16.0dp</dimen> - <integer name="max_more_suggestions_row">6</integer> - <fraction name="min_more_suggestions_width">90%</fraction> - <fraction name="more_suggestions_info_ratio">18%</fraction> - <dimen name="suggestions_strip_padding">0dp</dimen> - <dimen name="suggestion_min_width">44dp</dimen> - <dimen name="suggestion_padding">6dp</dimen> - <dimen name="suggestion_text_size">18dp</dimen> - <dimen name="more_suggestions_hint_text_size">27dp</dimen> - <integer name="suggestions_count_in_strip">3</integer> - <fraction name="center_suggestion_percentile">36%</fraction> - - <!-- Gesture trail parameters --> - <!-- Minimum distance between gesture trail sampling points. --> - <dimen name="gesture_trail_min_sampling_distance">9.6dp</dimen> - <!-- Maximum angular threshold between gesture trails interpolation segments in degree. --> - <integer name="gesture_trail_max_interpolation_angular_threshold">15</integer> - <!-- Maximum distance threshold between gesture trails interpolation segments. --> - <dimen name="gesture_trail_max_interpolation_distance_threshold">16.0dp</dimen> - <!-- Maximum number of gesture trail interpolation segments. --> - <integer name="gesture_trail_max_interpolation_segments">6</integer> - <dimen name="gesture_trail_start_width">10.0dp</dimen> - <dimen name="gesture_trail_end_width">2.5dp</dimen> - <!-- Percentages of gesture preview taril body and shadow, in proportion to the trail width. - A negative value of the shadow ratio disables drawing shadow. --> - <!-- TODO: May use the shadow to alleviate rugged trail drawing. --> - <integer name="gesture_trail_body_ratio">100</integer> - <integer name="gesture_trail_shadow_ratio">-1</integer> - <!-- Gesture floating preview text parameters --> - <dimen name="gesture_floating_preview_text_size">24dp</dimen> - <dimen name="gesture_floating_preview_text_offset">73dp</dimen> - <dimen name="gesture_floating_preview_horizontal_padding">24dp</dimen> - <dimen name="gesture_floating_preview_vertical_padding">16dp</dimen> - <dimen name="gesture_floating_preview_round_radius">2dp</dimen> - - <!-- Emoji keyboard --> - <fraction name="emoji_keyboard_key_width">14.2857%p</fraction> - <fraction name="emoji_keyboard_row_height">33%p</fraction> - <fraction name="emoji_keyboard_key_letter_size">68%p</fraction> - <integer name="emoji_keyboard_max_key_count">21</integer> - <dimen name="emoji_category_page_id_height">3dp</dimen> - - <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. --> - <dimen name="accessibility_edge_slop">8dp</dimen> - - <integer name="user_dictionary_max_word_length" translatable="false">48</integer> - - <dimen name="language_on_spacebar_horizontal_margin">1dp</dimen> - -</resources> diff --git a/java/res/values/donottranslate-config-important-notice.xml b/java/res/values/donottranslate-config-important-notice.xml new file mode 100644 index 000000000..7c6527c28 --- /dev/null +++ b/java/res/values/donottranslate-config-important-notice.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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> + <!-- The array of the text of the important notices displayed on the suggestion strip. --> + <string-array name="important_notice_title_array" translatable="false"> + <!-- empty --> + </string-array> + <!-- The array of the contents of the important notices. --> + <string-array name="important_notice_contents_array" translatable="false"> + <!-- empty --> + </string-array> +</resources> diff --git a/java/res/values/donottranslate-config-spacing-and-punctuations.xml b/java/res/values/donottranslate-config-spacing-and-punctuations.xml new file mode 100644 index 000000000..1be5cf888 --- /dev/null +++ b/java/res/values/donottranslate-config-spacing-and-punctuations.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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"> + <!-- TODO: these settings depend on the language. They should be put either in the dictionary + header, or in the subtype maybe? --> + <!-- Symbols that are suggested between words --> + <string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string> + <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) --> + <string name="symbols_preceded_by_space">([{&</string> + <!-- Symbols that are normally followed by a space (used to add an auto-space after these) --> + <string name="symbols_followed_by_space">.,;:!?)]}&</string> + <!-- Symbols that separate words --> + <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> + <string name="symbols_word_separators">"	 
 "()[]{}*&<>+=|.,;:!?/_\"</string> + <!-- Word connectors --> + <string name="symbols_word_connectors">\'-</string> + <!-- The sentence separator code point, for capitalization --> + <!-- U+002E: "." FULL STOP ; 2Eh = 46d --> + <integer name="sentence_separator">46</integer> + <!-- Whether this language uses spaces between words --> + <bool name="current_language_has_spaces">true</bool> +</resources> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index af5ec061b..9a610a0d0 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -18,25 +18,6 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- TODO: these settings depend on the language. They should be put either in the dictionary - header, or in the subtype maybe? --> - <!-- Symbols that are suggested between words --> - <string name="suggested_punctuations">!,?,\\,,:,;,\",(,),\',-,/,@,_</string> - <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) --> - <string name="symbols_preceded_by_space">([{&</string> - <!-- Symbols that are normally followed by a space (used to add an auto-space after these) --> - <string name="symbols_followed_by_space">.,;:!?)]}&</string> - <!-- Symbols that separate words --> - <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) --> - <string name="symbols_word_separators">"	 \n"()[]{}*&<>+=|.,;:!?/_\"</string> - <!-- Word connectors --> - <string name="symbols_word_connectors">\'-</string> - <!-- The sentence separator code point, for capitalization --> - <!-- U+002E: "." FULL STOP ; 2Eh = 46d --> - <integer name="sentence_separator">46</integer> - <!-- Whether this language uses spaces between words --> - <bool name="current_language_has_spaces">true</bool> - <!-- Always show the suggestion strip --> <string name="prefs_suggestion_visibility_show_value">0</string> <!-- Show the suggestion strip only on portrait mode --> @@ -57,74 +38,22 @@ <item>@string/prefs_suggestion_visibility_hide_name</item> </string-array> - <string name="auto_correction_threshold_mode_index_off">0</string> - <string name="auto_correction_threshold_mode_index_modest">1</string> - <string name="auto_correction_threshold_mode_index_aggressive">2</string> - <string name="auto_correction_threshold_mode_index_very_aggressive">3</string> - <string-array name="auto_correction_threshold_mode_indexes"> - <item>@string/auto_correction_threshold_mode_index_off</item> - <item>@string/auto_correction_threshold_mode_index_modest</item> - <item>@string/auto_correction_threshold_mode_index_aggressive</item> - <item>@string/auto_correction_threshold_mode_index_very_aggressive</item> - </string-array> - <string-array name="auto_correction_threshold_modes"> - <item>@string/auto_correction_threshold_mode_off</item> - <item>@string/auto_correction_threshold_mode_modest</item> - <item>@string/auto_correction_threshold_mode_aggressive</item> - <item>@string/auto_correction_threshold_mode_very_aggressive</item> - </string-array> - + <!-- For backward compatibility. + See {@link SettingsValues#needsToShowVoiceInputKey(SharedPreferences,Resources)} --> <string name="voice_mode_main">0</string> - <string name="voice_mode_symbols">1</string> - <string name="voice_mode_off">2</string> - <string-array name="voice_input_modes_values"> - <item>@string/voice_mode_main</item> - <item>@string/voice_mode_symbols</item> - <item>@string/voice_mode_off</item> - </string-array> - <!-- Array of Voice Input modes --> - <string-array name="voice_input_modes"> - <item>@string/voice_input_modes_main_keyboard</item> - <item>@string/voice_input_modes_symbols_keyboard</item> - <item>@string/voice_input_modes_off</item> - </string-array> - <!-- Array of Voice Input modes summary --> - <string-array name="voice_input_modes_summary"> - <item>@string/voice_input_modes_summary_main_keyboard</item> - <item>@string/voice_input_modes_summary_symbols_keyboard</item> - <item>@string/voice_input_modes_summary_off</item> - </string-array> <!-- 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_gingerbread">Gingerbread</string> - <string name="layout_ics">IceCreamSandwich</string> - <string name="layout_klp">KeyLimePie</string> - - <!-- For keyboard theme switcher dialog --> - <string-array name="keyboard_layout_modes"> - <item>@string/layout_ics</item> - <item>@string/layout_gingerbread</item> - <item>@string/layout_klp</item> - </string-array> - <!-- An element must be an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. --> - <string-array name="keyboard_layout_modes_values"> - <item>0</item> - <item>1</item> - <item>2</item> - </string-array> - <!-- For keyboard color scheme option dialog. --> - <string-array name="keyboard_color_schemes"> + <string-array name="keyboard_theme_names"> <item>@string/keyboard_color_scheme_white</item> <item>@string/keyboard_color_scheme_blue</item> </string-array> - <!-- An element must be an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. --> - <string-array name="keyboard_color_schemes_values"> + <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. --> + <string-array name="keyboard_theme_ids"> <item>2</item> <item>0</item> </string-array> diff --git a/java/res/values/keyboard-heights.xml b/java/res/values/keyboard-heights.xml index c651a89b3..12dd51d9d 100644 --- a/java/res/values/keyboard-heights.xml +++ b/java/res/values/keyboard-heights.xml @@ -33,7 +33,5 @@ <!-- Preferable keyboard height in absolute scale: 48.0mm --> <!-- Xoom --> <item>HARDWARE=stingray,283.1337</item> - <!-- Default value for unknown device: empty string --> - <item>,</item> </string-array> </resources> diff --git a/java/res/values/keyboard-icons-holo.xml b/java/res/values/keyboard-icons-holo.xml index b49e1d10b..4c888d570 100644 --- a/java/res/values/keyboard-icons-holo.xml +++ b/java/res/values/keyboard-icons-holo.xml @@ -32,7 +32,6 @@ <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item> <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item> <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo_dark</item> - <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo_dark</item> <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item> <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item> <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo_dark</item> diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml index cde4e4447..032b5fd91 100644 --- a/java/res/values/keypress-vibration-durations.xml +++ b/java/res/values/keypress-vibration-durations.xml @@ -59,7 +59,5 @@ <item>MODEL=XT1035:MANUFACTURER=motorola,18</item> <!-- Sony Xperia Z, Z Ultra --> <item>MODEL=C6603|C6806:MANUFACTURER=Sony,35</item> - <!-- Default value for unknown device. The negative value means system default. --> - <item>,-1</item> </string-array> </resources> diff --git a/java/res/values/keypress-volumes.xml b/java/res/values/keypress-volumes.xml index d359055c2..074581d00 100644 --- a/java/res/values/keypress-volumes.xml +++ b/java/res/values/keypress-volumes.xml @@ -26,7 +26,5 @@ <item>HARDWARE=grouper,0.3f</item> <item>HARDWARE=mako,0.3f</item> <item>HARDWARE=manta,0.2f</item> - <!-- Default value for unknown device. The negative value means system default. --> - <item>,-1.0f</item> </string-array> </resources> diff --git a/java/res/values/phantom-sudden-move-event-device-list.xml b/java/res/values/phantom-sudden-move-event-device-list.xml index 53002b31e..4f91cd389 100644 --- a/java/res/values/phantom-sudden-move-event-device-list.xml +++ b/java/res/values/phantom-sudden-move-event-device-list.xml @@ -23,7 +23,5 @@ See {@link com.android.inputmethod.keyboard.PointerTracker}. --> <!-- Xoom --> <item>HARDWARE=stingray,true</item> - <!-- Default value for unknown device --> - <item>,false</item> </string-array> </resources> diff --git a/java/res/values/platform-theme.xml b/java/res/values/platform-theme.xml new file mode 100644 index 000000000..8e131a2b0 --- /dev/null +++ b/java/res/values/platform-theme.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:android="http://schemas.android.com/apk/res/android"> + <style name="platformActivityTheme" parent="@android:style/Theme.Holo" /> + <style name="platformDialogTheme" parent="@android:style/Theme.Holo.Dialog" /> +</resources> diff --git a/java/res/values/strings-config-important-notice.xml b/java/res/values/strings-config-important-notice.xml new file mode 100644 index 000000000..aa3cd109c --- /dev/null +++ b/java/res/values/strings-config-important-notice.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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> + <integer name="config_important_notice_version">0</integer> + <!-- Description for option enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy [CHAR LIMIT=68] --> + <string name="use_personalized_dicts_summary">Learn from your communications and typed data to improve suggestions</string> +</resources> diff --git a/java/res/values/strings-talkback-descriptions.xml b/java/res/values/strings-talkback-descriptions.xml new file mode 100644 index 000000000..4ffca10c8 --- /dev/null +++ b/java/res/values/strings-talkback-descriptions.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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"> + <!-- Spoken description to let the user know that when typing in a password, they can plug in a headset in to hear spoken descriptions of the keys they type. [CHAR LIMIT=NONE] --> + <string name="spoken_use_headphones">Plug in a headset to hear password keys spoken aloud.</string> + + <!-- Spoken description for the currently entered text --> + <string name="spoken_current_text_is">Current text is "%s"</string> + <!-- Spoken description when there is no text entered --> + <string name="spoken_no_text_entered">No text entered</string> + + <!-- Spoken description to let the user know what auto-correction will be performed when a key is pressed. An auto-correction replaces a single word with one or more words. --> + <string name="spoken_auto_correct"><xliff:g id="KEY_NAME" example="Space">%1$s</xliff:g> corrects <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> to <xliff:g id="CORRECTED_WORD">%3$s</xliff:g></string> + <!-- Spoken description used during obscured (e.g. password) entry to let the user know that auto-correction will be performed when a key is pressed. --> + <string name="spoken_auto_correct_obscured"><xliff:g id="KEY_NAME" example="Space">%1$s</xliff:g> performs auto-correction</string> + + <!-- Spoken description for unknown keyboard keys. --> + <string name="spoken_description_unknown">Key code %d</string> + <!-- 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 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. --> + <string name="spoken_description_to_symbol">Symbols</string> + <!-- Spoken description for the "To Alpha" keyboard key. --> + <string name="spoken_description_to_alpha">Letters</string> + <!-- Spoken description for the "To Numbers" keyboard key. --> + <string name="spoken_description_to_numeric">Numbers</string> + <!-- Spoken description for the "Settings" keyboard key. --> + <string name="spoken_description_settings">Settings</string> + <!-- Spoken description for the "Tab" keyboard key. --> + <string name="spoken_description_tab">Tab</string> + <!-- Spoken description for the "Space" keyboard key. --> + <string name="spoken_description_space">Space</string> + <!-- Spoken description for the "Mic" keyboard key. --> + <string name="spoken_description_mic">Voice input</string> + <!-- Spoken description for the "Emoji" keyboard key. --> + <string name="spoken_description_emoji">Emoji</string> + <!-- Spoken description for the "Return" keyboard key. --> + <string name="spoken_description_return">Return</string> + <!-- Spoken description for the "Search" keyboard key. --> + <string name="spoken_description_search">Search</string> + <!-- Spoken description for the "U+2022" (BULLET) keyboard key. --> + <string name="spoken_description_dot">Dot</string> + <!-- Spoken description for the "Switch language" keyboard key. --> + <string name="spoken_description_language_switch">Switch language</string> + <!-- Spoken description for the "Next" action keyboard key. --> + <string name="spoken_description_action_next">Next</string> + <!-- Spoken description for the "Previous" action keyboard key. --> + <string name="spoken_description_action_previous">Previous</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 changing to the symbols keyboard. --> + <string name="spoken_description_mode_symbol">Symbols mode</string> + <!-- Spoken feedback after changing to the symbols shift keyboard. --> + <string name="spoken_description_mode_symbol_shift">Symbols shift 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> + + <!-- Spoken feedback when the keyboard is hidden. --> + <string name="announce_keyboard_hidden">Keyboard hidden</string> + <!-- Spoken feedback when the keyboard mode changes. --> + <string name="announce_keyboard_mode">Showing <xliff:g id="KEYBOARD_MODE" example="email">%s</xliff:g> keyboard</string> + <!-- Description of the keyboard mode for entering dates. --> + <string name="keyboard_mode_date">date</string> + <!-- Description of the keyboard mode for entering dates and times. --> + <string name="keyboard_mode_date_time">date and time</string> + <!-- Description of the keyboard mode for entering email addresses. --> + <string name="keyboard_mode_email">email</string> + <!-- Description of the keyboard mode for entering text messages. --> + <string name="keyboard_mode_im">messaging</string> + <!-- Description of the keyboard mode for entering numbers. --> + <string name="keyboard_mode_number">number</string> + <!-- Description of the keyboard mode for entering phone numbers. --> + <string name="keyboard_mode_phone">phone</string> + <!-- Description of the keyboard mode for entering generic text. --> + <string name="keyboard_mode_text">text</string> + <!-- Description of the keyboard mode for entering times. --> + <string name="keyboard_mode_time">time</string> + <!-- Description of the keyboard mode for entering URLs. --> + <string name="keyboard_mode_url">URL</string> + + <!-- Description of the emoji category icon of Recents. --> + <string name="spoken_descrption_emoji_category_recents">Recents</string> + <!-- Description of the emoji category icon of People. --> + <string name="spoken_descrption_emoji_category_people">People</string> + <!-- Description of the emoji category icon of Objects. --> + <string name="spoken_descrption_emoji_category_objects">Objects</string> + <!-- Description of the emoji category icon of Nature. --> + <string name="spoken_descrption_emoji_category_nature">Nature</string> + <!-- Description of the emoji category icon of Places. --> + <string name="spoken_descrption_emoji_category_places">Places</string> + <!-- Description of the emoji category icon of Symbols. --> + <string name="spoken_descrption_emoji_category_symbols">Symbols</string> + <!-- Description of the emoji category icon of Emoticons. --> + <string name="spoken_descrption_emoji_category_emoticons">Emoticons</string> +</resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 11b3ea3af..9f93055e2 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -78,7 +78,7 @@ <string name="key_preview_popup_dismiss_default_delay">Default</string> <!-- Units abbreviation for the duration (milliseconds) [CHAR LIMIT=10] --> - <string name="abbreviation_unit_milliseconds"><xliff:g id="milliseconds">%s</xliff:g>ms</string> + <string name="abbreviation_unit_milliseconds"><xliff:g id="MILLISECONDS">%s</xliff:g>ms</string> <!-- The text that represents the current settings value is the system default [CHAR LIMIT=25] --> <string name="settings_system_default">System default</string> @@ -87,6 +87,9 @@ <!-- Description for option enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=65] --> <string name="use_contacts_dict_summary">Use names from Contacts for suggestions and corrections</string> + <!-- Option name for enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy [CHAR LIMIT=25] --> + <string name="use_personalized_dicts">Personalized suggestions</string> + <!-- Option name for enabling or disabling the double-space period feature that lets double tap on spacebar insert a period followed by a space [CHAR LIMIT=30] --> <string name="use_double_space_period">Double-space period</string> <!-- Description for option enabling or disabling the double-space period feature that lets double tap on spacebar insert a period followed by a space [CHAR LIMIT=65] --> @@ -147,118 +150,15 @@ <string name="gesture_floating_preview_text">Dynamic floating preview</string> <!-- Description for "gesture_floating_preview_text" option. The user can see a suggested word floating under the moving finger during a gesture input. [CHAR LIMIT=65]--> <string name="gesture_floating_preview_text_summary">See the suggested word while gesturing</string> - - <!-- Indicates that a word has been added to the dictionary --> - <string name="added_word"><xliff:g id="word">%s</xliff:g> : Saved</string> - - <!-- Spoken description to let the user know that when typing in a password, they can plug in a headset in to hear spoken descriptions of the keys they type. [CHAR LIMIT=NONE] --> - <string name="spoken_use_headphones">Plug in a headset to hear password keys spoken aloud.</string> - - <!-- Spoken description for the currently entered text --> - <string name="spoken_current_text_is">Current text is "%s"</string> - <!-- Spoken description when there is no text entered --> - <string name="spoken_no_text_entered">No text entered</string> - - <!-- Spoken description to let the user know what auto-correction will be performed when a key is pressed. An auto-correction replaces a single word with one or more words. --> - <string name="spoken_auto_correct"><xliff:g id="key" example="Space">%1$s</xliff:g> corrects <xliff:g id="original_word">%2$s</xliff:g> to <xliff:g id="corrected">%3$s</xliff:g></string> - <!-- Spoken description used during obscured (e.g. password) entry to let the user know that auto-correction will be performed when a key is pressed. --> - <string name="spoken_auto_correct_obscured"><xliff:g id="key" example="Space">%1$s</xliff:g> performs auto-correction</string> - - <!-- Spoken description for unknown keyboard keys. --> - <string name="spoken_description_unknown">Key code %d</string> - <!-- 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 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. --> - <string name="spoken_description_to_symbol">Symbols</string> - <!-- Spoken description for the "To Alpha" keyboard key. --> - <string name="spoken_description_to_alpha">Letters</string> - <!-- Spoken description for the "To Numbers" keyboard key. --> - <string name="spoken_description_to_numeric">Numbers</string> - <!-- Spoken description for the "Settings" keyboard key. --> - <string name="spoken_description_settings">Settings</string> - <!-- Spoken description for the "Tab" keyboard key. --> - <string name="spoken_description_tab">Tab</string> - <!-- Spoken description for the "Space" keyboard key. --> - <string name="spoken_description_space">Space</string> - <!-- Spoken description for the "Mic" keyboard key. --> - <string name="spoken_description_mic">Voice input</string> - <!-- Spoken description for the "Smiley" keyboard key. --> - <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 "Search" keyboard key. --> - <string name="spoken_description_search">Search</string> - <!-- Spoken description for the "U+2022" (BULLET) keyboard key. --> - <string name="spoken_description_dot">Dot</string> - <!-- Spoken description for the "Switch language" keyboard key. --> - <string name="spoken_description_language_switch">Switch language</string> - <!-- Spoken description for the "Next" action keyboard key. --> - <string name="spoken_description_action_next">Next</string> - <!-- Spoken description for the "Previous" action keyboard key. --> - <string name="spoken_description_action_previous">Previous</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> - - <!-- Spoken feedback when the keyboard is hidden. --> - <string name="announce_keyboard_hidden">Keyboard hidden</string> - <!-- Spoken feedback when the keyboard mode changes. --> - <string name="announce_keyboard_mode">Showing <xliff:g id="mode" example="email">%s</xliff:g> keyboard</string> - <!-- Description of the keyboard mode for entering dates. --> - <string name="keyboard_mode_date">date</string> - <!-- Description of the keyboard mode for entering dates and times. --> - <string name="keyboard_mode_date_time">date and time</string> - <!-- Description of the keyboard mode for entering email addresses. --> - <string name="keyboard_mode_email">email</string> - <!-- Description of the keyboard mode for entering text messages. --> - <string name="keyboard_mode_im">messaging</string> - <!-- Description of the keyboard mode for entering numbers. --> - <string name="keyboard_mode_number">number</string> - <!-- Description of the keyboard mode for entering phone numbers. --> - <string name="keyboard_mode_phone">phone</string> - <!-- Description of the keyboard mode for entering generic text. --> - <string name="keyboard_mode_text">text</string> - <!-- Description of the keyboard mode for entering times. --> - <string name="keyboard_mode_time">time</string> - <!-- Description of the keyboard mode for entering URLs. --> - <string name="keyboard_mode_url">URL</string> + <!-- Option to enable space aware gesture input. The user can input multiple words by gliding through the space key during a gesture input. [CHAR LIMIT=30]--> + <string name="gesture_space_aware">Phrase gesture</string> + <!-- Description for "gesture_space_aware" option. The user can input multiple words by gliding through the space key during a gesture input.[CHAR LIMIT=65]--> + <string name="gesture_space_aware_summary">Input spaces during gestures by gliding to the space key</string> <!-- Preferences item for enabling speech input --> <string name="voice_input">Voice input key</string> - - <!-- Voice Input modes --> - <!-- On settings screen, voice input pop-up menu option to show voice key on main keyboard [CHAR LIMIT=20] --> - <string name="voice_input_modes_main_keyboard">On main keyboard</string> - <!-- On settings screen, voice input pop-up menu option to show voice key on symbols keyboard [CHAR LIMIT=20] --> - <string name="voice_input_modes_symbols_keyboard">On symbols keyboard</string> - <!-- On settings screen, voice input pop-up menu option to never show voice key [CHAR LIMIT=20] --> - <string name="voice_input_modes_off">Off</string> - <!-- Voice Input modes summary --> - <!-- On settings screen, voice input pop-up menu summary text to show voice key on main keyboard [CHAR LIMIT=20] --> - <string name="voice_input_modes_summary_main_keyboard">Mic on main keyboard</string> - <!-- On settings screen, voice input pop-up menu summary text to show voice key on symbols keyboard [CHAR LIMIT=20] --> - <string name="voice_input_modes_summary_symbols_keyboard">Mic on symbols keyboard</string> - <!-- On settings screen, voice input pop-up menu summary text to never show voice key [CHAR LIMIT=20] --> - <string name="voice_input_modes_summary_off">Voice input is disabled</string> + <!-- The summary text to describe the reason why the "Voice input key" option is disabled. [CHAR LIMIT=100] --> + <string name="voice_input_disabled_summary">No voice input methods enabled. Check Language & input settings.</string> <!-- Title for configuring input method settings [CHAR LIMIT=35] --> <string name="configure_input_method">Configure input methods</string> @@ -346,32 +246,40 @@ <!-- Title of the item to change the keyboard theme [CHAR LIMIT=20]--> <string name="keyboard_layout">Keyboard theme</string> - <!-- Description for English (United Kingdom) keyboard subtype [CHAR LIMIT=25] --> + <!-- Description for English (UK) keyboard subtype [CHAR LIMIT=25] + (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. --> <string name="subtype_en_GB">English (UK)</string> - <!-- Description for English (United States) keyboard subtype [CHAR LIMIT=25] --> + <!-- Description for English (US) keyboard subtype [CHAR LIMIT=25] + (US) should be an abbreviation of United States to fit in the CHAR LIMIT. --> <string name="subtype_en_US">English (US)</string> - <!-- Description for Spanish (United States) keyboard subtype [CHAR LIMIT=25] --> + <!-- Description for Spanish (US) keyboard subtype [CHAR LIMIT=25] + (US) should be an abbreviation of United States to fit in the CHAR LIMIT. --> <string name="subtype_es_US">Spanish (US)</string> - <!-- Description for English (United Kingdom) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + <!-- Description for English (UK) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. This should be identical to subtype_en_GB aside from the trailing (%s). --> - <string name="subtype_with_layout_en_GB">English (UK) (<xliff:g id="layout">%s</xliff:g>)</string> - <!-- Description for English (United States) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + <string name="subtype_with_layout_en_GB">English (UK) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> + <!-- Description for English (US) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + (US) should be an abbreviation of United States to fit in the CHAR LIMIT. This should be identical to subtype_en_US aside from the trailing (%s). --> - <string name="subtype_with_layout_en_US">English (US) (<xliff:g id="layout">%s</xliff:g>)</string> - <!-- Description for Spanish (United States) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + <string name="subtype_with_layout_en_US">English (US) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> + <!-- Description for Spanish (US) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] + (US) should be an abbreviation of United Statesn to fit in the CHAR LIMIT. This should be identical to subtype_es_US aside from the trailing (%s). --> - <string name="subtype_with_layout_es_US">Spanish (US) (<xliff:g id="layout">%s</xliff:g>)</string> - <!-- Description for Nepali (Traditional) keyboard subtype [CHAR LIMIT=25] --> - <string name="subtype_nepali_traditional"><xliff:g id="language">%s</xliff:g> (Traditional)</string> - <!-- TODO: Uncomment once we can handle IETF language tag with script name specified. - Description for Serbian Cyrillic keyboard subtype [CHAR LIMIT=25] - <string name="subtype_serbian_cyrillic">Serbian (Cyrillic)</string> - Description for Serbian Latin keyboard subtype [CHAR LIMIT=25] - <string name="subtype_serbian_latin">Serbian (Latin)</string> - Description for Serbian Latin keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] - This should be identical to subtype_serbian_latin aside from the trailing (%s). - <string name="subtype_with_layout_sr-Latn">Serbian (Latin) (<xliff:g id="layout">%s</xliff:g>)</string> - --> + <string name="subtype_with_layout_es_US">Spanish (US) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> + <!-- Description for "LANGUAGE_NAME" (Traditional) keyboard subtype [CHAR LIMIT=25] + (Traditional) can be an abbreviation to fit in the CHAR LIMIT. --> + <string name="subtype_generic_traditional"><xliff:g id="LANGUAGE_NAME" example="Nepali">%s</xliff:g> (Traditional)</string> + <!-- Description for "LANGUAGE_NAME" (Compact) keyboard subtype [CHAR LIMIT=25] + (Compact) can be an abbreviation to fit in the CHAR LIMIT. + TODO: Remove translatable=false once we are settled down with the naming. --> + <string name="subtype_generic_compact" translatable="false"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string> + <!-- Description for "LANGUAGE_NAME" (Cyrillic) keyboard subtype [CHAR LIMIT=25] + (Cyrillic) can be an abbreviation to fit in the CHAR LIMIT. --> + <string name="subtype_generic_cyrillic"><xliff:g id="LANGUAGE_NAME" example="Serbian">%s</xliff:g> (Cyrillic)</string> + <!-- Description for "LANGUAGE_NAME" (Latin) keyboard subtype [CHAR LIMIT=25] + (Latin) can be an abbreviation to fit in the CHAR LIMIT. --> + <string name="subtype_generic_latin"><xliff:g id="LANGUAGE_NAME" example="Serbian">%s</xliff:g> (Latin)</string> <!-- This string is displayed in a language list that allows to choose a language for suggestions in a software keyboard. This setting won't give suggestions in any particular language, hence "No language". @@ -480,7 +388,7 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Title of the button to postpone enabling a custom input style entry in the settings dialog [CHAR LIMIT=15] --> <string name="not_now">Not now</string> <!-- Toast text to describe the same input style already exists [CHAR LIMIT=64]--> - <string name="custom_input_style_already_exists">"The same input style already exists: <xliff:g id="input_style_name">%s</xliff:g>"</string> + <string name="custom_input_style_already_exists">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME" example="English (Dvorak)">%s</xliff:g>"</string> <!-- Title of an option for usability study mode --> <string name="prefs_usability_study_mode">Usability study mode</string> @@ -490,26 +398,38 @@ mobile devices. [CHAR LIMIT=25] --> <string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string> <!-- Title of the settings for keypress sound volume [CHAR LIMIT=35] --> <string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string> + <!-- Title of the settings for key popup show up animation duration (in milliseconds) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_show_up_duration_settings" translatable="false">Key popup show up duration</string> + <!-- Title of the settings for key popup dismiss animation duration (in milliseconds) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_dismiss_duration_settings" translatable="false">Key popup dismiss duration</string> + <!-- Title of the settings for key popup show up animation start scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_show_up_start_scale_settings" translatable="false">Key popup show up start scale</string> + <!-- Title of the settings for key popup dismiss animation end scale (in percentile) [CHAR LIMIT=35] --> + <string name="prefs_key_popup_dismiss_end_scale_settings" translatable="false">Key popup dismiss end scale</string> <!-- Title of the settings for reading an external dictionary file --> <string name="prefs_read_external_dictionary">Read external dictionary file</string> - <!-- Title of the settings for using only personalization dictionary --> - <string name="prefs_use_only_personalization_dictionary" translatable="false">Use only personalization dictionary</string> - <!-- Title of the settings for boosting personalization dictionary --> - <string name="prefs_boost_personalization_dictionary" translatable="false">Boost personalization dictionary</string> <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] --> <string name="read_external_dictionary_no_files_message">No dictionary files in the Downloads folder</string> <!-- Title of the dialog that selects a file to install as an external dictionary [CHAR LIMIT=50] --> <string name="read_external_dictionary_multiple_files_title">Select a dictionary file to install</string> <!-- Title of the confirmation dialog to install a file as an external dictionary [CHAR LIMIT=50] --> - <string name="read_external_dictionary_confirm_install_message">Really install this file for <xliff:g id="locale_name">%s</xliff:g>?</string> + <string name="read_external_dictionary_confirm_install_message">Really install this file for <xliff:g id="LANGUAGE_NAME" example="English">%s</xliff:g>?</string> <!-- Title for an error dialog that contains the details of the error in the body [CHAR LIMIT=80] --> <string name="error">There was an error</string> + <!-- Title of the settings for dumpping contacts dictionary file [CHAR LIMIT=35] --> + <string name="prefs_dump_contacts_dict">Dump contacts dictionary</string> + <!-- Title of the settings for dumpping personal dictionary file [CHAR LIMIT=35] --> + <string name="prefs_dump_user_dict">Dump personal dictionary</string> + <!-- Title of the settings for dumpping user history dictionary file [CHAR LIMIT=35] --> + <string name="prefs_dump_user_history_dict">Dump user history dictionary</string> + <!-- Title of the settings for dumpping personalization dictionary file [CHAR LIMIT=35] --> + <string name="prefs_dump_personalization_dict">Dump personalization dictionary</string> <!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] --> <string name="button_default">Default</string> <!-- Title of the setup wizard welcome screen. [CHAR LIMT=40] --> - <string name="setup_welcome_title">"Welcome to <xliff:g id="application_name">%s</xliff:g>"</string> + <string name="setup_welcome_title">"Welcome to <xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>"</string> <!-- Additional title of the setup wizard welcome screen, just below the setup_welcome_title. [CHAR_LIMIT=64] --> <string name="setup_welcome_additional_description">with Gesture Typing</string> <!-- The label of the button that starts the setup wizard. [CHAR_LIMIT=64] --> @@ -517,23 +437,23 @@ mobile devices. [CHAR LIMIT=25] --> <!-- The label of the button that navigates the user to the next step of the setup wizard. [CHAR_LIMIT=64] --> <string name="setup_next_action">Next step</string> <!-- Title of the setup wizard. [CHAR LIMT=40] --> - <string name="setup_steps_title">"Setting up <xliff:g id="application_name">%s</xliff:g>"</string> + <string name="setup_steps_title">"Setting up <xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>"</string> <!-- Ordinal number of the 1st step in the setup wizard. [CHAR LIMIT=5] --> <string name="setup_step1_bullet" translatable="false">1</string> <!-- Title of the 1st step in the setup wizard. [CHAR LIMIT=64] --> - <string name="setup_step1_title">"Enable <xliff:g id="application_name">%s</xliff:g>"</string> + <string name="setup_step1_title">"Enable <xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>"</string> <!-- Detailed instruction of the 1st step in the setup wizard. [CHAR LIMIT=120] --> - <string name="setup_step1_instruction">"Please check \"<xliff:g id="application_name">%s</xliff:g>\" in your Language & input settings. This will authorize it to run on your device."</string> + <string name="setup_step1_instruction">"Please check \"<xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>\" in your Language & input settings. This will authorize it to run on your device."</string> <!-- Detailed instruction of the already finished 1st step in the setup wizard. [CHAR LIMIT=120] --> - <string name="setup_step1_finished_instruction">"<xliff:g id="application_name">%s</xliff:g> is already enabled in your Language & input settings, so this step is done. On to the next one!"</string> + <string name="setup_step1_finished_instruction">"<xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g> is already enabled in your Language & input settings, so this step is done. On to the next one!"</string> <!-- The label of the button that triggers the Language & input settings in order to enable the keyboard. [CHAR_LIMIT=64] --> <string name="setup_step1_action">Enable in Settings</string> <!-- Ordinal number of the 2nd step in the setup wizard. [CHAR LIMIT=5] --> <string name="setup_step2_bullet" translatable="false">2</string> <!-- Title of the 2nd step in the setup wizard. [CHAR LIMIT=64] --> - <string name="setup_step2_title">"Switch to <xliff:g id="application_name">%s</xliff:g>"</string> + <string name="setup_step2_title">"Switch to <xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>"</string> <!-- Detailed instruction of the 2nd step in the setup wizard. [CHAR LIMIT=120] --> - <string name="setup_step2_instruction">"Next, select \"<xliff:g id="application_name">%s</xliff:g>\" as your active text-input method."</string> + <string name="setup_step2_instruction">"Next, select \"<xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>\" as your active text-input method."</string> <!-- The label of the button that triggers the choose input method dialog in order to select the keyboard. [CHAR_LIMIT=64] --> <string name="setup_step2_action">Switch input methods</string> <!-- Ordinal number of the 3rd step in the setup wizard. [CHAR LIMIT=5] --> @@ -541,7 +461,7 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Title of the 3rd step in the setup wizard. [CHAR LIMIT=64] --> <string name="setup_step3_title">"Congratulations, you're all set!"</string> <!-- Detailed instruction of the 3rd step in the setup wizard. [CHAR LIMIT=120] --> - <string name="setup_step3_instruction">Now you can type in all your favorite apps with <xliff:g id="application_name">%s</xliff:g>.</string> + <string name="setup_step3_instruction">Now you can type in all your favorite apps with <xliff:g id="APPLICATION_NAME" example="Android Keyboard">%s</xliff:g>.</string> <!-- The label of the button that triggers the screen for configuaring additional languages of the keyboard. [CHAR_LIMIT=64] --> <string name="setup_step3_action">Configure additional languages</string> <!-- The label of the button that finishes the setup wizard. [CHAR_LIMIT=64] --> @@ -592,13 +512,15 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Message to display in a dialog box while we are actively updating the word list [CHAR LIMIT=60] --> <string name="message_updating">Checking for updates</string> <!-- Message to display while the add-on dictionary list is updating [no space constraints on this, there is plenty of space but shorter is better because it's only on the screen for a second] --> - <string name="message_loading">Loading...</string> + <string name="message_loading">Loading…</string> <!-- String to explain this dictionary is the main dictionary for this language [CHAR_LIMIT=30] --> <string name="main_dict_description">Main dictionary</string> <!-- Standard message to dismiss a dialog box --> <string name="cancel">Cancel</string> + <!-- Title of the button in a dialog box. The button takes the user to the keyboard settings. [CHAR LIMIT=15] --> + <string name="go_to_settings">Settings</string> <!-- Action to download and install a dictionary [CHAR_LIMIT=15] --> <string name="install_dict">Install</string> @@ -609,24 +531,24 @@ mobile devices. [CHAR LIMIT=25] --> <!-- Message in the popup informing the user a dictionary is available for their language, and asking for a decision to download over their mobile data plan or not. The reason we ask for this is, the data is large and may be downloaded over a paid-per-megabyte connection but a dictionary is also essential to type comfortably, so we ask the user. This only pops in selected cases, when there is no dictionary at all currently, and the only available network seems to be metered. The "Language & input" part should be set to the actual name of the option (message ID 5292716747264442359 in the translation console). [CHAR_LIMIT=700] --> <string name="should_download_over_metered_prompt">The selected language on your mobile device has an available dictionary.<br/> -We recommend <b>downloading</b> the <xliff:g id="language" example="English">%1$s</xliff:g> dictionary to improve your typing experience.<br/> +We recommend <b>downloading</b> the <xliff:g id="LANGUAGE_NAME" example="English">%1$s</xliff:g> dictionary to improve your typing experience.<br/> <br/> The download could take a minute or two over 3G. Charges may apply if you don\'t have an <b>unlimited data plan</b>.<br/> If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.<br/> <br/> Tip: You can download and remove dictionaries by going to <b>Language & input</b> in the <b>Settings</b> menu of your mobile device.</string> - <string name="download_over_metered">Download now (<xliff:g id="size_in_megabytes" example="0.7">%1$.1f</xliff:g>MB)</string> + <string name="download_over_metered">Download now (<xliff:g id="SIZE_IN_MEGABYTES" example="0.7">%1$.1f</xliff:g>MB)</string> <string name="do_not_download_over_metered">Download over Wi-Fi</string> <!-- The text of the "dictionary available" notification. --> - <string name="dict_available_notification_title">A dictionary is available for <xliff:g id="language" example="English">%1$s</xliff:g></string> + <string name="dict_available_notification_title">A dictionary is available for <xliff:g id="LANGUAGE_NAME" example="English">%1$s</xliff:g></string> <!-- The small subtext in the "dictionary available" notification. --> <string name="dict_available_notification_description">Press to review and download</string> <!-- The text of the toast warning a download is starting automatically to enable suggestions for the selected language [CHAR LIMIT=100] --> - <string name="toast_downloading_suggestions">Downloading: suggestions for <xliff:g id="language" example="English">%1$s</xliff:g> will be ready soon.</string> + <string name="toast_downloading_suggestions">Downloading: suggestions for <xliff:g id="LANGUAGE_NAME" example="English">%1$s</xliff:g> will be ready soon.</string> <!-- Version text [CHAR LIMIT=30]--> - <string name="version_text">Version <xliff:g id="version_number" example="1.0.1864.643521">%1$s</xliff:g></string> + <string name="version_text">Version <xliff:g id="VERSION_NUMBER" example="1.0.1864.643521">%1$s</xliff:g></string> <!-- User dictionary settings --> <!-- User dictionary settings. The summary of the listem item to go into the User dictionary settings screen. --> diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 298936d9c..eb6cdd975 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -25,49 +25,49 @@ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_default</item> <item name="rowHeight">25%p</item> <item name="moreKeysTemplate">@xml/kbd_more_keys_keyboard_template</item> - <item name="keyboardLeftPadding">@fraction/keyboard_left_padding</item> - <item name="keyboardRightPadding">@fraction/keyboard_right_padding</item> + <item name="keyboardLeftPadding">@fraction/config_keyboard_left_padding</item> + <item name="keyboardRightPadding">@fraction/config_keyboard_right_padding</item> <item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item> </style> <style name="KeyboardView"> <item name="keyBackground">@drawable/btn_keyboard_key_klp</item> - <item name="keyLetterSize">@fraction/key_letter_ratio</item> - <item name="keyLargeLetterRatio">@fraction/key_large_letter_ratio</item> - <item name="keyLabelSize">@fraction/key_label_ratio</item> - <item name="keyLargeLabelRatio">@fraction/key_large_label_ratio</item> - <item name="keyHintLetterRatio">@fraction/key_hint_letter_ratio</item> - <item name="keyHintLabelRatio">@fraction/key_hint_label_ratio</item> - <item name="keyShiftedLetterHintRatio">@fraction/key_uppercase_letter_ratio</item> + <item name="keyLetterSize">@fraction/config_key_letter_ratio</item> + <item name="keyLargeLetterRatio">@fraction/config_key_large_letter_ratio</item> + <item name="keyLabelSize">@fraction/config_key_label_ratio</item> + <item name="keyLargeLabelRatio">@fraction/config_key_large_label_ratio</item> + <item name="keyHintLetterRatio">@fraction/config_key_hint_letter_ratio</item> + <item name="keyHintLabelRatio">@fraction/config_key_hint_label_ratio</item> + <item name="keyShiftedLetterHintRatio">@fraction/config_key_shifted_letter_hint_ratio</item> <item name="keyTypeface">normal</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="keyShiftedLetterHintPadding">@dimen/key_uppercase_letter_padding</item> - <item name="keyPreviewTextRatio">@fraction/key_preview_text_ratio</item> - <item name="verticalCorrection">@dimen/keyboard_vertical_correction</item> + <item name="keyLabelHorizontalPadding">@dimen/config_key_label_horizontal_padding</item> + <item name="keyHintLetterPadding">@dimen/config_key_hint_letter_padding</item> + <item name="keyPopupHintLetterPadding">@dimen/config_key_popup_hint_letter_padding</item> + <item name="keyShiftedLetterHintPadding">@dimen/config_key_shifted_letter_hint_padding</item> + <item name="keyPreviewTextRatio">@fraction/config_key_preview_text_ratio</item> + <item name="verticalCorrection">@dimen/config_keyboard_vertical_correction</item> <item name="backgroundDimAlpha">128</item> - <item name="gestureFloatingPreviewTextSize">@dimen/gesture_floating_preview_text_size</item> - <item name="gestureFloatingPreviewTextOffset">@dimen/gesture_floating_preview_text_offset</item> - <item name="gestureFloatingPreviewHorizontalPadding">@dimen/gesture_floating_preview_horizontal_padding</item> - <item name="gestureFloatingPreviewVerticalPadding">@dimen/gesture_floating_preview_vertical_padding</item> - <item name="gestureFloatingPreviewRoundRadius">@dimen/gesture_floating_preview_round_radius</item> - <item name="gestureTrailMinSamplingDistance">@dimen/gesture_trail_min_sampling_distance</item> - <item name="gestureTrailMaxInterpolationAngularThreshold">@integer/gesture_trail_max_interpolation_angular_threshold</item> - <item name="gestureTrailMaxInterpolationDistanceThreshold">@dimen/gesture_trail_max_interpolation_distance_threshold</item> - <item name="gestureTrailMaxInterpolationSegments">@integer/gesture_trail_max_interpolation_segments</item> + <item name="gestureFloatingPreviewTextSize">@dimen/config_gesture_floating_preview_text_size</item> + <item name="gestureFloatingPreviewTextOffset">@dimen/config_gesture_floating_preview_text_offset</item> + <item name="gestureFloatingPreviewHorizontalPadding">@dimen/config_gesture_floating_preview_horizontal_padding</item> + <item name="gestureFloatingPreviewVerticalPadding">@dimen/config_gesture_floating_preview_vertical_padding</item> + <item name="gestureFloatingPreviewRoundRadius">@dimen/config_gesture_floating_preview_round_radius</item> + <item name="gestureTrailMinSamplingDistance">@dimen/config_gesture_trail_min_sampling_distance</item> + <item name="gestureTrailMaxInterpolationAngularThreshold">@integer/config_gesture_trail_max_interpolation_angular_threshold</item> + <item name="gestureTrailMaxInterpolationDistanceThreshold">@dimen/config_gesture_trail_max_interpolation_distance_threshold</item> + <item name="gestureTrailMaxInterpolationSegments">@integer/config_gesture_trail_max_interpolation_segments</item> <item name="gestureTrailFadeoutStartDelay">@integer/config_gesture_trail_fadeout_start_delay</item> <item name="gestureTrailFadeoutDuration">@integer/config_gesture_trail_fadeout_duration</item> <item name="gestureTrailUpdateInterval">@integer/config_gesture_trail_update_interval</item> - <item name="gestureTrailStartWidth">@dimen/gesture_trail_start_width</item> - <item name="gestureTrailEndWidth">@dimen/gesture_trail_end_width</item> - <item name="gestureTrailBodyRatio">@integer/gesture_trail_body_ratio</item> - <item name="gestureTrailShadowRatio">@integer/gesture_trail_shadow_ratio</item> + <item name="gestureTrailStartWidth">@dimen/config_gesture_trail_start_width</item> + <item name="gestureTrailEndWidth">@dimen/config_gesture_trail_end_width</item> + <item name="gestureTrailBodyRatio">@integer/config_gesture_trail_body_ratio</item> + <item name="gestureTrailShadowRatio">@integer/config_gesture_trail_shadow_ratio</item> <!-- Common attributes of MainKeyboardView --> <item name="keyHysteresisDistance">@dimen/config_key_hysteresis_distance</item> <item name="keyHysteresisDistanceForSlidingModifier">@dimen/config_key_hysteresis_distance_for_sliding_modifier</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="keySelectionByDraggingFinger">@bool/config_key_selection_by_dragging_finger</item> <item name="slidingKeyInputPreviewWidth">@dimen/config_sliding_key_input_preview_width</item> <item name="slidingKeyInputPreviewBodyRatio">@integer/config_sliding_key_input_preview_body_ratio</item> <item name="slidingKeyInputPreviewShadowRatio">@integer/config_sliding_key_input_preview_shadow_ratio</item> @@ -75,11 +75,13 @@ <item name="keyRepeatInterval">@integer/config_key_repeat_interval</item> <item name="longPressShiftLockTimeout">@integer/config_longpress_shift_lock_timeout</item> <item name="ignoreAltCodeKeyTimeout">@integer/config_ignore_alt_code_key_timeout</item> - <item name="keyPreviewHeight">@dimen/key_preview_height</item> + <item name="keyPreviewLayout">@layout/key_preview</item> + <item name="keyPreviewHeight">@dimen/config_key_preview_height</item> + <!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. --> <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> <item name="moreKeysKeyboardLayout">@layout/more_keys_keyboard</item> <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item> - <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="languageOnSpacebarTextRatio">@fraction/config_language_on_spacebar_text_ratio</item> <item name="languageOnSpacebarFinalAlpha">@integer/config_language_on_spacebar_final_alpha</item> <item name="languageOnSpacebarFadeoutAnimator">@anim/language_on_spacebar_fadeout</item> <!-- Remove animations for now because it could drain a non-negligible amount of battery while typing. @@ -104,6 +106,7 @@ <style name="MainKeyboardView" parent="KeyboardView" /> + <style name="KeyPreviewTextView" /> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style @@ -118,14 +121,29 @@ parent="MainKeyboardView" /> <style name="MoreKeysKeyboardContainer" /> <style name="SuggestionStripView"> - <item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item> - <item name="centerSuggestionPercentile">@fraction/center_suggestion_percentile</item> - <item name="maxMoreSuggestionsRow">@integer/max_more_suggestions_row</item> - <item name="minMoreSuggestionsWidth">@fraction/min_more_suggestions_width</item> + <item name="suggestionsCountInStrip">@integer/config_suggestions_count_in_strip</item> + <item name="centerSuggestionPercentile">@fraction/config_center_suggestion_percentile</item> + <item name="maxMoreSuggestionsRow">@integer/config_max_more_suggestions_row</item> + <item name="minMoreSuggestionsWidth">@fraction/config_min_more_suggestions_width</item> + </style> + <style name="SuggestionWord"> + <item name="android:minWidth">@dimen/config_suggestion_min_width</item> + <item name="android:textSize">@dimen/config_suggestion_text_size</item> + <item name="android:gravity">center</item> + <item name="android:paddingLeft">@dimen/config_suggestion_text_horizontal_padding</item> + <item name="android:paddingTop">0dp</item> + <item name="android:paddingRight">@dimen/config_suggestion_text_horizontal_padding</item> + <item name="android:paddingBottom">0dp</item> + <!-- Provide a haptic feedback by ourselves based on the keyboard settings. + We just need to ignore the system's haptic feedback settings. --> + <item name="android:hapticFeedbackEnabled">false</item> + <item name="android:focusable">false</item> + <item name="android:clickable">false</item> + <item name="android:singleLine">true</item> + <item name="android:ellipsize">none</item> </style> - <style name="SuggestionWord" /> <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>
\ No newline at end of file +</resources> diff --git a/java/res/values/themes-gb.xml b/java/res/values/themes-gb.xml deleted file mode 100644 index f52695f55..000000000 --- a/java/res/values/themes-gb.xml +++ /dev/null @@ -1,146 +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. -*/ ---> - -<resources> - <style name="KeyboardTheme.GB" parent="KeyboardIcons.GB"> - <item name="keyboardStyle">@style/Keyboard.GB</item> - <item name="keyboardViewStyle">@style/KeyboardView.GB</item> - <item name="mainKeyboardViewStyle">@style/MainKeyboardView.GB</item> - <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.GB</item> - <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.GB</item> - <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.GB</item> - <item name="moreKeysKeyboardContainerStyle">@style/MoreKeysKeyboardContainer.GB</item> - <item name="suggestionStripViewStyle">@style/SuggestionStripView.GB</item> - <item name="suggestionWordStyle">@style/SuggestionWord.GB</item> - </style> - <style name="KeyboardIcons.GB"> - <!-- Keyboard icons --> - <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item> - <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item> - <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item> - <item name="iconSpaceKey">@drawable/sym_keyboard_space_holo_dark</item> - <item name="iconEnterKey">@drawable/sym_keyboard_return_holo_dark</item> - <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item> - <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item> - <item name="iconShortcutKey">@drawable/sym_keyboard_mic_holo_dark</item> - <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo_dark</item> - <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item> - <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item> - <!-- TODO: Needs non-holo disabled shortcut icon drawable --> - <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo_dark</item> - <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item> - <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_dark</item> - <!-- TODO: Needs dedicated black theme ZWNJ and ZWJ icons --> - <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo_dark</item> - <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item> - <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_holo_dark</item> - </style> - <style - name="Keyboard.GB" - parent="Keyboard" - > - <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] --> - <item name="themeId">1</item> - <item name="touchPositionCorrectionData">@array/touch_position_correction_data_gb</item> - <item name="keyboardTopPadding">@fraction/keyboard_top_padding_gb</item> - <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_gb</item> - <item name="horizontalGap">@fraction/key_horizontal_gap_gb</item> - <item name="verticalGap">@fraction/key_bottom_gap_gb</item> - </style> - <style - name="KeyboardView.GB" - parent="KeyboardView" - > - <item name="android:background">@drawable/keyboard_background_gb</item> - <item name="keyBackground">@drawable/btn_keyboard_key_gb</item> - <item name="keyTypeface">bold</item> - <item name="keyTextColor">@color/key_text_color_gb</item> - <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_gb</item> - <item name="keyHintLetterColor">@color/key_hint_letter_color_gb</item> - <item name="keyHintLabelColor">@color/key_hint_label_color_gb</item> - <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_gb</item> - <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_gb</item> - <item name="keyPreviewTextColor">@color/key_text_color_gb</item> - <item name="keyTextShadowColor">@color/key_text_shadow_color_gb</item> - <item name="keyTextShadowRadius">2.75</item> - </style> - <style - name="MainKeyboardView.GB" - parent="KeyboardView.GB" - > - <item name="keyPreviewLayout">@layout/key_preview_gb</item> - <item name="keyPreviewOffset">@dimen/key_preview_offset_gb</item> - <item name="gestureFloatingPreviewTextColor">@color/highlight_color_gb</item> - <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_gb</item> - <item name="gestureTrailColor">@color/highlight_color_gb</item> - <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_gb</item> - <item name="autoCorrectionSpacebarLedEnabled">true</item> - <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_gb</item> - <item name="spacebarTextColor">@color/spacebar_text_color_gb</item> - <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_gb</item> - </style> - <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, - for instance delete button, need themed {@link KeyboardView} attributes. --> - <style - name="EmojiPalettesView.GB" - parent="KeyboardView.GB" - > - <item name="keyBackground">@drawable/btn_keyboard_key_functional_gb</item> - <item name="emojiTabLabelColor">@color/emoji_tab_label_color_gb</item> - </style> - <style - name="MoreKeysKeyboard.GB" - parent="Keyboard.GB" - > - <item name="keyboardTopPadding">0%p</item> - <item name="keyboardBottomPadding">0%p</item> - <item name="horizontalGap">0%p</item> - <item name="touchPositionCorrectionData">@null</item> - </style> - <style - name="MoreKeysKeyboardView.GB" - parent="KeyboardView.GB" - > - <item name="android:background">@null</item> - <item name="keyBackground">@drawable/btn_keyboard_key_popup_gb</item> - <item name="keyTypeface">normal</item> - <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction_gb</item> - </style> - <style - name="MoreKeysKeyboardContainer.GB" - > - <item name="android:background">@drawable/keyboard_popup_panel_background_gb</item> - </style> - <style - name="SuggestionStripView.GB" - parent="SuggestionStripView" - > - <item name="android:background">@drawable/keyboard_suggest_strip_gb</item> - <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item> - <item name="colorValidTypedWord">@color/highlight_color_gb</item> - <item name="colorTypedWord">@color/typed_word_color_gb</item> - <item name="colorAutoCorrect">@color/highlight_color_gb</item> - <item name="colorSuggested">@color/highlight_color_gb</item> - <item name="alphaObsoleted">50%</item> - </style> - <style name="SuggestionWord.GB"> - <item name="android:background">@drawable/btn_suggestion_gb</item> - </style> -</resources> diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 432ad5122..720eda9ce 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -23,10 +23,10 @@ <item name="keyboardStyle">@style/Keyboard.ICS</item> <item name="keyboardViewStyle">@style/KeyboardView.ICS</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item> + <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.ICS</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item> - <item name="moreKeysKeyboardContainerStyle">@style/MoreKeysKeyboardContainer.ICS</item> <item name="suggestionStripViewStyle">@style/SuggestionStripView.ICS</item> <item name="suggestionWordStyle">@style/SuggestionWord.ICS</item> </style> @@ -36,10 +36,10 @@ > <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] --> <item name="themeId">2</item> - <item name="keyboardTopPadding">@fraction/keyboard_top_padding_holo</item> - <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_holo</item> - <item name="horizontalGap">@fraction/key_horizontal_gap_holo</item> - <item name="verticalGap">@fraction/key_bottom_gap_holo</item> + <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item> + <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item> + <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item> + <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item> <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item> </style> <style @@ -63,16 +63,22 @@ name="MainKeyboardView.ICS" parent="KeyboardView.ICS" > - <item name="keyPreviewLayout">@layout/key_preview_ics</item> - <item name="keyPreviewOffset">@dimen/key_preview_offset_holo</item> + <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> <item name="gestureTrailColor">@color/highlight_color_ics</item> <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_ics</item> <item name="autoCorrectionSpacebarLedEnabled">false</item> <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item> - <item name="spacebarTextColor">@color/spacebar_text_color_holo</item> - <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> + <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item> + <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> + <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_ics</item> + </style> + <style + name="KeyPreviewTextView.ICS" + parent="KeyPreviewTextView" + > + <item name="android:background">@drawable/keyboard_key_feedback_ics</item> </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> @@ -96,29 +102,28 @@ name="MoreKeysKeyboardView.ICS" parent="KeyboardView.ICS" > - <item name="android:background">@null</item> + <item name="android:background">@drawable/keyboard_popup_panel_background_ics</item> <item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item> <item name="keyTypeface">normal</item> - <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction_holo</item> - </style> - <style - name="MoreKeysKeyboardContainer.ICS" - > - <item name="android:background">@drawable/keyboard_popup_panel_background_ics</item> + <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item> </style> <style name="SuggestionStripView.ICS" parent="SuggestionStripView" > <item name="android:background">@drawable/keyboard_suggest_strip_holo</item> - <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item> + <item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item> <item name="colorValidTypedWord">@color/typed_word_color_ics</item> <item name="colorTypedWord">@color/typed_word_color_ics</item> <item name="colorAutoCorrect">@color/highlight_color_ics</item> <item name="colorSuggested">@color/suggested_word_color_ics</item> <item name="alphaObsoleted">70%</item> </style> - <style name="SuggestionWord.ICS"> + <style + name="SuggestionWord.ICS" + parent="SuggestionWord" + > <item name="android:background">@drawable/btn_suggestion_ics</item> + <item name="android:textColor">@color/highlight_color_ics</item> </style> </resources> diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml index a3730019d..830527171 100644 --- a/java/res/values/themes-klp.xml +++ b/java/res/values/themes-klp.xml @@ -23,10 +23,10 @@ <item name="keyboardStyle">@style/Keyboard.KLP</item> <item name="keyboardViewStyle">@style/KeyboardView.KLP</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item> + <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.KLP</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item> - <item name="moreKeysKeyboardContainerStyle">@style/MoreKeysKeyboardContainer.KLP</item> <item name="suggestionStripViewStyle">@style/SuggestionStripView.KLP</item> <item name="suggestionWordStyle">@style/SuggestionWord.KLP</item> </style> @@ -36,10 +36,10 @@ > <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] --> <item name="themeId">0</item> - <item name="keyboardTopPadding">@fraction/keyboard_top_padding_holo</item> - <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_holo</item> - <item name="horizontalGap">@fraction/key_horizontal_gap_holo</item> - <item name="verticalGap">@fraction/key_bottom_gap_holo</item> + <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item> + <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item> + <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item> + <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item> <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item> </style> <style @@ -63,16 +63,22 @@ name="MainKeyboardView.KLP" parent="KeyboardView.KLP" > - <item name="keyPreviewLayout">@layout/key_preview_klp</item> - <item name="keyPreviewOffset">@dimen/key_preview_offset_holo</item> + <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> <item name="gestureFloatingPreviewTextColor">@color/highlight_color_klp</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> <item name="gestureTrailColor">@color/highlight_color_klp</item> <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_klp</item> <item name="autoCorrectionSpacebarLedEnabled">false</item> <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item> - <item name="spacebarTextColor">@color/spacebar_text_color_holo</item> - <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> + <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item> + <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> + <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_klp</item> + </style> + <style + name="KeyPreviewTextView.KLP" + parent="KeyPreviewTextView" + > + <item name="android:background">@drawable/keyboard_key_feedback_klp</item> </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> @@ -96,29 +102,28 @@ name="MoreKeysKeyboardView.KLP" parent="KeyboardView.KLP" > - <item name="android:background">@null</item> + <item name="android:background">@drawable/keyboard_popup_panel_background_klp</item> <item name="keyBackground">@drawable/btn_keyboard_key_popup_klp</item> <item name="keyTypeface">normal</item> - <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction_holo</item> - </style> - <style - name="MoreKeysKeyboardContainer.KLP" - > - <item name="android:background">@drawable/keyboard_popup_panel_background_klp</item> + <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item> </style> <style name="SuggestionStripView.KLP" parent="SuggestionStripView" > <item name="android:background">@drawable/keyboard_suggest_strip_holo</item> - <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item> + <item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item> <item name="colorValidTypedWord">@color/typed_word_color_klp</item> <item name="colorTypedWord">@color/typed_word_color_klp</item> <item name="colorAutoCorrect">@color/highlight_color_klp</item> <item name="colorSuggested">@color/suggested_word_color_klp</item> <item name="alphaObsoleted">70%</item> </style> - <style name="SuggestionWord.KLP"> + <style + name="SuggestionWord.KLP" + parent="SuggestionWord" + > <item name="android:background">@drawable/btn_suggestion_klp</item> + <item name="android:textColor">@color/highlight_color_klp</item> </style> </resources> diff --git a/java/res/values/touch-position-correction.xml b/java/res/values/touch-position-correction.xml index becec0e0a..e090d106b 100644 --- a/java/res/values/touch-position-correction.xml +++ b/java/res/values/touch-position-correction.xml @@ -37,26 +37,6 @@ </string-array> <string-array - name="touch_position_correction_data_gb" - translatable="false" - > - <!-- First row --> - <item>0.0091285</item> - <item>0.1193203</item> - <item>0.1622607</item> - - <!-- Second row --> - <item>-0.0233128</item> - <item>0.1379798</item> - <item>0.1585229</item> - - <!-- Third row --> - <item>-0.0080185</item> - <item>0.1911477</item> - <item>0.1570948</item> - </string-array> - - <string-array name="touch_position_correction_data_holo" translatable="false" > diff --git a/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml index 4d8b446a2..c7d446014 100644 --- a/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml +++ b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml @@ -20,7 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="5%p" - latin:rowHeight="@dimen/popup_key_height" + latin:rowHeight="@dimen/config_more_keys_keyboard_key_height" style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml index d90a5884e..fbe8cfcc0 100644 --- a/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml +++ b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml @@ -20,7 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="8%p" - latin:rowHeight="@dimen/popup_key_height" + latin:rowHeight="@dimen/config_more_keys_keyboard_key_height" style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml-sw600dp/key_f1.xml b/java/res/xml-sw600dp/key_f1.xml index ac0053236..ba78a6430 100644 --- a/java/res/xml-sw600dp/key_f1.xml +++ b/java/res/xml-sw600dp/key_f1.xml @@ -23,37 +23,14 @@ > <switch> <case - latin:keyboardLayoutSetElement="symbols" - latin:mode="url" - > - <Key - latin:keyLabel=":" /> - </case> - <case - latin:keyboardLayoutSetElement="symbols" - > - <Key - latin:keyLabel="\@" /> - </case> - <!-- keyboardLayoutSetElement != "symbols" --> - <case latin:mode="email" > <Key - latin:keyLabel="\@" /> - </case> - <case - latin:mode="url" - > - <Key - latin:keyLabel="/" - latin:keyHintLabel=":" - latin:moreKeys=":" - latin:keyStyle="hasShiftedLetterHintStyle" /> + latin:keySpec="\@" /> </case> <default> <Key - latin:keyLabel="/" /> + latin:keySpec="/" /> </default> </switch> </merge> diff --git a/java/res/xml-sw600dp/key_question_exclamation.xml b/java/res/xml-sw600dp/key_question_exclamation.xml index 860a0be77..edee5c5dd 100644 --- a/java/res/xml-sw600dp/key_question_exclamation.xml +++ b/java/res/xml-sw600dp/key_question_exclamation.xml @@ -26,11 +26,11 @@ latin:mode="email|url" > <Key - latin:keyLabel="-" /> + latin:keySpec="-" /> </case> <default> <Key - latin:keyLabel="\?" + latin:keySpec="\?" latin:keyHintLabel="!" latin:moreKeys="!" latin:keyStyle="hasShiftedLetterHintStyle" /> diff --git a/java/res/xml-sw600dp/key_shortcut.xml b/java/res/xml-sw600dp/key_shortcut.xml index 87fc75cd5..d24e81f73 100644 --- a/java/res/xml-sw600dp/key_shortcut.xml +++ b/java/res/xml-sw600dp/key_shortcut.xml @@ -23,29 +23,29 @@ > <switch> <case - latin:shortcutKeyEnabled="true" + latin:supportsSwitchingToShortcutIme="true" latin:clobberSettingsKey="false" > <Key latin:keyStyle="shortcutKeyStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/settings_as_more_key" /> + latin:moreKeys="!text/keyspec_settings" /> </case> <case - latin:shortcutKeyEnabled="true" + latin:supportsSwitchingToShortcutIme="true" latin:clobberSettingsKey="true" > <Key latin:keyStyle="shortcutKeyStyle" /> </case> <case - latin:shortcutKeyEnabled="false" + latin:supportsSwitchingToShortcutIme="false" latin:clobberSettingsKey="false" > <Key latin:keyStyle="settingsKeyStyle" /> </case> - <!-- shortcutKeyEnabled="false" clobberSettingsKey="true" --> + <!-- supportsSwitchingToShortcutIme="false" clobberSettingsKey="true" --> <default> <Spacer /> </default> diff --git a/java/res/xml-sw600dp/key_space_5kw.xml b/java/res/xml-sw600dp/key_space_5kw.xml index 86af89f50..71ae5fd8f 100644 --- a/java/res/xml-sw600dp/key_space_5kw.xml +++ b/java/res/xml-sw600dp/key_space_5kw.xml @@ -23,7 +23,7 @@ > <switch> <case - latin:languageCode="fa" + latin:languageCode="fa|ne" latin:languageSwitchKeyEnabled="true" > <Key @@ -35,7 +35,7 @@ latin:keyStyle="zwnjKeyStyle" /> </case> <case - latin:languageCode="fa" + latin:languageCode="fa|ne" latin:languageSwitchKeyEnabled="false" > <Key diff --git a/java/res/xml-sw600dp/key_space_symbols.xml b/java/res/xml-sw600dp/key_space_symbols.xml index 07aa7d179..b3cb5ac78 100644 --- a/java/res/xml-sw600dp/key_space_symbols.xml +++ b/java/res/xml-sw600dp/key_space_symbols.xml @@ -21,6 +21,7 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <include - latin:keyboardLayout="@xml/key_space_5kw" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="45.0%p" /> </merge> diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml index d817add11..3d5556fe5 100644 --- a/java/res/xml-sw600dp/key_styles_common.xml +++ b/java/res/xml-sw600dp/key_styles_common.xml @@ -39,7 +39,6 @@ <!-- Base style for shift key. A single space is used for dummy label in moreKeys. --> <key-style latin:styleName="baseForShiftKeyStyle" - latin:code="!code/key_shift" latin:keyActionFlags="noKeyPreview" latin:keyLabelFlags="preserveCase" latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" /> @@ -49,7 +48,7 @@ > <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key_shifted" + latin:keySpec="!icon/shift_key_shifted|!code/key_shift" latin:backgroundType="stickyOff" latin:parentStyle="baseForShiftKeyStyle" /> </case> @@ -58,77 +57,56 @@ > <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key_shifted" + latin:keySpec="!icon/shift_key_shifted|!code/key_shift" latin:backgroundType="stickyOn" latin:parentStyle="baseForShiftKeyStyle" /> </case> <default> <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key" + latin:keySpec="!icon/shift_key|!code/key_shift" latin:backgroundType="stickyOff" latin:parentStyle="baseForShiftKeyStyle" /> </default> </switch> <key-style latin:styleName="deleteKeyStyle" - latin:code="!code/key_delete" - latin:keyIcon="!icon/delete_key" + latin:keySpec="!icon/delete_key|!code/key_delete" latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> <include latin:keyboardLayout="@xml/key_styles_enter" /> - <!-- Override defaultEnterKeyStyle in key_styles_enter.xml --> - <key-style - latin:styleName="defaultEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/enter_key" - latin:keyLabelFlags="preserveCase|autoXScale|followKeyLargeLabelRatio" - latin:keyActionFlags="noKeyPreview" - latin:backgroundType="functional" - latin:parentStyle="navigateMoreKeysStyle" /> <key-style latin:styleName="spaceKeyStyle" - latin:code="!code/key_space" + latin:keySpec=" |!code/key_space" latin:keyActionFlags="noKeyPreview|enableLongPress" /> <!-- U+200C: ZERO WIDTH NON-JOINER U+200D: ZERO WIDTH JOINER --> <key-style latin:styleName="zwnjKeyStyle" - latin:code="0x200C" - latin:keyIcon="!icon/zwnj_key" + latin:keySpec="!icon/zwnj_key|‌" latin:moreKeys="!icon/zwj_key|‍" latin:keyLabelFlags="hasPopupHint" latin:keyActionFlags="noKeyPreview" /> <key-style - latin:styleName="smileyKeyStyle" - latin:keyLabel=":-)" - latin:keyOutputText=":-) " - latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/more_keys_for_smiley" /> - <key-style latin:styleName="shortcutKeyStyle" - latin:code="!code/key_shortcut" - latin:keyIcon="!icon/shortcut_key" + latin:keySpec="!icon/shortcut_key|!code/key_shortcut" latin:keyIconDisabled="!icon/shortcut_key_disabled" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="languageSwitchKeyStyle" - latin:code="!code/key_language_switch" - latin:keyIcon="!icon/language_switch_key" + latin:keySpec="!icon/language_switch_key|!code/key_language_switch" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress" latin:altCode="!code/key_space" /> <key-style latin:styleName="emojiKeyStyle" - latin:code="!code/key_emoji" - latin:keyIcon="!icon/emoji_key" + latin:keySpec="!icon/emoji_key|!code/key_emoji" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="settingsKeyStyle" - latin:code="!code/key_settings" - latin:keyIcon="!icon/settings_key" + latin:keySpec="!icon/settings_key|!code/key_settings" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <switch> @@ -138,8 +116,7 @@ > <key-style latin:styleName="tabKeyStyle" - latin:code="!code/key_action_previous" - latin:keyIcon="!icon/tab_key" + latin:keySpec="!icon/tab_key|!code/key_action_previous" latin:keyIconPreview="!icon/tab_key_preview" latin:backgroundType="functional" /> </case> @@ -149,16 +126,14 @@ > <key-style latin:styleName="tabKeyStyle" - latin:code="!code/key_action_next" - latin:keyIcon="!icon/tab_key" + latin:keySpec="!icon/tab_key|!code/key_action_next" latin:keyIconPreview="!icon/tab_key_preview" latin:backgroundType="functional" /> </case> <default> <key-style latin:styleName="tabKeyStyle" - latin:code="!code/key_tab" - latin:keyIcon="!icon/tab_key" + latin:keySpec="!icon/tab_key|!code/key_tab" latin:keyIconPreview="!icon/tab_key_preview" latin:backgroundType="functional" /> </default> @@ -170,28 +145,23 @@ latin:backgroundType="functional" /> <key-style latin:styleName="toSymbolKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:keyLabel="!text/label_to_symbol_key" + latin:keySpec="!text/keylabel_to_symbol|!code/key_switch_alpha_symbol" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="toAlphaKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:keyLabel="!text/label_to_alpha_key" + latin:keySpec="!text/keylabel_to_alpha|!code/key_switch_alpha_symbol" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="toMoreSymbolKeyStyle" - latin:code="!code/key_shift" - latin:keyLabel="!text/label_to_more_symbol_for_tablet_key" + latin:keySpec="!text/keylabel_tablet_to_more_symbol|!code/key_shift" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" - latin:code="!code/key_shift" - latin:keyLabel="!text/label_to_symbol_key" + latin:keySpec="!text/keylabel_to_symbol|!code/key_shift" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="comKeyStyle" - latin:keyLabel="!text/keylabel_for_popular_domain" + latin:keySpec="!text/keyspec_popular_domain" latin:keyLabelFlags="autoXScale|fontNormal|hasPopupHint|preserveCase" - latin:keyOutputText="!text/keylabel_for_popular_domain" - latin:moreKeys="!text/more_keys_for_popular_domain" /> + latin:moreKeys="!text/morekeys_popular_domain" /> </merge> diff --git a/java/res/xml-sw600dp/key_styles_enter.xml b/java/res/xml-sw600dp/key_styles_enter.xml index 1d8ccfae3..0699e4527 100644 --- a/java/res/xml-sw600dp/key_styles_enter.xml +++ b/java/res/xml-sw600dp/key_styles_enter.xml @@ -21,7 +21,7 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <!-- TODO: Stop using many conditional cases for emoji_key_as_more_key. There are way too many to maintain. --> + <!-- TODO: Stop using many conditional cases for keyspec_emoji_key. There are way too many to maintain. --> <!-- Navigate more keys style --> <switch> <!-- latin:passwordInput="true" --> @@ -32,7 +32,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:imeAction="actionNext" @@ -48,7 +48,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:imeAction="actionPrevious" @@ -64,7 +64,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/action_previous_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" /> </case> <case latin:navigateNext="true" @@ -73,7 +73,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:navigateNext="false" @@ -82,7 +82,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:navigateNext="false" @@ -99,22 +99,11 @@ <!-- Enter key style --> <key-style latin:styleName="defaultEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/enter_key" + latin:keySpec="!icon/enter_key|!code/key_enter" latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" latin:parentStyle="navigateMoreKeysStyle" /> - <key-style - latin:styleName="shiftEnterKeyStyle" - latin:code="!code/key_shift_enter" - latin:parentStyle="defaultEnterKeyStyle" /> - <key-style - latin:styleName="defaultActionEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/undefined" - latin:backgroundType="action" - latin:parentStyle="defaultEnterKeyStyle" /> <switch> <!-- Shift + Enter in textMultiLine field. --> <case @@ -123,63 +112,72 @@ > <key-style latin:styleName="enterKeyStyle" - latin:parentStyle="shiftEnterKeyStyle" /> + latin:keySpec="!icon/enter_key|!code/key_shift_enter" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionGo" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_go_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_go_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionNext" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_next_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_next_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionPrevious" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_previous_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_previous_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionDone" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_done_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_done_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionSend" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_send_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_send_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionSearch" > <key-style latin:styleName="enterKeyStyle" - latin:keyIcon="!icon/search_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!icon/search_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionCustomLabel" > <key-style latin:styleName="enterKeyStyle" + latin:keySpec="dummy_label|!code/key_enter" latin:keyLabelFlags="fromCustomActionLabel" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <!-- imeAction is either actionNone or actionUnspecified. --> <default> diff --git a/java/res/xml-sw600dp/keys_arabic3_left.xml b/java/res/xml-sw600dp/keys_arabic3_left.xml index 0f2ccc0ac..9b4031e55 100644 --- a/java/res/xml-sw600dp/keys_arabic3_left.xml +++ b/java/res/xml-sw600dp/keys_arabic3_left.xml @@ -23,10 +23,10 @@ > <!-- U+0630: "ذ" ARABIC LETTER THAL --> <Key - latin:keyLabel="ذ" + latin:keySpec="ذ" latin:keyLabelFlags="fontNormal" /> <!-- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE --> <Key - latin:keyLabel="ئ" + latin:keySpec="ئ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-sw600dp/keys_comma_period.xml b/java/res/xml-sw600dp/keys_comma_period.xml index 7604e033d..23172cf18 100644 --- a/java/res/xml-sw600dp/keys_comma_period.xml +++ b/java/res/xml-sw600dp/keys_comma_period.xml @@ -21,83 +21,33 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <Key + latin:keySpec="!text/keyspec_tablet_comma" + latin:keyHintLabel="!text/keyhintlabel_tablet_comma" + latin:keyLabelFlags="hasPopupHint" + latin:moreKeys="!text/morekeys_tablet_comma" + latin:backgroundType="functional" + latin:keyStyle="hasShiftedLetterHintStyle" /> <switch> <case - latin:mode="email|url" + latin:languageCode="hi" + latin:keyboardLayoutSet="hindi_compact" > + <!-- U+0964: "।" DEVANAGARI DANDA --> <Key - latin:keyLabel="," - latin:keyHintLabel="-" - latin:moreKeys="-" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="_" - latin:moreKeys="_" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - </case> - <case - latin:languageCode="ar" - > - <Key - latin:keyLabel="!text/keylabel_for_apostrophe" - latin:keyHintLabel="!text/keyhintlabel_for_apostrophe" - latin:moreKeys="!text/more_keys_for_apostrophe" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics" - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_arabic_diacritics" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - </case> - <case - latin:languageCode="fa" - > - <Key - latin:keyLabel="!text/keylabel_for_apostrophe" - latin:keyHintLabel="!text/keyhintlabel_for_apostrophe" - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_apostrophe" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics" + latin:keySpec="\u0964" latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_arabic_diacritics" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - </case> - <case - latin:languageCode="hy" - > - <!-- U+055D: "՝" ARMENIAN COMMA --> - <Key - latin:keyLabel="՝" + latin:moreKeys="!autoColumnOrder!8,\\,,.,',#,),(,/,;,@,:,-,",+,\\%,&" latin:backgroundType="functional" /> - <!-- U+0589: "։" ARMENIAN FULL STOP --> - <Key - latin:keyLabel="։" - latin:keyLabelFlags="hasPopupHint" - latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_punctuation" /> </case> <default> <Key - latin:keyLabel="!text/keylabel_for_tablet_comma" - latin:keyHintLabel="!text/keyhintlabel_for_tablet_comma" - latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_tablet_comma" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_period" + latin:keySpec="!text/keyspec_tablet_period" + latin:keyHintLabel="!text/keyhintlabel_tablet_period" + latin:keyLabelFlags="hasPopupHint" + latin:moreKeys="!text/morekeys_tablet_period" latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_period" /> + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> </merge> diff --git a/java/res/xml-sw600dp/keys_dvorak_123.xml b/java/res/xml-sw600dp/keys_dvorak_123.xml index 58416abb4..91ceb1c43 100644 --- a/java/res/xml-sw600dp/keys_dvorak_123.xml +++ b/java/res/xml-sw600dp/keys_dvorak_123.xml @@ -26,31 +26,31 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel=""" + latin:keySpec=""" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <Key - latin:keyLabel="<" + latin:keySpec="<" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <Key - latin:keyLabel=">" + latin:keySpec=">" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> </case> <default> <Key - latin:keyLabel="\'" + latin:keySpec="\'" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys="!,"" /> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="\?,<" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys=">" /> diff --git a/java/res/xml-sw600dp/keys_exclamation_question.xml b/java/res/xml-sw600dp/keys_exclamation_question.xml index cd38282ee..97bd95d6a 100644 --- a/java/res/xml-sw600dp/keys_exclamation_question.xml +++ b/java/res/xml-sw600dp/keys_exclamation_question.xml @@ -22,7 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="!" /> + latin:keySpec="!" + latin:moreKeys="!text/morekeys_exclamation" /> <Key - latin:keyLabel="\?" /> + latin:keySpec="\?" + latin:moreKeys="!text/morekeys_question" /> </merge> diff --git a/java/res/xml-sw600dp/keys_farsi3_right.xml b/java/res/xml-sw600dp/keys_farsi3_right.xml index 3c91ae92d..45d128628 100644 --- a/java/res/xml-sw600dp/keys_farsi3_right.xml +++ b/java/res/xml-sw600dp/keys_farsi3_right.xml @@ -23,10 +23,10 @@ > <!-- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE --> <Key - latin:keyLabel="آ" + latin:keySpec="آ" latin:keyLabelFlags="fontNormal" /> <!-- U+0686: "چ" ARABIC LETTER TCHEH --> <Key - latin:keyLabel="چ" + latin:keySpec="چ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml index 324e025ed..76ac6bbdd 100644 --- a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml +++ b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml @@ -23,20 +23,20 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel="[" + latin:keySpec="[" latin:keyHintLabel="{" latin:additionalMoreKeys="{" latin:keyStyle="hasShiftedLetterHintStyle" /> <Key - latin:keyLabel="]" + latin:keySpec="]" latin:keyHintLabel="}" latin:additionalMoreKeys="}" latin:keyStyle="hasShiftedLetterHintStyle" /> <Key - latin:keyLabel="\\" + latin:keySpec="\\" latin:keyHintLabel="|" latin:additionalMoreKeys="\\|" latin:keyStyle="hasShiftedLetterHintStyle" /> @@ -44,11 +44,11 @@ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> <Key - latin:keyLabel="{" /> + latin:keySpec="{" /> <Key - latin:keyLabel="}" /> + latin:keySpec="}" /> <Key - latin:keyLabel="|" /> + latin:keySpec="|" /> </default> </switch> </merge>
\ No newline at end of file diff --git a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml index 254b5e571..f18fb507c 100644 --- a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml +++ b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml @@ -23,15 +23,15 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel=";" + latin:keySpec=";" latin:keyHintLabel=":" latin:additionalMoreKeys=":" latin:keyStyle="hasShiftedLetterHintStyle" /> <Key - latin:keyLabel="\'" + latin:keySpec="\'" latin:keyHintLabel=""" latin:additionalMoreKeys=""" latin:keyStyle="hasShiftedLetterHintStyle" @@ -40,9 +40,9 @@ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> <Key - latin:keyLabel=":" /> + latin:keySpec=":" /> <Key - latin:keyLabel=""" + latin:keySpec=""" latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" /> </default> </switch> diff --git a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml index 774ff8d05..9ac718cd8 100644 --- a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml +++ b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml @@ -23,24 +23,24 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel="," + latin:keySpec="," latin:keyHintLabel="<" latin:additionalMoreKeys="<" latin:keyStyle="hasShiftedLetterHintStyle" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyHintLabel=">" latin:additionalMoreKeys=">" latin:keyStyle="hasShiftedLetterHintStyle" /> <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyHintLabel="\?" latin:additionalMoreKeys="\?" latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_question" /> + latin:moreKeys="!text/morekeys_question" /> </case> <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> @@ -51,14 +51,14 @@ U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel="<" + latin:keySpec="<" latin:moreKeys="!fixedColumnOrder!3,‹,≤,«" /> <Key - latin:keyLabel=">" + latin:keySpec=">" latin:moreKeys="!fixedColumnOrder!3,›,≥,»" /> <Key - latin:keyLabel="\?" - latin:moreKeys="!text/more_keys_for_symbols_question" /> + latin:keySpec="\?" + latin:moreKeys="!text/morekeys_question" /> </default> </switch> </merge> diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml index 11b403452..2ba6a491b 100644 --- a/java/res/xml-sw600dp/row_dvorak4.xml +++ b/java/res/xml-sw600dp/row_dvorak4.xml @@ -39,7 +39,7 @@ <include latin:keyboardLayout="@xml/key_question_exclamation" /> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:keyHintLabel="_" latin:moreKeys="_" latin:keyStyle="hasShiftedLetterHintStyle" /> diff --git a/java/res/xml-sw600dp/row_pcqwerty5.xml b/java/res/xml-sw600dp/row_pcqwerty5.xml index b854f1051..52b581ae6 100644 --- a/java/res/xml-sw600dp/row_pcqwerty5.xml +++ b/java/res/xml-sw600dp/row_pcqwerty5.xml @@ -24,37 +24,32 @@ <Row latin:keyWidth="7.0%p" > + <include + latin:keyWidth="9.0%p" + latin:keyboardLayout="@xml/key_shortcut" /> <switch> <case latin:languageSwitchKeyEnabled="true" > <Key latin:keyStyle="languageSwitchKeyStyle" - latin:keyWidth="9.0%p" - latin:backgroundType="functional" /> - </case> - </switch> - <Key - latin:keyStyle="spaceKeyStyle" - latin:keyXPos="25.5%p" - latin:keyWidth="49.0%p" /> - <switch> - <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" - > - <include - latin:keyXPos="-9.0%p" - latin:keyWidth="9.0%p" - latin:keyboardLayout="@xml/key_shortcut" /> + latin:keyXPos="22.0%p" + latin:keyWidth="9.0%p" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="40.0%p" /> </case> - <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> - <include - latin:keyXPos="-9.0%p" - latin:keyWidth="9.0%p" - latin:backgroundType="functional" - latin:keyboardLayout="@xml/key_f2" /> + <Key + latin:keyStyle="spaceKeyStyle" + latin:keyXPos="29.0%p" + latin:keyWidth="42.0%p" /> </default> </switch> + <include + latin:keyXPos="-9.0%p" + latin:keyWidth="9.0%p" + latin:backgroundType="functional" + latin:keyboardLayout="@xml/key_f2" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/rowkeys_dvorak3.xml b/java/res/xml-sw600dp/rowkeys_dvorak3.xml index 2148bb2c7..e58d6dbef 100644 --- a/java/res/xml-sw600dp/rowkeys_dvorak3.xml +++ b/java/res/xml-sw600dp/rowkeys_dvorak3.xml @@ -22,26 +22,26 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="q" /> + latin:keySpec="q" /> <Key - latin:keyLabel="j" - latin:moreKeys="!text/more_keys_for_j" /> + latin:keySpec="j" + latin:moreKeys="!text/morekeys_j" /> <Key - latin:keyLabel="k" - latin:moreKeys="!text/more_keys_for_k" /> + latin:keySpec="k" + latin:moreKeys="!text/morekeys_k" /> <Key - latin:keyLabel="x" /> + latin:keySpec="x" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> <Key - latin:keyLabel="w" - latin:moreKeys="!text/more_keys_for_w" /> + latin:keySpec="w" + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> <Key - latin:keyLabel="z" - latin:moreKeys="!text/more_keys_for_z" /> + latin:keySpec="z" + latin:moreKeys="!text/morekeys_z" /> </merge> diff --git a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml index 254d3fdba..e4b824f80 100644 --- a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml +++ b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml @@ -21,87 +21,98 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <Key - latin:keyLabel="`" - latin:keyHintLabel="~" - latin:additionalMoreKeys="~" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="1" - latin:keyHintLabel="!" - latin:additionalMoreKeys="!" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_exclamation,!text/more_keys_for_symbols_1" /> - <Key - latin:keyLabel="2" - latin:keyHintLabel="\@" - latin:additionalMoreKeys="\@" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_2" /> - <Key - latin:keyLabel="3" - latin:keyHintLabel="\#" - latin:additionalMoreKeys="\#" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_3" /> - <Key - latin:keyLabel="4" - latin:keyHintLabel="$" - latin:additionalMoreKeys="$" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_4" /> - <Key - latin:keyLabel="5" - latin:keyHintLabel="%" - latin:additionalMoreKeys="\\%" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_5" /> - <Key - latin:keyLabel="6" - latin:keyHintLabel="^" - latin:additionalMoreKeys="^" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_6" /> - <Key - latin:keyLabel="7" - latin:keyHintLabel="&" - latin:additionalMoreKeys="&" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_7" /> - <Key - latin:keyLabel="8" - latin:keyHintLabel="*" - latin:additionalMoreKeys="*" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_8" /> - <Key - latin:keyLabel="9" - latin:keyHintLabel="(" - latin:additionalMoreKeys="(" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_9" /> - <Key - latin:keyLabel="0" - latin:keyHintLabel=")" - latin:additionalMoreKeys=")" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="!text/more_keys_for_symbols_0" /> - <!-- U+2013: "–" EN DASH - U+2014: "—" EM DASH - U+00B7: "·" MIDDLE DOT --> - <Key - latin:keyLabel="-" - latin:keyHintLabel="_" - latin:additionalMoreKeys="_" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="–,—,·" /> - <!-- U+221E: "∞" INFINITY - U+2260: "≠" NOT EQUAL TO - U+2248: "≈" ALMOST EQUAL TO --> - <Key - latin:keyLabel="=" - latin:keyHintLabel="+" - latin:additionalMoreKeys="+" - latin:keyStyle="hasShiftedLetterHintStyle" - latin:moreKeys="∞,≠,≈" /> + <switch> + <case + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" + > + <Key + latin:keySpec="`" + latin:keyHintLabel="~" + latin:additionalMoreKeys="~" + latin:keyStyle="hasShiftedLetterHintStyle" /> + <Key + latin:keySpec="1" + latin:keyHintLabel="!" + latin:additionalMoreKeys="!" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_exclamation,!text/morekeys_symbols_1" /> + <Key + latin:keySpec="2" + latin:keyHintLabel="\@" + latin:additionalMoreKeys="\@" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_2" /> + <Key + latin:keySpec="3" + latin:keyHintLabel="\#" + latin:additionalMoreKeys="\#" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_3" /> + <Key + latin:keySpec="4" + latin:keyHintLabel="$" + latin:additionalMoreKeys="$" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_4" /> + <Key + latin:keySpec="5" + latin:keyHintLabel="%" + latin:additionalMoreKeys="\\%" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_5" /> + <Key + latin:keySpec="6" + latin:keyHintLabel="^" + latin:additionalMoreKeys="^" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_6" /> + <Key + latin:keySpec="7" + latin:keyHintLabel="&" + latin:additionalMoreKeys="&" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_7" /> + <Key + latin:keySpec="8" + latin:keyHintLabel="*" + latin:additionalMoreKeys="*" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_8" /> + <Key + latin:keySpec="9" + latin:keyHintLabel="(" + latin:additionalMoreKeys="(" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_9" /> + <Key + latin:keySpec="0" + latin:keyHintLabel=")" + latin:additionalMoreKeys=")" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="!text/morekeys_symbols_0" /> + <!-- U+2013: "–" EN DASH + U+2014: "—" EM DASH + U+00B7: "·" MIDDLE DOT --> + <Key + latin:keySpec="-" + latin:keyHintLabel="_" + latin:additionalMoreKeys="_" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="–,—,·" /> + <!-- U+221E: "∞" INFINITY + U+2260: "≠" NOT EQUAL TO + U+2248: "≈" ALMOST EQUAL TO --> + <Key + latin:keySpec="=" + latin:keyHintLabel="+" + latin:additionalMoreKeys="+" + latin:keyStyle="hasShiftedLetterHintStyle" + latin:moreKeys="∞,≠,≈" /> + </case> + <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" --> + <default> + <include + latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" /> + </default> + </switch> </merge> diff --git a/java/res/xml-sw600dp/rows_colemak.xml b/java/res/xml-sw600dp/rows_colemak.xml index ab059da83..7559bfb96 100644 --- a/java/res/xml-sw600dp/rows_colemak.xml +++ b/java/res/xml-sw600dp/rows_colemak.xml @@ -28,8 +28,6 @@ > <include latin:keyboardLayout="@xml/rowkeys_colemak1" /> - <include - latin:keyboardLayout="@xml/key_colemak_colon" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillRight" /> diff --git a/java/res/xml-sw600dp/rows_greek.xml b/java/res/xml-sw600dp/rows_greek.xml index 066dc47fb..60ee478d8 100644 --- a/java/res/xml-sw600dp/rows_greek.xml +++ b/java/res/xml-sw600dp/rows_greek.xml @@ -27,8 +27,6 @@ latin:keyWidth="9.0%p" > <include - latin:keyboardLayout="@xml/key_greek_semicolon" /> - <include latin:keyboardLayout="@xml/rowkeys_greek1" /> <Key latin:keyStyle="deleteKeyStyle" diff --git a/java/res/xml-sw600dp/rows_hebrew.xml b/java/res/xml-sw600dp/rows_hebrew.xml index 852e17683..86b34202f 100644 --- a/java/res/xml-sw600dp/rows_hebrew.xml +++ b/java/res/xml-sw600dp/rows_hebrew.xml @@ -45,8 +45,10 @@ latin:keyWidth="9.0%p" > <include - latin:keyboardLayout="@xml/rowkeys_hebrew3" - latin:keyXPos="10.0%p" /> + latin:keyboardLayout="@xml/rowkeys_hebrew3" /> + <include + latin:keyboardLayout="@xml/keys_exclamation_question" + latin:keyWidth="9.5%p" /> </Row> <include latin:keyboardLayout="@xml/row_qwerty4" /> diff --git a/java/res/xml-sw600dp/rows_hindi_compact.xml b/java/res/xml-sw600dp/rows_hindi_compact.xml new file mode 100644 index 000000000..ac476eb3b --- /dev/null +++ b/java/res/xml-sw600dp/rows_hindi_compact.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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="8.182%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact1" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="8.182%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact2" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="8.182%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact3" /> + <include + latin:keyboardLayout="@xml/keys_exclamation_question" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml-sw600dp/rows_myanmar.xml b/java/res/xml-sw600dp/rows_myanmar.xml new file mode 100644 index 000000000..8eedf9d2f --- /dev/null +++ b/java/res/xml-sw600dp/rows_myanmar.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar1" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="9.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar2" /> + </Row> + <Row + latin:keyWidth="9.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar3" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="9.0%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="10.0%p" /> + <include + latin:keyboardLayout="@xml/rowkeys_myanmar4" /> + <include + latin:keyboardLayout="@xml/keys_exclamation_question" /> + </Row> + <include + 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 index 37bf2e808..757e77933 100644 --- a/java/res/xml-sw600dp/rows_number_normal.xml +++ b/java/res/xml-sw600dp/rows_number_normal.xml @@ -23,29 +23,29 @@ > <Row> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="+" + latin:keySpec="+" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="1" + latin:keySpec="1" latin:keyStyle="numKeyStyle" latin:keyXPos="31%p" /> <Key - latin:keyLabel="2" + latin:keySpec="2" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="3" + latin:keySpec="3" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="deleteKeyStyle" @@ -58,7 +58,7 @@ latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> @@ -67,30 +67,30 @@ latin:mode="time|datetime" > <Key - latin:keyLabel="," + latin:keySpec="," latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_am_pm" + latin:moreKeys="!text/morekeys_am_pm" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> </case> <default> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> </default> </switch> <Key - latin:keyLabel="4" + latin:keySpec="4" latin:keyStyle="numKeyStyle" latin:keyXPos="31%p" /> <Key - latin:keyLabel="5" + latin:keySpec="5" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="6" + latin:keySpec="6" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="enterKeyStyle" @@ -99,12 +99,12 @@ </Row> <Row> <Key - latin:keyLabel="(" + latin:keySpec="(" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel=")" + latin:keySpec=")" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> @@ -113,28 +113,28 @@ latin:mode="time|datetime" > <Key - latin:keyLabel=":" + latin:keySpec=":" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> </case> <default> <Key - latin:keyLabel="=" + latin:keySpec="=" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> </default> </switch> <Key - latin:keyLabel="7" + latin:keySpec="7" latin:keyStyle="numKeyStyle" latin:keyXPos="31%p" /> <Key - latin:keyLabel="8" + latin:keySpec="8" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="9" + latin:keySpec="9" latin:keyStyle="numKeyStyle" /> <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> <Spacer /> @@ -148,10 +148,10 @@ latin:keyStyle="numStarKeyStyle" latin:keyXPos="31%p" /> <Key - latin:keyLabel="0" + latin:keySpec="0" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="\#" + latin:keySpec="\#" latin:keyStyle="numKeyStyle" /> <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> <Spacer diff --git a/java/res/xml-sw600dp/rows_pcqwerty.xml b/java/res/xml-sw600dp/rows_pcqwerty.xml index 8714815ef..73b7e473e 100644 --- a/java/res/xml-sw600dp/rows_pcqwerty.xml +++ b/java/res/xml-sw600dp/rows_pcqwerty.xml @@ -26,19 +26,8 @@ <Row latin:keyWidth="7.0%p" > - <switch> - <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" - > - <include - latin:keyboardLayout="@xml/rowkeys_pcqwerty1" /> - </case> - <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> - <default> - <include - latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/rowkeys_pcqwerty1" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillRight" /> @@ -56,7 +45,7 @@ latin:keyWidth="7.0%p" > <Spacer - latin:keyWidth="12.0%p" /> + latin:keyWidth="10.0%p" /> <include latin:keyboardLayout="@xml/rowkeys_pcqwerty3" /> <Key diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml index c4799bbcd..9022bc532 100644 --- a/java/res/xml-sw600dp/rows_phone.xml +++ b/java/res/xml-sw600dp/rows_phone.xml @@ -27,12 +27,12 @@ latin:keyboardLayout="@xml/key_styles_number" /> <Row> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="+" + latin:keySpec="+" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> @@ -54,12 +54,12 @@ </Row> <Row> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> @@ -81,17 +81,17 @@ </Row> <Row> <Key - latin:keyLabel="(" + latin:keySpec="(" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel=")" + latin:keySpec=")" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> <Key - latin:keyLabel="N" + latin:keySpec="N" latin:keyStyle="numKeyStyle" latin:keyWidth="10%p" latin:backgroundType="functional" /> @@ -116,7 +116,7 @@ <Key latin:keyStyle="num0KeyStyle" /> <Key - latin:keyLabel="\#" + latin:keySpec="\#" latin:keyStyle="numKeyStyle" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/rows_swiss.xml b/java/res/xml-sw600dp/rows_swiss.xml new file mode 100644 index 000000000..4f4ca85b4 --- /dev/null +++ b/java/res/xml-sw600dp/rows_swiss.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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="8.182%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_swiss1" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="8.182%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_swiss2" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="8.182%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="10.0%p" /> + <Spacer + latin:keyWidth="3.181%p" /> + <include + latin:keyboardLayout="@xml/rowkeys_qwertz3" /> + <include + latin:keyboardLayout="@xml/keys_exclamation_question" /> + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyXPos="-10.0%p" + latin:keyWidth="fillRight" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml index cf94b06ed..a915c3351 100644 --- a/java/res/xml-sw600dp/rows_symbols.xml +++ b/java/res/xml-sw600dp/rows_symbols.xml @@ -51,9 +51,9 @@ latin:keyStyle="toMoreSymbolKeyStyle" latin:keyWidth="10.0%p" /> <Key - latin:keyLabel="\\" /> + latin:keySpec="\\" /> <Key - latin:keyLabel="=" /> + latin:keySpec="=" /> <include latin:keyboardLayout="@xml/rowkeys_symbols3" /> <Key @@ -62,6 +62,7 @@ </Row> <Row latin:keyWidth="9.0%p" + latin:backgroundType="functional" > <Key latin:keyStyle="toAlphaKeyStyle" diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml index 92299f65d..7ead4d5b1 100644 --- a/java/res/xml-sw600dp/rows_symbols_shift.xml +++ b/java/res/xml-sw600dp/rows_symbols_shift.xml @@ -54,16 +54,17 @@ latin:keyboardLayout="@xml/rowkeys_symbols_shift3" /> <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK --> <Key - latin:keyLabel="¡" /> + latin:keySpec="¡" /> <!-- U+00BF: "¿" INVERTED QUESTION MARK --> <Key - latin:keyLabel="¿" /> + latin:keySpec="¿" /> <Key latin:keyStyle="backFromMoreSymbolKeyStyle" latin:keyWidth="fillRight" /> </Row> <Row latin:keyWidth="9.0%p" + latin:backgroundType="functional" > <Key latin:keyStyle="toAlphaKeyStyle" diff --git a/java/res/xml-v16/keystyle_devanagari_sign_anusvara.xml b/java/res/xml-v16/keystyle_devanagari_sign_anusvara.xml new file mode 100644 index 000000000..71439d68c --- /dev/null +++ b/java/res/xml-v16/keystyle_devanagari_sign_anusvara.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- The code point U+25CC for key label is needed because the font rendering system prior to + API version 16 can't automatically render dotted circle for incomplete combining letter + of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the + counterpart files named res/xml-v16/key_*.xml don't have this hack. --> +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0903: "ः" DEVANAGARI SIGN VISARGA + U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + U+093C: "़" DEVANAGARI SIGN NUKTA --> + <key-style + latin:styleName="moreKeysDevanagariSignAnusvara" + latin:moreKeys="ः,ँ,़" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariSignAnusvara" /> + </default> + </switch> + <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA --> + <key-style + latin:styleName="baseKeyDevanagariSignAnusvara" + latin:parentStyle="moreKeysDevanagariSignAnusvara" + latin:keySpec="ं" + latin:keyLabelFlags="fontNormal" /> +</merge> diff --git a/java/res/xml-v16/key_devanagari_sign_candrabindu.xml b/java/res/xml-v16/keystyle_devanagari_sign_candrabindu.xml index 03017dd78..6198d01a9 100644 --- a/java/res/xml-v16/key_devanagari_sign_candrabindu.xml +++ b/java/res/xml-v16/keystyle_devanagari_sign_candrabindu.xml @@ -29,8 +29,7 @@ <case latin:keyboardLayoutSet="hindi" > - <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU - U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E --> + <!-- U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E --> <key-style latin:styleName="moreKeysDevanagariSignCandrabindu" latin:moreKeys="ॅ" /> @@ -41,8 +40,9 @@ </default> </switch> <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU --> - <Key - latin:keyStyle="moreKeysDevanagariSignCandrabindu" - latin:keyLabel="ँ" + <key-style + latin:styleName="baseKeyDevanagariSignCandrabindu" + latin:parentStyle="moreKeysDevanagariSignCandrabindu" + latin:keySpec="ँ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/key_devanagari_sign_nukta.xml b/java/res/xml-v16/keystyle_devanagari_sign_nukta.xml index 09c347706..e0b47bb6f 100644 --- a/java/res/xml-v16/key_devanagari_sign_nukta.xml +++ b/java/res/xml-v16/keystyle_devanagari_sign_nukta.xml @@ -36,14 +36,23 @@ latin:styleName="moreKeysDevanagariSignNukta" latin:moreKeys="ॽ,॰,ऽ" /> </case> + <case + latin:keyboardLayoutSet="nepali_romanized" + > + <!-- U+093C: "़" DEVANAGARI SIGN NUKTA --> + <key-style + latin:styleName="moreKeysDevanagariSignNukta" + latin:moreKeys="़" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariSignNukta" /> </default> </switch> <!-- U+093C: "़" DEVANAGARI SIGN NUKTA --> - <Key - latin:keyStyle="moreKeysDevanagariSignNukta" - latin:keyLabel="़" + <key-style + latin:styleName="baseKeyDevanagariSignNukta" + latin:parentStyle="moreKeysDevanagariSignNukta" + latin:keySpec="़" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_sign_virama.xml b/java/res/xml-v16/keystyle_devanagari_sign_virama.xml index a2fbf53d3..0c3a29b16 100644 --- a/java/res/xml-v16/keystyle_devanagari_sign_virama.xml +++ b/java/res/xml-v16/keystyle_devanagari_sign_virama.xml @@ -25,9 +25,24 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA --> + <key-style + latin:styleName="moreKeysDevanagariSignVirama" + latin:moreKeys="्" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariSignVirama" /> + </default> + </switch> <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA --> <key-style latin:styleName="baseKeyDevanagariSignVirama" - latin:keyLabel="्" + latin:parentStyle="moreKeysDevanagariSignVirama" + latin:keySpec="्" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml b/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml index ac56cb77b..b047893a6 100644 --- a/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml +++ b/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml @@ -28,6 +28,6 @@ <!-- U+0903: "ः" DEVANAGARI SIGN VISARGA --> <key-style latin:styleName="baseKeyDevanagariSignVisarga" - latin:keyLabel="ः" + latin:keySpec="ः" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml index 8e256032c..5bb0351ec 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml @@ -35,6 +35,14 @@ latin:styleName="moreKeysDevanagariVowelSignAa" latin:moreKeys="ां,ाँ,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+093E: "ा" DEVANAGARI VOWEL SIGN AA --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAa" + latin:moreKeys="ा,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignAa" /> @@ -44,6 +52,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAa" latin:parentStyle="moreKeysDevanagariVowelSignAa" - latin:keyLabel="ा" + latin:keySpec="ा" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml index e79033971..8edf6eb1c 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml @@ -35,6 +35,14 @@ latin:moreKeys="ैं,%" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0948: "ै" DEVANAGARI VOWEL SIGN AI --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAi" + latin:moreKeys="ै,%" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> @@ -51,6 +59,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAi" latin:parentStyle="moreKeysDevanagariVowelSignAi" - latin:keyLabel="ै" + latin:keySpec="ै" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml index 43387a388..212e058d1 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml @@ -34,6 +34,14 @@ latin:styleName="moreKeysDevanagariVowelSignAu" latin:moreKeys="ौं,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAu" + latin:moreKeys="ौ,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignAu" /> @@ -43,6 +51,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAu" latin:parentStyle="moreKeysDevanagariVowelSignAu" - latin:keyLabel="ौ" + latin:keySpec="ौ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/key_devanagari_sign_anusvara.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_candra_e.xml index 27c7bff5a..ef2c3f14b 100644 --- a/java/res/xml-v16/key_devanagari_sign_anusvara.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_candra_e.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2013, The Android Open Source Project +** Copyright 2014, 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. @@ -25,8 +25,18 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA --> - <Key - latin:keyLabel="ं" - latin:keyLabelFlags="fontNormal" /> + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraE" + latin:moreKeys="ॅ" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraE" /> + </default> + </switch> </merge> diff --git a/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_candra_o.xml index 0316a7bde..ac01d37b7 100644 --- a/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_candra_o.xml @@ -25,8 +25,24 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraO" + latin:moreKeys="ॉ" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraO" /> + </default> + </switch> <!-- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O --> - <Key - latin:keyLabel="ॉ" + <key-style + latin:styleName="baseKeyDevanagariVowelSignCandraO" + latin:parentStyle="moreKeysDevanagariVowelSignCandraO" + latin:keySpec="ॉ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml index c70d9d944..77d6eb5e0 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml @@ -35,6 +35,14 @@ latin:moreKeys="ें" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0947: "े" DEVANAGARI VOWEL SIGN E --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignE" + latin:moreKeys="े" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+0903: "ः" DEVANAGARI SIGN VISARGA @@ -52,6 +60,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignE" latin:parentStyle="moreKeysDevanagariVowelSignE" - latin:keyLabel="े" + latin:keySpec="े" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml index 845c1b02e..d79447be5 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml @@ -34,6 +34,14 @@ latin:styleName="moreKeysDevanagariVowelSignI" latin:moreKeys="िं" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+093F: "ि" DEVANAGARI VOWEL SIGN I --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignI" + latin:moreKeys="ि" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignI" /> @@ -43,6 +51,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignI" latin:parentStyle="moreKeysDevanagariVowelSignI" - latin:keyLabel="ि" + latin:keySpec="ि" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml index 0de9650be..0e10f3172 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml @@ -34,6 +34,14 @@ latin:styleName="moreKeysDevanagariVowelSignIi" latin:moreKeys="ीं,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignIi" + latin:moreKeys="ी,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignIi" /> @@ -43,6 +51,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignIi" latin:parentStyle="moreKeysDevanagariVowelSignIi" - latin:keyLabel="ी" + latin:keySpec="ी" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml index 06f07fac9..47ca906ce 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml @@ -29,13 +29,21 @@ <case latin:keyboardLayoutSet="hindi" > - <!-- U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA + <!-- U+094B/U+0902: "ों" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O --> <key-style latin:styleName="moreKeysDevanagariVowelSignO" latin:moreKeys="ों,ॉ,ॊ" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+094B: "ो" DEVANAGARI VOWEL SIGN O --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignO" + latin:moreKeys="ो" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignO" /> @@ -45,6 +53,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignO" latin:parentStyle="moreKeysDevanagariVowelSignO" - latin:keyLabel="ो" + latin:keySpec="ो" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml index 469a27bdf..694e4abe7 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml @@ -35,6 +35,14 @@ latin:styleName="moreKeysDevanagariVowelSignU" latin:moreKeys="ुं,ुँ" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0941: "ु" DEVANAGARI VOWEL SIGN U --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignU" + latin:moreKeys="ु" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignU" /> @@ -44,6 +52,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignU" latin:parentStyle="moreKeysDevanagariVowelSignU" - latin:keyLabel="ु" + latin:keySpec="ु" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml index 25867c086..f17489e3a 100644 --- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml @@ -35,6 +35,14 @@ latin:styleName="moreKeysDevanagariVowelSignUu" latin:moreKeys="ूं,ूँ,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+0942: "ू" DEVANAGARI VOWEL SIGN UU --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignUu" + latin:moreKeys="ू,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignUu" /> @@ -44,6 +52,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignUu" latin:parentStyle="moreKeysDevanagariVowelSignUu" - latin:keyLabel="ू" + latin:keySpec="ू" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml b/java/res/xml-v16/keystyle_devanagari_vowel_sign_vocalic_r.xml index 4dd3e85cc..27098466d 100644 --- a/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml +++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_vocalic_r.xml @@ -35,6 +35,15 @@ latin:moreKeys="ॄ" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignVocalicR" + latin:moreKeys="ऋ,ृ" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+0913: "ओ" DEVANAGARI LETTER O --> @@ -48,8 +57,9 @@ </default> </switch> <!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R --> - <Key - latin:keyStyle="moreKeysDevanagariVowelSignVocalicR" - latin:keyLabel="ृ" + <key-style + latin:styleName="baseKeyDevanagariVowelSignVocalicR" + latin:parentStyle="moreKeysDevanagariVowelSignVocalicR" + latin:keySpec="ृ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/kbd_armenian_phonetic.xml b/java/res/xml/kbd_armenian_phonetic.xml index 1eb3c7e7d..da12870ed 100644 --- a/java/res/xml/kbd_armenian_phonetic.xml +++ b/java/res/xml/kbd_armenian_phonetic.xml @@ -21,9 +21,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:rowHeight="20%p" - latin:verticalGap="@fraction/key_bottom_gap_5row" - latin:keyLetterSize="@fraction/key_letter_ratio_5row" - latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" > <include diff --git a/java/res/xml/kbd_emoji_category1.xml b/java/res/xml/kbd_emoji_category1.xml index c11a83017..5145ea9d3 100644 --- a/java/res/xml/kbd_emoji_category1.xml +++ b/java/res/xml/kbd_emoji_category1.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_faces" diff --git a/java/res/xml/kbd_emoji_category2.xml b/java/res/xml/kbd_emoji_category2.xml index d3e5890ea..ac8784f4b 100644 --- a/java/res/xml/kbd_emoji_category2.xml +++ b/java/res/xml/kbd_emoji_category2.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_objects" diff --git a/java/res/xml/kbd_emoji_category3.xml b/java/res/xml/kbd_emoji_category3.xml index 0efafa814..88c4db92b 100644 --- a/java/res/xml/kbd_emoji_category3.xml +++ b/java/res/xml/kbd_emoji_category3.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_nature" diff --git a/java/res/xml/kbd_emoji_category4.xml b/java/res/xml/kbd_emoji_category4.xml index e5291207f..262384d80 100644 --- a/java/res/xml/kbd_emoji_category4.xml +++ b/java/res/xml/kbd_emoji_category4.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_places" diff --git a/java/res/xml/kbd_emoji_category5.xml b/java/res/xml/kbd_emoji_category5.xml index 1836879d6..bf823f978 100644 --- a/java/res/xml/kbd_emoji_category5.xml +++ b/java/res/xml/kbd_emoji_category5.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_symbols" diff --git a/java/res/xml/kbd_emoji_category6.xml b/java/res/xml/kbd_emoji_category6.xml index b47ebfec0..edb82fc64 100644 --- a/java/res/xml/kbd_emoji_category6.xml +++ b/java/res/xml/kbd_emoji_category6.xml @@ -20,10 +20,10 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" latin:keyLetterSize="90%p" latin:keyLabelSize="60%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:textsArray="@array/emoji_emoticons" diff --git a/java/res/xml/kbd_emoji_recents.xml b/java/res/xml/kbd_emoji_recents.xml index 73926ecc0..edf3872c1 100644 --- a/java/res/xml/kbd_emoji_recents.xml +++ b/java/res/xml/kbd_emoji_recents.xml @@ -20,10 +20,10 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="@fraction/emoji_keyboard_key_width" - latin:keyLetterSize="@fraction/emoji_keyboard_key_letter_size" + latin:keyWidth="@fraction/config_emoji_keyboard_key_width" + latin:keyLetterSize="@fraction/config_emoji_keyboard_key_letter_size" latin:keyLabelSize="60%p" - latin:rowHeight="@fraction/emoji_keyboard_row_height" + latin:rowHeight="@fraction/config_emoji_keyboard_row_height" > <GridRows latin:codesArray="@array/emoji_recents" diff --git a/java/res/xml-sw600dp/key_colemak_colon.xml b/java/res/xml/kbd_hindi_compact.xml index a5a6e9526..7502bba9e 100644 --- a/java/res/xml-sw600dp/key_colemak_colon.xml +++ b/java/res/xml/kbd_hindi_compact.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2014, 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,12 +18,9 @@ */ --> -<merge +<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <Key - latin:keyLabel=":" - latin:keyHintLabel=";" - latin:moreKeys=";" - latin:keyStyle="hasShiftedLetterHintStyle" /> -</merge> + <include + latin:keyboardLayout="@xml/rows_hindi_compact" /> +</Keyboard> diff --git a/java/res/xml/kbd_khmer.xml b/java/res/xml/kbd_khmer.xml index 7a2337a48..d703e78f7 100644 --- a/java/res/xml/kbd_khmer.xml +++ b/java/res/xml/kbd_khmer.xml @@ -21,9 +21,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:rowHeight="20%p" - latin:verticalGap="@fraction/key_bottom_gap_5row" - latin:keyLetterSize="@fraction/key_letter_ratio_5row" - latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" > <include diff --git a/java/res/xml/kbd_lao.xml b/java/res/xml/kbd_lao.xml index 2bba330de..6f7709562 100644 --- a/java/res/xml/kbd_lao.xml +++ b/java/res/xml/kbd_lao.xml @@ -21,9 +21,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:rowHeight="20%p" - latin:verticalGap="@fraction/key_bottom_gap_5row" - latin:keyLetterSize="@fraction/key_letter_ratio_5row" - latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" > <include diff --git a/java/res/xml/kbd_more_keys_keyboard_template.xml b/java/res/xml/kbd_more_keys_keyboard_template.xml index 537973d03..7104ec7e0 100644 --- a/java/res/xml/kbd_more_keys_keyboard_template.xml +++ b/java/res/xml/kbd_more_keys_keyboard_template.xml @@ -20,7 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="10%p" - latin:rowHeight="@dimen/popup_key_height" + latin:rowHeight="@dimen/config_more_keys_keyboard_key_height" style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml/kbd_myanmar.xml b/java/res/xml/kbd_myanmar.xml new file mode 100644 index 000000000..af997b1c8 --- /dev/null +++ b/java/res/xml/kbd_myanmar.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:rowHeight="20%p" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" + latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" +> + <include + latin:keyboardLayout="@xml/rows_myanmar" /> +</Keyboard> diff --git a/java/res/xml/kbd_pcqwerty.xml b/java/res/xml/kbd_pcqwerty.xml index 5155bc510..045696451 100644 --- a/java/res/xml/kbd_pcqwerty.xml +++ b/java/res/xml/kbd_pcqwerty.xml @@ -21,9 +21,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:rowHeight="20%p" - latin:verticalGap="@fraction/key_bottom_gap_5row" - latin:keyLetterSize="@fraction/key_letter_ratio_5row" - latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" > <include diff --git a/java/res/xml/kbd_suggestions_pane_template.xml b/java/res/xml/kbd_suggestions_pane_template.xml index 21316e6bb..5b4f60673 100644 --- a/java/res/xml/kbd_suggestions_pane_template.xml +++ b/java/res/xml/kbd_suggestions_pane_template.xml @@ -20,6 +20,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="10%p" - latin:rowHeight="@dimen/more_suggestions_row_height" + latin:rowHeight="@dimen/config_more_suggestions_row_height" > </Keyboard> diff --git a/java/res/xml-sw600dp/key_azerty3_right.xml b/java/res/xml/kbd_swiss.xml index a5a6e9526..c64ad1103 100644 --- a/java/res/xml-sw600dp/key_azerty3_right.xml +++ b/java/res/xml/kbd_swiss.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2013, 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,12 +18,9 @@ */ --> -<merge +<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <Key - latin:keyLabel=":" - latin:keyHintLabel=";" - latin:moreKeys=";" - latin:keyStyle="hasShiftedLetterHintStyle" /> -</merge> + <include + latin:keyboardLayout="@xml/rows_swiss" /> +</Keyboard> diff --git a/java/res/xml/kbd_thai.xml b/java/res/xml/kbd_thai.xml index 294bffb5b..7e65217f9 100644 --- a/java/res/xml/kbd_thai.xml +++ b/java/res/xml/kbd_thai.xml @@ -21,9 +21,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:rowHeight="20%p" - latin:verticalGap="@fraction/key_bottom_gap_5row" - latin:keyLetterSize="@fraction/key_letter_ratio_5row" - latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row" + latin:verticalGap="@fraction/config_key_vertical_gap_5row" + latin:keyLetterSize="@fraction/config_key_letter_ratio_5row" + latin:keyShiftedLetterHintRatio="@fraction/config_key_shifted_letter_hint_ratio_5row" latin:touchPositionCorrectionData="@array/touch_position_correction_data_default" > <include diff --git a/java/res/xml/key_armenian_sha.xml b/java/res/xml/key_armenian_sha.xml index 3865c1984..b6418f26f 100644 --- a/java/res/xml/key_armenian_sha.xml +++ b/java/res/xml/key_armenian_sha.xml @@ -23,6 +23,6 @@ > <!-- U+0577: "շ" ARMENIAN SMALL LETTER SHA --> <Key - latin:keyLabel="շ" + latin:keySpec="շ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/key_armenian_xeh.xml b/java/res/xml/key_armenian_xeh.xml index 007a5802d..cfc5bc0f9 100644 --- a/java/res/xml/key_armenian_xeh.xml +++ b/java/res/xml/key_armenian_xeh.xml @@ -23,6 +23,6 @@ > <!-- U+056D: "խ" ARMENIAN SMALL LETTER XEH --> <Key - latin:keyLabel="խ" + latin:keySpec="խ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/key_colemak_colon.xml b/java/res/xml/key_colemak_colon.xml deleted file mode 100644 index 307b4ebca..000000000 --- a/java/res/xml/key_colemak_colon.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?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" -> - <switch> - <case - latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" - > - <Key - latin:keyLabel=";" - latin:keyHintLabel="0" - latin:additionalMoreKeys="0" /> - </case> - <default> - <Key - latin:keyLabel=":" - latin:keyHintLabel="0" - latin:additionalMoreKeys="0" - latin:moreKeys=";" /> - </default> - </switch> -</merge> diff --git a/java/res/xml/key_f1.xml b/java/res/xml/key_f1.xml index 72e38cb1a..c96ddcac1 100644 --- a/java/res/xml/key_f1.xml +++ b/java/res/xml/key_f1.xml @@ -26,17 +26,26 @@ latin:mode="url" > <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyStyle="f1MoreKeysStyle" /> </case> <case latin:mode="email" > <Key - latin:keyLabel="\@" + latin:keySpec="\@" latin:keyStyle="f1MoreKeysStyle" /> </case> <case + latin:supportsSwitchingToShortcutIme="false" + > + <Key + latin:keySpec="!text/keyspec_comma" + latin:keyLabelFlags="hasPopupHint" + latin:keyStyle="f1MoreKeysStyle" /> + </case> + <!-- latin:supportsSwitchingToShortcutIme="true" --> + <case latin:hasShortcutKey="true" > <Key @@ -45,9 +54,9 @@ <!-- latin:hasShortcutKey="false" --> <default> <Key - latin:keyLabel="!text/keylabel_for_comma" + latin:keySpec="!text/keyspec_comma" latin:keyLabelFlags="hasPopupHint" - latin:additionalMoreKeys="!text/more_keys_for_comma,!text/shortcut_as_more_key" + latin:additionalMoreKeys="!text/keyspec_shortcut" latin:keyStyle="f1MoreKeysStyle" /> </default> </switch> diff --git a/java/res/xml/key_greek_semicolon.xml b/java/res/xml/key_greek_semicolon.xml deleted file mode 100644 index ae73a59f6..000000000 --- a/java/res/xml/key_greek_semicolon.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?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" -> - <switch> - <case - latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" - > - <Key - latin:keyLabel=":" - latin:keyHintLabel="1" - latin:moreKeys=";" - latin:additionalMoreKeys="1" /> - </case> - <default> - <Key - latin:keyLabel=";" - latin:keyHintLabel="1" - latin:moreKeys=":" - latin:additionalMoreKeys="1" /> - </default> - </switch> -</merge> diff --git a/java/res/xml/key_nepali_traditional_period.xml b/java/res/xml/key_period.xml index 1c389b009..e1d4bbdf7 100644 --- a/java/res/xml/key_nepali_traditional_period.xml +++ b/java/res/xml/key_period.xml @@ -18,32 +18,42 @@ */ --> -<!-- The code point U+25CC for key label is needed because the font rendering system prior to - API version 16 can't automatically render dotted circle for incomplete combining letter - of Hindi. The files named res/xml/{key,keys}_nepali*.xml have this U+25CC hack, although the - counterpart files named res/xml-v16/{key,keys}_nepali*.xml don't have this hack. --> <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <switch> <case - latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" + latin:languageCode="hi" + latin:keyboardLayoutSet="hindi_compact" > + <!-- U+0964: "।" DEVANAGARI DANDA --> <Key - latin:keyLabel="," + latin:keySpec="\u0964" + latin:keyLabelFlags="hasPopupHint" + latin:moreKeys="!autoColumnOrder!9,\\,,.,?,!,#,),(,/,;,',@,:,-,",+,\\%,&" latin:backgroundType="functional" /> </case> - <default> + <case + latin:languageCode="ne" + latin:keyboardLayoutSet="nepali_traditional" + > <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" /> - <!-- U+002E: "." FULL STOP --> <Key latin:keyStyle="baseKeyDevanagariSignVirama" latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!fixedColumnOrder!9,.,!text/more_keys_for_punctuation" + latin:moreKeys="!text/morekeys_punctuation" + latin:backgroundType="functional" /> + </case> + <default> + <Key + latin:keySpec="!text/keyspec_period" + latin:keyHintLabel="!text/keyhintlabel_period" + latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint" + latin:moreKeys="!text/morekeys_period" latin:backgroundType="functional" /> </default> </switch> diff --git a/java/res/xml/key_space_3kw.xml b/java/res/xml/key_space_3kw.xml deleted file mode 100644 index 20ec882df..000000000 --- a/java/res/xml/key_space_3kw.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, 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:languageSwitchKeyEnabled="true" - > - <Key - latin:keyStyle="languageSwitchKeyStyle" /> - <Key - latin:keyStyle="spaceKeyStyle" - latin:keyWidth="20%p" /> - </case> - <!-- languageSwitchKeyEnabled="false" --> - <default> - <Key - latin:keyStyle="spaceKeyStyle" - latin:keyWidth="30%p" /> - </default> - </switch> -</merge> diff --git a/java/res/xml/key_space_symbols.xml b/java/res/xml/key_space_symbols.xml index 1efc4ff4e..0ce522889 100644 --- a/java/res/xml/key_space_symbols.xml +++ b/java/res/xml/key_space_symbols.xml @@ -21,6 +21,8 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <include - latin:keyboardLayout="@xml/key_space_3kw" /> + <Key + latin:backgroundType="normal" + latin:keyStyle="spaceKeyStyle" + latin:keyWidth="30%p" /> </merge> diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml index c9d87bfd4..78e030132 100644 --- a/java/res/xml/key_styles_common.xml +++ b/java/res/xml/key_styles_common.xml @@ -42,7 +42,6 @@ <!-- Base style for shift key. A single space is used for dummy label in moreKeys. --> <key-style latin:styleName="baseForShiftKeyStyle" - latin:code="!code/key_shift" latin:keyActionFlags="noKeyPreview" latin:keyLabelFlags="preserveCase" latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" /> @@ -52,7 +51,7 @@ > <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key_shifted" + latin:keySpec="!icon/shift_key_shifted|!code/key_shift" latin:backgroundType="stickyOff" latin:parentStyle="baseForShiftKeyStyle" /> </case> @@ -61,155 +60,97 @@ > <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key_shifted" + latin:keySpec="!icon/shift_key_shifted|!code/key_shift" latin:backgroundType="stickyOn" latin:parentStyle="baseForShiftKeyStyle" /> </case> <default> <key-style latin:styleName="shiftKeyStyle" - latin:keyIcon="!icon/shift_key" + latin:keySpec="!icon/shift_key|!code/key_shift" latin:backgroundType="stickyOff" latin:parentStyle="baseForShiftKeyStyle" /> </default> </switch> <key-style latin:styleName="deleteKeyStyle" - latin:code="!code/key_delete" - latin:keyIcon="!icon/delete_key" + latin:keySpec="!icon/delete_key|!code/key_delete" latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> + <!-- emojiKeyStyle must be defined before including @xml/key_syles_enter. --> + <key-style + latin:styleName="emojiKeyStyle" + latin:keySpec="!icon/emoji_key|!code/key_emoji" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="functional" /> <include latin:keyboardLayout="@xml/key_styles_enter" /> <key-style latin:styleName="spaceKeyStyle" - latin:code="!code/key_space" + latin:keySpec=" |!code/key_space" latin:keyActionFlags="noKeyPreview|enableLongPress" /> <!-- U+200C: ZERO WIDTH NON-JOINER U+200D: ZERO WIDTH JOINER --> <key-style latin:styleName="zwnjKeyStyle" - latin:code="0x200C" - latin:keyIcon="!icon/zwnj_key" + latin:keySpec="!icon/zwnj_key|‌" latin:moreKeys="!icon/zwj_key|‍" latin:keyLabelFlags="hasPopupHint" latin:keyActionFlags="noKeyPreview" /> <key-style latin:styleName="shortcutKeyStyle" - latin:code="!code/key_shortcut" - latin:keyIcon="!icon/shortcut_key" + latin:keySpec="!icon/shortcut_key|!code/key_shortcut" latin:keyIconDisabled="!icon/shortcut_key_disabled" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:altCode="!code/key_space" latin:parentStyle="f1MoreKeysStyle" /> <key-style latin:styleName="settingsKeyStyle" - latin:code="!code/key_settings" - latin:keyIcon="!icon/settings_key" + latin:keySpec="!icon/settings_key|!code/key_settings" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:altCode="!code/key_space" latin:backgroundType="functional" /> <key-style latin:styleName="languageSwitchKeyStyle" - latin:code="!code/key_language_switch" - latin:keyIcon="!icon/language_switch_key" + latin:keySpec="!icon/language_switch_key|!code/key_language_switch" latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress" latin:altCode="!code/key_space" /> <key-style - latin:styleName="emojiKeyStyle" - latin:code="!code/key_emoji" - latin:keyIcon="!icon/emoji_key" - latin:keyActionFlags="noKeyPreview" - latin:backgroundType="functional" /> - <!-- Overriding EnterKeyStyle here --> - <switch> - <!-- Shift + Enter in textMultiLine field. --> - <case - latin:isMultiLine="true" - latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" - > - <key-style - latin:styleName="enterKeyStyle" - latin:parentStyle="shiftEnterKeyStyle" /> - </case> - <!-- Smiley in textShortMessage field. - Overrides common enter key style. --> - <case - latin:mode="im" - > - <key-style - latin:styleName="enterKeyStyle" - latin:parentStyle="emojiKeyStyle" /> - </case> - </switch> - <key-style latin:styleName="tabKeyStyle" - latin:code="!code/key_tab" - latin:keyIcon="!icon/tab_key" + latin:keySpec="!icon/tab_key|!code/key_tab" latin:keyIconPreview="!icon/tab_key_preview" latin:backgroundType="functional" /> <!-- Note: This key style is not for functional tab key. This is used for the tab key which is laid out as normal letter key. --> <key-style latin:styleName="nonSpecialBackgroundTabKeyStyle" - latin:code="!code/key_tab" - latin:keyIcon="!icon/tab_key" + latin:keySpec="!icon/tab_key|!code/key_tab" latin:keyIconPreview="!icon/tab_key_preview" /> <key-style latin:styleName="baseForLayoutSwitchKeyStyle" latin:keyLabelFlags="preserveCase" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> - <switch> - <!-- When this qwerty keyboard has no shortcut keys but shortcut key is enabled, then symbol - keyboard will have a shortcut key. That means we should use label_to_symbol_key label - and shortcut_for_label icon. --> - <case - latin:shortcutKeyOnSymbols="true" - > - <key-style - latin:styleName="baseForToSymbolKeyStyle" - latin:keyIcon="!icon/shortcut_for_label" - latin:keyLabel="!text/label_to_symbol_with_microphone_key" - latin:keyLabelFlags="withIconRight|preserveCase" - latin:parentStyle="baseForLayoutSwitchKeyStyle" /> - </case> - <default> - <key-style - latin:styleName="baseForToSymbolKeyStyle" - latin:keyLabel="!text/label_to_symbol_key" - latin:parentStyle="baseForLayoutSwitchKeyStyle" /> - </default> - </switch> <key-style latin:styleName="toSymbolKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:parentStyle="baseForToSymbolKeyStyle" /> + latin:keySpec="!text/keylabel_to_symbol|!code/key_switch_alpha_symbol" + latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="toAlphaKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:keyLabel="!text/label_to_alpha_key" + latin:keySpec="!text/keylabel_to_alpha|!code/key_switch_alpha_symbol" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="toMoreSymbolKeyStyle" - latin:code="!code/key_shift" - latin:keyLabel="!text/label_to_more_symbol_key" + latin:keySpec="!text/keylabel_to_more_symbol|!code/key_shift" latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" - latin:code="!code/key_shift" - latin:parentStyle="baseForToSymbolKeyStyle" /> - <key-style - latin:styleName="punctuationKeyStyle" - latin:keyLabel="." - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_punctuation" - latin:backgroundType="functional" /> + latin:keySpec="!text/keylabel_to_symbol|!code/key_shift" + latin:parentStyle="baseForLayoutSwitchKeyStyle" /> <key-style latin:styleName="comKeyStyle" - latin:keyLabel="!text/keylabel_for_popular_domain" + latin:keySpec="!text/keyspec_popular_domain" latin:keyLabelFlags="autoXScale|fontNormal|hasPopupHint|preserveCase" - latin:keyOutputText="!text/keylabel_for_popular_domain" - latin:moreKeys="!text/more_keys_for_popular_domain" + latin:moreKeys="!text/morekeys_popular_domain" latin:backgroundType="functional" /> </merge> diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml index 84c2abc08..0bb2bb408 100644 --- a/java/res/xml/key_styles_currency.xml +++ b/java/res/xml/key_styles_currency.xml @@ -50,7 +50,7 @@ 19. San Marino (it_SM) 20. Slovakia (sk_SK) 21. Slovenia (sl_SI) - 22. Spain (es_ES, ca_ES) + 22. Spain (es_ES, ca_ES, eu_ES, gl_ES) 23. Vatican City (it_VA) --> <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" @@ -113,21 +113,47 @@ U+00A2: "¢" CENT SIGN --> <key-style latin:styleName="currencyKeyStyle" - latin:keyLabel="!text/keylabel_for_currency" - latin:moreKeys="!text/more_keys_for_currency" /> + latin:keySpec="!text/keyspec_currency" + latin:moreKeys="!text/morekeys_currency" /> <key-style latin:styleName="moreCurrency1KeyStyle" - latin:keyLabel="£" /> + latin:keySpec="£" /> <key-style latin:styleName="moreCurrency2KeyStyle" - latin:keyLabel="€" /> + latin:keySpec="€" /> <key-style latin:styleName="moreCurrency3KeyStyle" - latin:keyLabel="$" + latin:keySpec="$" latin:moreKeys="¢" /> <key-style latin:styleName="moreCurrency4KeyStyle" - latin:keyLabel="¢" /> + latin:keySpec="¢" /> + </case> + <!-- IN: India (Rupee) --> + <case + latin:countryCode="IN" + > + <!-- U+20B9: "₹" INDIAN RUPEE SIGN + U+00A3: "£" POUND SIGN + U+20AC: "€" EURO SIGN + U+00A2: "¢" CENT SIGN --> + <key-style + latin:styleName="currencyKeyStyle" + latin:keySpec="₹" + latin:moreKeys="!text/morekeys_currency" /> + <key-style + latin:styleName="moreCurrency1KeyStyle" + latin:keySpec="£" /> + <key-style + latin:styleName="moreCurrency2KeyStyle" + latin:keySpec="€" /> + <key-style + latin:styleName="moreCurrency3KeyStyle" + latin:keySpec="$" + latin:moreKeys="¢" /> + <key-style + latin:styleName="moreCurrency4KeyStyle" + latin:keySpec="¢" /> </case> <!-- GB: United Kingdom (Pound) --> <case @@ -140,21 +166,21 @@ U+20B1: "₱" PESO SIGN --> <key-style latin:styleName="currencyKeyStyle" - latin:keyLabel="£" + latin:keySpec="£" latin:moreKeys="¢,$,€,¥,₱" /> <key-style latin:styleName="moreCurrency1KeyStyle" - latin:keyLabel="€" /> + latin:keySpec="€" /> <key-style latin:styleName="moreCurrency2KeyStyle" - latin:keyLabel="¥" /> + latin:keySpec="¥" /> <key-style latin:styleName="moreCurrency3KeyStyle" - latin:keyLabel="$" + latin:keySpec="$" latin:moreKeys="¢" /> <key-style latin:styleName="moreCurrency4KeyStyle" - latin:keyLabel="¢" /> + latin:keySpec="¢" /> </case> <!-- ar: Arabic (Dollar and Rial) --> <default> diff --git a/java/res/xml/key_styles_currency_dollar.xml b/java/res/xml/key_styles_currency_dollar.xml index 674a3966d..d3211bd69 100644 --- a/java/res/xml/key_styles_currency_dollar.xml +++ b/java/res/xml/key_styles_currency_dollar.xml @@ -25,18 +25,18 @@ U+00A5: "¥" YEN SIGN --> <key-style latin:styleName="currencyKeyStyle" - latin:keyLabel="$" - latin:moreKeys="!text/more_keys_for_currency_dollar" /> + latin:keySpec="$" + latin:moreKeys="!text/morekeys_currency_dollar" /> <key-style latin:styleName="moreCurrency1KeyStyle" - latin:keyLabel="£" /> + latin:keySpec="£" /> <key-style latin:styleName="moreCurrency2KeyStyle" - latin:keyLabel="¢" /> + latin:keySpec="¢" /> <key-style latin:styleName="moreCurrency3KeyStyle" - latin:keyLabel="€" /> + latin:keySpec="€" /> <key-style latin:styleName="moreCurrency4KeyStyle" - latin:keyLabel="¥" /> + latin:keySpec="¥" /> </merge> diff --git a/java/res/xml/key_styles_currency_euro.xml b/java/res/xml/key_styles_currency_euro.xml index c1b5e0384..c2ae87bea 100644 --- a/java/res/xml/key_styles_currency_euro.xml +++ b/java/res/xml/key_styles_currency_euro.xml @@ -26,19 +26,19 @@ U+20B1: "₱" PESO SIGN --> <key-style latin:styleName="currencyKeyStyle" - latin:keyLabel="€" + latin:keySpec="€" latin:moreKeys="¢,£,$,¥,₱" /> <key-style latin:styleName="moreCurrency1KeyStyle" - latin:keyLabel="£" /> + latin:keySpec="£" /> <key-style latin:styleName="moreCurrency2KeyStyle" - latin:keyLabel="¥" /> + latin:keySpec="¥" /> <key-style latin:styleName="moreCurrency3KeyStyle" - latin:keyLabel="$" + latin:keySpec="$" latin:moreKeys="¢" /> <key-style latin:styleName="moreCurrency4KeyStyle" - latin:keyLabel="¢" /> + latin:keySpec="¢" /> </merge> diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml index 083e6a67d..acb27abb1 100644 --- a/java/res/xml/key_styles_enter.xml +++ b/java/res/xml/key_styles_enter.xml @@ -21,7 +21,7 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <!-- TODO: Stop using many conditional cases for emoji_key_as_more_key. There are way too many to maintain. --> + <!-- TODO: Stop using many conditional cases for keyspec_emoji_key. There are way too many to maintain. --> <!-- Navigate more keys style --> <switch> <!-- latin:passwordInput="true" --> @@ -33,7 +33,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:imeAction="actionNext" @@ -51,7 +51,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:imeAction="actionPrevious" @@ -69,7 +69,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/action_previous_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" /> </case> <case latin:navigateNext="true" @@ -79,7 +79,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:navigateNext="false" @@ -89,7 +89,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:navigateNext="false" @@ -108,7 +108,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:imeAction="actionNext" @@ -126,7 +126,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:imeAction="actionPrevious" @@ -144,7 +144,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/action_previous_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" /> </case> <case latin:navigateNext="true" @@ -154,7 +154,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_next_as_more_key" /> + latin:moreKeys="!text/keyspec_action_next" /> </case> <case latin:navigateNext="false" @@ -164,7 +164,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/action_previous_as_more_key" /> + latin:moreKeys="!text/keyspec_action_previous" /> </case> <case latin:navigateNext="false" @@ -182,7 +182,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/emoji_key_as_more_key,!text/action_previous_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous" /> </case> <case latin:imeAction="actionNext" @@ -191,7 +191,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/emoji_key_as_more_key" /> + latin:moreKeys="!text/keyspec_emoji_key" /> </case> <case latin:imeAction="actionPrevious" @@ -200,7 +200,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/emoji_key_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_next" /> </case> <case latin:imeAction="actionPrevious" @@ -209,7 +209,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/emoji_key_as_more_key" /> + latin:moreKeys="!text/keyspec_emoji_key" /> </case> <case latin:navigateNext="true" @@ -218,7 +218,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/emoji_key_as_more_key,!text/action_previous_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous,!text/keyspec_action_next" /> </case> <case latin:navigateNext="true" @@ -227,7 +227,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/emoji_key_as_more_key,!text/action_next_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_next" /> </case> <case latin:navigateNext="false" @@ -236,7 +236,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/emoji_key_as_more_key,!text/action_previous_as_more_key" /> + latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous" /> </case> <case latin:navigateNext="false" @@ -245,7 +245,7 @@ <key-style latin:styleName="navigateMoreKeysStyle" latin:keyLabelFlags="hasPopupHint|preserveCase" - latin:moreKeys="!text/emoji_key_as_more_key" /> + latin:moreKeys="!text/keyspec_emoji_key" /> </case> <default> <key-style @@ -255,21 +255,13 @@ <!-- Enter key style --> <key-style latin:styleName="defaultEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/enter_key" latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" latin:parentStyle="navigateMoreKeysStyle" /> <key-style latin:styleName="shiftEnterKeyStyle" - latin:code="!code/key_shift_enter" - latin:parentStyle="defaultEnterKeyStyle" /> - <key-style - latin:styleName="defaultActionEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/undefined" - latin:backgroundType="action" + latin:keySpec="!icon/enter_key|!code/key_shift_enter" latin:parentStyle="defaultEnterKeyStyle" /> <switch> <!-- Shift + Enter in textMultiLine field. --> @@ -281,66 +273,84 @@ latin:styleName="enterKeyStyle" latin:parentStyle="shiftEnterKeyStyle" /> </case> + <!-- Smiley in textShortMessage field. + This <case> should be after Shift + Enter <case> and before any of action <case>. --> + <case + latin:mode="im" + > + <key-style + latin:styleName="enterKeyStyle" + latin:parentStyle="emojiKeyStyle" /> + </case> <case latin:imeAction="actionGo" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_go_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_go_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionNext" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_next_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_next_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionPrevious" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_previous_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_previous_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionDone" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_done_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_done_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionSend" > <key-style latin:styleName="enterKeyStyle" - latin:keyLabel="!text/label_send_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!text/label_send_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionSearch" > <key-style latin:styleName="enterKeyStyle" - latin:keyIcon="!icon/search_key" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:keySpec="!icon/search_key|!code/key_enter" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <case latin:imeAction="actionCustomLabel" > <key-style latin:styleName="enterKeyStyle" + latin:keySpec="dummy_label|!code/key_enter" latin:keyLabelFlags="fromCustomActionLabel" - latin:parentStyle="defaultActionEnterKeyStyle" /> + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> </case> <!-- imeAction is either actionNone or actionUnspecified. --> <default> <key-style latin:styleName="enterKeyStyle" + latin:keySpec="!icon/enter_key|!code/key_enter" latin:parentStyle="defaultEnterKeyStyle" /> </default> </switch> diff --git a/java/res/xml/key_styles_f1.xml b/java/res/xml/key_styles_f1.xml index 8dfc3cb84..8a07827fa 100644 --- a/java/res/xml/key_styles_f1.xml +++ b/java/res/xml/key_styles_f1.xml @@ -36,7 +36,7 @@ <key-style latin:styleName="f1MoreKeysStyle" latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/settings_as_more_key" + latin:moreKeys="!text/keyspec_settings" latin:backgroundType="functional" /> </default> </switch> diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml index 2e5a601b0..5c108cf58 100644 --- a/java/res/xml/key_styles_number.xml +++ b/java/res/xml/key_styles_number.xml @@ -43,82 +43,74 @@ latin:parentStyle="numKeyStyle" /> <key-style latin:styleName="num0KeyStyle" - latin:keyLabel="0" + latin:keySpec="0" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num1KeyStyle" - latin:keyLabel="1" + latin:keySpec="1" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num2KeyStyle" - latin:keyLabel="2" + latin:keySpec="2" latin:keyHintLabel="ABC" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num3KeyStyle" - latin:keyLabel="3" + latin:keySpec="3" latin:keyHintLabel="DEF" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num4KeyStyle" - latin:keyLabel="4" + latin:keySpec="4" latin:keyHintLabel="GHI" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num5KeyStyle" - latin:keyLabel="5" + latin:keySpec="5" latin:keyHintLabel="JKL" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num6KeyStyle" - latin:keyLabel="6" + latin:keySpec="6" latin:keyHintLabel="MNO" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num7KeyStyle" - latin:keyLabel="7" + latin:keySpec="7" latin:keyHintLabel="PQRS" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num8KeyStyle" - latin:keyLabel="8" + latin:keySpec="8" latin:keyHintLabel="TUV" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num9KeyStyle" - latin:keyLabel="9" + latin:keySpec="9" latin:keyHintLabel="WXYZ" latin:parentStyle="numberKeyStyle" /> - <!-- U+002A: "*" ASTERISK - U+FF0A: "*" FULLWIDTH ASTERISK --> + <!-- U+FF0A: "*" FULLWIDTH ASTERISK --> <key-style latin:styleName="numStarKeyStyle" - latin:code="0x002A" - latin:keyLabel="*" + latin:keySpec="*|*" latin:parentStyle="numKeyStyle" /> <!-- Only for non-tablet device --> <key-style latin:styleName="numPhoneToSymbolKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:keyLabel="!text/label_to_phone_symbols_key" + latin:keySpec="!text/keylabel_to_phone_symbols|!code/key_switch_alpha_symbol" latin:parentStyle="numModeKeyStyle" /> <key-style latin:styleName="numPhoneToNumericKeyStyle" - latin:code="!code/key_switch_alpha_symbol" - latin:keyLabel="!text/label_to_phone_numeric_key" + latin:keySpec="!text/keylabel_to_phone_numeric|!code/key_switch_alpha_symbol" latin:parentStyle="numModeKeyStyle" /> - <!-- U+002C: "," COMMA --> <key-style latin:styleName="numPauseKeyStyle" - latin:code="0x002C" - latin:keyLabel="!text/label_pause_key" + latin:keySpec="!text/label_pause_key|," latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale" latin:parentStyle="numKeyBaseStyle" /> - <!-- U+003B: ";" SEMICOLON --> <key-style latin:styleName="numWaitKeyStyle" - latin:code="0x003B" - latin:keyLabel="!text/label_wait_key" + latin:keySpec="!text/label_wait_key|;" latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale" latin:parentStyle="numKeyBaseStyle" /> <key-style @@ -127,15 +119,13 @@ latin:parentStyle="tabKeyStyle" /> <key-style latin:styleName="numSpaceKeyStyle" - latin:code="!code/key_space" - latin:keyIcon="!icon/space_key_for_number_layout" + latin:keySpec="!icon/space_key_for_number_layout|!code/key_space" latin:keyActionFlags="enableLongPress" latin:parentStyle="numKeyBaseStyle" /> <!-- Override defaultEnterKeyStyle in key_styles_enter.xml --> <key-style latin:styleName="defaultEnterKeyStyle" - latin:code="!code/key_enter" - latin:keyIcon="!icon/enter_key" + latin:keySpec="!icon/enter_key|!code/key_enter" latin:keyLabelFlags="preserveCase|autoXScale|followKeyLargeLabelRatio" latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" diff --git a/java/res/xml/key_symbols_period.xml b/java/res/xml/key_symbols_period.xml deleted file mode 100644 index 6efc9dee3..000000000 --- a/java/res/xml/key_symbols_period.xml +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, 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" -> - <!-- U+2105: "℅" CARE OF - U+2122: "™" TRADE MARK SIGN - U+00AE: "®" REGISTERED SIGN - U+00A9: "©" COPYRIGHT SIGN - U+00A7: "§" SECTION SIGN - U+00B6: "¶" PILCROW SIGN - U+002C: "," COMMA - U+2022: "•" BULLET --> - <!-- U+00B0: "°" DEGREE SIGN - U+2032: "′" PRIME - U+2033: "″" DOUBLE PRIME - U+2191: "↑" UPWARDS ARROW - U+2193: "↓" DOWNWARDS ARROW - U+2190: "←" LEFTWARDS ARROW - U+2192: "→" RIGHTWARDS ARROW - U+2026: "…" HORIZONTAL ELLIPSIS --> - <!-- U+0394: "Δ" GREEK CAPITAL LETTER DELTA - U+03A0: "Π" GREEK CAPITAL LETTER PI - U+03C0: "π" GREEK SMALL LETTER PI --> - <Key - latin:keyLabel="." - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!fixedColumnOrder!8,℅,™,®,©,§,¶,\\,,•,°,′,″,↑,↓,←,→,…,!text/more_keys_for_bullet,Δ,Π,π" /> -</merge> diff --git a/java/res/xml/key_thai_kho_khuat.xml b/java/res/xml/key_thai_kho_khuat.xml index 0ffd0f924..84988f870 100644 --- a/java/res/xml/key_thai_kho_khuat.xml +++ b/java/res/xml/key_thai_kho_khuat.xml @@ -27,13 +27,13 @@ > <!-- U+0E05: "ฅ" THAI CHARACTER KHO KHON --> <Key - latin:keyLabel="ฅ" + latin:keySpec="ฅ" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+0E03: "ฃ" THAI CHARACTER KHO KHUAT --> <Key - latin:keyLabel="ฃ" + latin:keySpec="ฃ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/keyboard_layout_set_hindi_compact.xml b/java/res/xml/keyboard_layout_set_hindi_compact.xml new file mode 100644 index 000000000..77d02fbbc --- /dev/null +++ b/java/res/xml/keyboard_layout_set_hindi_compact.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<KeyboardLayoutSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_hindi_compact" + latin:enableProximityCharsCorrection="true" /> + <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" /> +</KeyboardLayoutSet> diff --git a/java/res/xml/keyboard_layout_set_myanmar.xml b/java/res/xml/keyboard_layout_set_myanmar.xml new file mode 100644 index 000000000..5c823b263 --- /dev/null +++ b/java/res/xml/keyboard_layout_set_myanmar.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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. +*/ +--> + +<KeyboardLayoutSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_myanmar" + latin:enableProximityCharsCorrection="true" /> + <Element + latin:elementName="alphabetAutomaticShifted" + latin:elementKeyboard="@xml/kbd_myanmar" + latin:enableProximityCharsCorrection="true" /> + <!-- On these shifted alphabet layouts the proximity characters correction should be disabled + because the letters on these layouts aren't the ones in different case of the above + unshifted layouts. --> + <Element + latin:elementName="alphabetManualShifted" + latin:elementKeyboard="@xml/kbd_myanmar" /> + <Element + latin:elementName="alphabetShiftLocked" + latin:elementKeyboard="@xml/kbd_myanmar" /> + <Element + latin:elementName="alphabetShiftLockShifted" + latin:elementKeyboard="@xml/kbd_myanmar" /> + <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" /> +</KeyboardLayoutSet> diff --git a/java/res/xml/keyboard_layout_set_swiss.xml b/java/res/xml/keyboard_layout_set_swiss.xml new file mode 100644 index 000000000..e17a5ab8b --- /dev/null +++ b/java/res/xml/keyboard_layout_set_swiss.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<KeyboardLayoutSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_swiss" + latin:enableProximityCharsCorrection="true" /> + <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" /> +</KeyboardLayoutSet> diff --git a/java/res/xml/keys_arabic3_left.xml b/java/res/xml/keys_arabic3_left.xml index 157af4a52..2b3e12c03 100644 --- a/java/res/xml/keys_arabic3_left.xml +++ b/java/res/xml/keys_arabic3_left.xml @@ -23,6 +23,6 @@ > <!-- U+0630: "ذ" ARABIC LETTER THAL --> <Key - latin:keyLabel="ذ" + latin:keySpec="ذ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/keys_comma_period.xml b/java/res/xml/keys_comma_period.xml deleted file mode 100644 index 1b51e45ed..000000000 --- a/java/res/xml/keys_comma_period.xml +++ /dev/null @@ -1,87 +0,0 @@ -<?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" -> - <switch> - <case - latin:languageCode="ar" - > - <Key - latin:keyLabel="!text/keylabel_for_apostrophe" - latin:keyHintLabel="!text/keyhintlabel_for_apostrophe" - latin:moreKeys="!text/more_keys_for_apostrophe" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics" - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_arabic_diacritics" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - </case> - <case - latin:languageCode="fa" - > - <Key - latin:keyLabel="!text/keylabel_for_apostrophe" - latin:keyHintLabel="!text/keyhintlabel_for_apostrophe" - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_apostrophe" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics" - latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_arabic_diacritics" - latin:backgroundType="functional" - latin:keyStyle="hasShiftedLetterHintStyle" /> - </case> - <case - latin:languageCode="hy" - > - <!-- U+055D: "՝" ARMENIAN COMMA --> - <Key - latin:keyLabel="՝" - latin:backgroundType="functional" /> - <!-- U+0589: "։" ARMENIAN FULL STOP --> - <Key - latin:keyLabel="։" - latin:keyLabelFlags="hasPopupHint" - latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_punctuation" /> - </case> - <default> - <Key - latin:keyLabel="!text/keylabel_for_tablet_comma" - latin:keyHintLabel="!text/keyhintlabel_for_tablet_comma" - latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_tablet_comma" /> - <Key - latin:keyLabel="." - latin:keyHintLabel="!text/keyhintlabel_for_period" - latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_period" /> - </default> - </switch> -</merge> diff --git a/java/res/xml-sw600dp/key_greek_semicolon.xml b/java/res/xml/keys_comma_period_symbols.xml index 3f09419b1..843595c27 100644 --- a/java/res/xml-sw600dp/key_greek_semicolon.xml +++ b/java/res/xml/keys_comma_period_symbols.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2013, 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,8 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel=";" - latin:keyHintLabel=":" - latin:moreKeys=":" - latin:keyStyle="hasShiftedLetterHintStyle" /> + latin:keySpec="!text/keyspec_comma" /> + <!-- U+2026: "…" HORIZONTAL ELLIPSIS --> + <Key + latin:keySpec="." + latin:moreKeys="…" /> </merge> diff --git a/java/res/xml/keys_curly_brackets.xml b/java/res/xml/keys_curly_brackets.xml index 6a4b1a945..596516af3 100644 --- a/java/res/xml/keys_curly_brackets.xml +++ b/java/res/xml/keys_curly_brackets.xml @@ -22,9 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="{" - latin:code="!code/key_left_curly_bracket" /> + latin:keySpec="!text/keyspec_left_curly_bracket" /> <Key - latin:keyLabel="}" - latin:code="!code/key_right_curly_bracket" /> + latin:keySpec="!text/keyspec_right_curly_bracket" /> </merge> diff --git a/java/res/xml/keys_dvorak_123.xml b/java/res/xml/keys_dvorak_123.xml index fa94f1f28..6efc7f2c5 100644 --- a/java/res/xml/keys_dvorak_123.xml +++ b/java/res/xml/keys_dvorak_123.xml @@ -26,7 +26,7 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel=""" + latin:keySpec=""" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> </case> @@ -34,7 +34,7 @@ latin:mode="url" > <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> </case> @@ -42,13 +42,13 @@ latin:mode="email" > <Key - latin:keyLabel="\@" + latin:keySpec="\@" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> </case> <default> <Key - latin:keyLabel="\'" + latin:keySpec="\'" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys="!,"" /> @@ -59,22 +59,22 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel="<" + latin:keySpec="<" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <Key - latin:keyLabel=">" + latin:keySpec=">" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> </case> <default> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="\?,<" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys=">" /> diff --git a/java/res/xml/keys_farsi3_right.xml b/java/res/xml/keys_farsi3_right.xml index 77efb0a21..2618e478c 100644 --- a/java/res/xml/keys_farsi3_right.xml +++ b/java/res/xml/keys_farsi3_right.xml @@ -23,6 +23,6 @@ > <!-- U+0686: "چ" ARABIC LETTER TCHEH --> <Key - latin:keyLabel="چ" + latin:keySpec="چ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml index 56d0727dd..778de02a1 100644 --- a/java/res/xml/keys_less_greater.xml +++ b/java/res/xml/keys_less_greater.xml @@ -25,30 +25,24 @@ <case latin:languageCode="fa" > - <!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel="«" - latin:code="0x00BB" + latin:keySpec="!text/keyspec_left_double_angle_quote" latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_less_than" /> + latin:moreKeys="!text/morekeys_less_than" /> <Key - latin:keyLabel="»" - latin:code="0x00AB" + latin:keySpec="!text/keyspec_right_double_angle_quote" latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_greater_than" /> + latin:moreKeys="!text/morekeys_greater_than" /> </case> <default> <Key - latin:keyLabel="<" - latin:code="!code/key_less_than" + latin:keySpec="!text/keyspec_less_than" latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_less_than" /> + latin:moreKeys="!text/morekeys_less_than" /> <Key - latin:keyLabel=">" - latin:code="!code/key_greater_than" + latin:keySpec="!text/keyspec_greater_than" latin:backgroundType="functional" - latin:moreKeys="!text/more_keys_for_greater_than" /> + latin:moreKeys="!text/morekeys_greater_than" /> </default> </switch> </merge> diff --git a/java/res/xml/keys_parentheses.xml b/java/res/xml/keys_parentheses.xml index 25e89c930..320b109a8 100644 --- a/java/res/xml/keys_parentheses.xml +++ b/java/res/xml/keys_parentheses.xml @@ -22,11 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="(" - latin:code="!code/key_left_parenthesis" - latin:moreKeys="!text/more_keys_for_left_parenthesis" /> + latin:keySpec="!text/keyspec_left_parenthesis" + latin:moreKeys="!text/morekeys_left_parenthesis" /> <Key - latin:keyLabel=")" - latin:code="!code/key_right_parenthesis" - latin:moreKeys="!text/more_keys_for_right_parenthesis" /> + latin:keySpec="!text/keyspec_right_parenthesis" + latin:moreKeys="!text/morekeys_right_parenthesis" /> </merge> diff --git a/java/res/xml/keys_pcqwerty2_right3.xml b/java/res/xml/keys_pcqwerty2_right3.xml index 6f86477da..b188cffab 100644 --- a/java/res/xml/keys_pcqwerty2_right3.xml +++ b/java/res/xml/keys_pcqwerty2_right3.xml @@ -23,26 +23,26 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel="[" + latin:keySpec="[" latin:additionalMoreKeys="{" /> <Key - latin:keyLabel="]" + latin:keySpec="]" latin:additionalMoreKeys="}" /> <Key - latin:keyLabel="\\" + latin:keySpec="\\" latin:additionalMoreKeys="\\|" /> </case> <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> <Key - latin:keyLabel="{" /> + latin:keySpec="{" /> <Key - latin:keyLabel="}" /> + latin:keySpec="}" /> <Key - latin:keyLabel="|" /> + latin:keySpec="|" /> </default> </switch> </merge> diff --git a/java/res/xml/keys_pcqwerty3_right2.xml b/java/res/xml/keys_pcqwerty3_right2.xml index 8da145b20..8a1f60fae 100644 --- a/java/res/xml/keys_pcqwerty3_right2.xml +++ b/java/res/xml/keys_pcqwerty3_right2.xml @@ -23,22 +23,22 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel=";" + latin:keySpec=";" latin:additionalMoreKeys=":" /> <Key - latin:keyLabel="\'" + latin:keySpec="\'" latin:additionalMoreKeys=""" latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,%,!text/single_quotes" /> </case> <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> <Key - latin:keyLabel=":" /> + latin:keySpec=":" /> <Key - latin:keyLabel=""" + latin:keySpec=""" latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" /> </default> </switch> diff --git a/java/res/xml/keys_pcqwerty4_right3.xml b/java/res/xml/keys_pcqwerty4_right3.xml index e6084cb45..a87f550f7 100644 --- a/java/res/xml/keys_pcqwerty4_right3.xml +++ b/java/res/xml/keys_pcqwerty4_right3.xml @@ -23,18 +23,18 @@ > <switch> <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" > <Key - latin:keyLabel="," + latin:keySpec="," latin:additionalMoreKeys="<" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:additionalMoreKeys=">" /> <Key - latin:keyLabel="/" + latin:keySpec="/" latin:additionalMoreKeys="\?" - latin:moreKeys="!text/more_keys_for_symbols_question" /> + latin:moreKeys="!text/morekeys_question" /> </case> <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> <default> @@ -45,14 +45,14 @@ U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel="<" + latin:keySpec="<" latin:moreKeys="!fixedColumnOrder!3,‹,≤,«" /> <Key - latin:keyLabel=">" + latin:keySpec=">" latin:moreKeys="!fixedColumnOrder!3,›,≥,»" /> <Key - latin:keyLabel="\?" - latin:moreKeys="!text/more_keys_for_symbols_question" /> + latin:keySpec="\?" + latin:moreKeys="!text/morekeys_question" /> </default> </switch> </merge> diff --git a/java/res/xml/keys_square_brackets.xml b/java/res/xml/keys_square_brackets.xml index 5c128fd0c..076b2c2d9 100644 --- a/java/res/xml/keys_square_brackets.xml +++ b/java/res/xml/keys_square_brackets.xml @@ -22,9 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="[" - latin:code="!code/key_left_square_bracket" /> + latin:keySpec="!text/keyspec_left_square_bracket" /> <Key - latin:keyLabel="]" - latin:code="!code/key_right_square_bracket" /> + latin:keySpec="!text/keyspec_right_square_bracket" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_sign_anusvara.xml b/java/res/xml/keystyle_devanagari_sign_anusvara.xml new file mode 100644 index 000000000..6dc9b7e3a --- /dev/null +++ b/java/res/xml/keystyle_devanagari_sign_anusvara.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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. +*/ +--> + +<!-- The code point U+25CC for key label is needed because the font rendering system prior to + API version 16 can't automatically render dotted circle for incomplete combining letter + of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the + counterpart files named res/xml-v16/key_*.xml don't have this hack. --> +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0903: "ः" DEVANAGARI SIGN VISARGA + U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + U+093C: "़" DEVANAGARI SIGN NUKTA --> + <key-style + latin:styleName="moreKeysDevanagariSignAnusvara" + latin:moreKeys="◌ः|ः,◌ँ|ँ,◌़|़" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariSignAnusvara" /> + </default> + </switch> + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0902: "ं" DEVANAGARI SIGN ANUSVARA --> + <key-style + latin:styleName="baseKeyDevanagariSignAnusvara" + latin:parentStyle="moreKeysDevanagariSignAnusvara" + latin:keySpec="◌ं|ं" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> +</merge> diff --git a/java/res/xml/key_devanagari_sign_candrabindu.xml b/java/res/xml/keystyle_devanagari_sign_candrabindu.xml index df0c4e054..24cb44ba8 100644 --- a/java/res/xml/key_devanagari_sign_candrabindu.xml +++ b/java/res/xml/keystyle_devanagari_sign_candrabindu.xml @@ -42,9 +42,9 @@ </switch> <!-- U+25CC: "◌" DOTTED CIRCLE U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU --> - <Key - latin:keyStyle="moreKeysDevanagariSignCandrabindu" - latin:keyLabel="◌ँ" - latin:code="0x0901" + <key-style + latin:styleName="baseKeyDevanagariSignCandrabindu" + latin:parentStyle="moreKeysDevanagariSignCandrabindu" + latin:keySpec="◌ँ|ँ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/key_devanagari_sign_nukta.xml b/java/res/xml/keystyle_devanagari_sign_nukta.xml index f7a03ee90..41da555ce 100644 --- a/java/res/xml/key_devanagari_sign_nukta.xml +++ b/java/res/xml/keystyle_devanagari_sign_nukta.xml @@ -37,6 +37,15 @@ latin:styleName="moreKeysDevanagariSignNukta" latin:moreKeys="◌ॽ|ॽ,◌॰|॰,◌ऽ|ऽ" /> </case> + <case + latin:keyboardLayoutSet="nepali_romanized" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+093C: "़" DEVANAGARI SIGN NUKTA --> + <key-style + latin:styleName="moreKeysDevanagariSignNukta" + latin:moreKeys="◌़|़" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariSignNukta" /> @@ -44,9 +53,9 @@ </switch> <!-- U+25CC: "◌" DOTTED CIRCLE U+093C: "़" DEVANAGARI SIGN NUKTA --> - <Key - latin:keyStyle="moreKeysDevanagariSignNukta" - latin:keyLabel="◌़" - latin:code="0x093C" + <key-style + latin:styleName="baseKeyDevanagariSignNukta" + latin:parentStyle="moreKeysDevanagariSignNukta" + latin:keySpec="◌़|़" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_sign_virama.xml b/java/res/xml/keystyle_devanagari_sign_virama.xml index b22fbe842..96506e2fc 100644 --- a/java/res/xml/keystyle_devanagari_sign_virama.xml +++ b/java/res/xml/keystyle_devanagari_sign_virama.xml @@ -25,11 +25,26 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+094D: "्" DEVANAGARI SIGN VIRAMA --> + <key-style + latin:styleName="moreKeysDevanagariSignVirama" + latin:moreKeys="◌्|्" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariSignVirama" /> + </default> + </switch> <!-- U+25CC: "◌" DOTTED CIRCLE U+094D: "्" DEVANAGARI SIGN VIRAMA --> <key-style latin:styleName="baseKeyDevanagariSignVirama" - latin:keyLabel="◌्" - latin:code="0x094D" + latin:parentStyle="moreKeysDevanagariSignVirama" + latin:keySpec="◌्|्" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_sign_visarga.xml b/java/res/xml/keystyle_devanagari_sign_visarga.xml index cb294951f..45f519a43 100644 --- a/java/res/xml/keystyle_devanagari_sign_visarga.xml +++ b/java/res/xml/keystyle_devanagari_sign_visarga.xml @@ -29,7 +29,6 @@ U+0903: "ः" DEVANAGARI SIGN VISARGA --> <key-style latin:styleName="baseKeyDevanagariSignVisarga" - latin:keyLabel="◌ः" - latin:code="0x0903" + latin:keySpec="◌ः|ः" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml b/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml index 2e78c53ec..4b876505a 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml @@ -36,6 +36,15 @@ latin:styleName="moreKeysDevanagariVowelSignAa" latin:moreKeys="◌ां|ां,◌ाँ|ाँ,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+093E: "ा" DEVANAGARI VOWEL SIGN AA --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAa" + latin:moreKeys="◌ा|ा,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignAa" /> @@ -46,7 +55,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAa" latin:parentStyle="moreKeysDevanagariVowelSignAa" - latin:keyLabel="◌ा" - latin:code="0x093E" + latin:keySpec="◌ा|ा" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml b/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml index 0554c0e15..050a7ce0e 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml @@ -36,6 +36,15 @@ latin:moreKeys="◌ैं|ैं,%" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0948: "ै" DEVANAGARI VOWEL SIGN AI --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAi" + latin:moreKeys="◌ै|ै,%" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> @@ -53,7 +62,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAi" latin:parentStyle="moreKeysDevanagariVowelSignAi" - latin:keyLabel="◌ै" - latin:code="0x0948" + latin:keySpec="◌ै|ै" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_au.xml b/java/res/xml/keystyle_devanagari_vowel_sign_au.xml index 29a11a82e..49e67da38 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_au.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_au.xml @@ -30,11 +30,20 @@ latin:keyboardLayoutSet="hindi" > <!-- U+25CC: "◌" DOTTED CIRCLE - U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA --> + U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA --> <key-style latin:styleName="moreKeysDevanagariVowelSignAu" latin:moreKeys="◌ौं|ौं,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+094C: "ौ" DEVANAGARI VOWEL SIGN AU --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignAu" + latin:moreKeys="◌ौ|ौ,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignAu" /> @@ -44,7 +53,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignAu" latin:parentStyle="moreKeysDevanagariVowelSignAu" - latin:keyLabel="◌ौ" - latin:code="0x094C" + latin:keySpec="◌ौ|ौ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/key_devanagari_sign_anusvara.xml b/java/res/xml/keystyle_devanagari_vowel_sign_candra_e.xml index 0acd3bcd4..86f68d355 100644 --- a/java/res/xml/key_devanagari_sign_anusvara.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_candra_e.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2013, The Android Open Source Project +** Copyright 2014, 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. @@ -25,10 +25,19 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <!-- U+25CC: "◌" DOTTED CIRCLE - U+0902: "ं" DEVANAGARI SIGN ANUSVARA --> - <Key - latin:keyLabel="◌ं" - latin:code="0x0902" - latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraE" + latin:moreKeys="◌ॅ|ॅ" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraE" /> + </default> + </switch> </merge> diff --git a/java/res/xml/key_devanagari_vowel_sign_candra_o.xml b/java/res/xml/keystyle_devanagari_vowel_sign_candra_o.xml index 370fc5405..fd711e049 100644 --- a/java/res/xml/key_devanagari_vowel_sign_candra_o.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_candra_o.xml @@ -25,10 +25,26 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <switch> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraO" + latin:moreKeys="◌ॉ|ॉ" /> + </case> + <default> + <key-style + latin:styleName="moreKeysDevanagariVowelSignCandraO" /> + </default> + </switch> <!-- U+25CC: "◌" DOTTED CIRCLE U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O --> - <Key - latin:keyLabel="◌ॉ" - latin:code="0x0949" + <key-style + latin:styleName="baseKeyDevanagariVowelSignCandraO" + latin:parentStyle="moreKeysDevanagariVowelSignCandraO" + latin:keySpec="◌ॉ|ॉ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_e.xml b/java/res/xml/keystyle_devanagari_vowel_sign_e.xml index edd29c791..88f6a74f4 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_e.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_e.xml @@ -36,6 +36,15 @@ latin:moreKeys="◌ें|ें" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0947: "े" DEVANAGARI VOWEL SIGN E --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignE" + latin:moreKeys="◌े|े" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+25CC: "◌" DOTTED CIRCLE @@ -53,7 +62,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignE" latin:parentStyle="moreKeysDevanagariVowelSignE" - latin:keyLabel="◌े" - latin:code="0x0947" + latin:keySpec="◌े|े" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_i.xml b/java/res/xml/keystyle_devanagari_vowel_sign_i.xml index 200fed29f..a84fdb4a9 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_i.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_i.xml @@ -35,6 +35,15 @@ latin:styleName="moreKeysDevanagariVowelSignI" latin:moreKeys="ि◌ं|िं" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+093F: "ि" DEVANAGARI VOWEL SIGN I --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignI" + latin:moreKeys="◌ि|ि" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignI" /> @@ -45,7 +54,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignI" latin:parentStyle="moreKeysDevanagariVowelSignI" - latin:keyLabel="◌ि" - latin:code="0x093F" + latin:keySpec="◌ि|ि" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml b/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml index 6dc9951df..6f6eb0f15 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml @@ -29,12 +29,21 @@ <case latin:keyboardLayoutSet="hindi" > - <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II + <!-- U+25CC: "◌" DOTTED CIRCLE U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA --> <key-style latin:styleName="moreKeysDevanagariVowelSignIi" latin:moreKeys="◌ीं|ीं,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0940: "ी" DEVANAGARI VOWEL SIGN II --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignIi" + latin:moreKeys="◌ी|ी,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignIi" /> @@ -45,7 +54,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignIi" latin:parentStyle="moreKeysDevanagariVowelSignIi" - latin:keyLabel="◌ी" - latin:code="0x0940" + latin:keySpec="◌ी|ी" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_o.xml b/java/res/xml/keystyle_devanagari_vowel_sign_o.xml index 233ac8609..68b176a43 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_o.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_o.xml @@ -30,13 +30,22 @@ latin:keyboardLayoutSet="hindi" > <!-- U+25CC: "◌" DOTTED CIRCLE - U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA + U+094B/U+0902: "ों" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O --> <key-style latin:styleName="moreKeysDevanagariVowelSignO" latin:moreKeys="◌ों|ों,◌ॉ|ॉ,◌ॊ|ॊ" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+094B: "ो" DEVANAGARI VOWEL SIGN O --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignO" + latin:moreKeys="◌ो|ो" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignO" /> @@ -47,7 +56,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignO" latin:parentStyle="moreKeysDevanagariVowelSignO" - latin:keyLabel="◌ो" - latin:code="0x094B" + latin:keySpec="◌ो|ो" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_u.xml b/java/res/xml/keystyle_devanagari_vowel_sign_u.xml index 7291b7099..7c058b174 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_u.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_u.xml @@ -36,6 +36,15 @@ latin:styleName="moreKeysDevanagariVowelSignU" latin:moreKeys="◌ुं|ुं,◌ुँ|ुँ" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0941: "ु" DEVANAGARI VOWEL SIGN U --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignU" + latin:moreKeys="◌ु|ु" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignU" /> @@ -46,7 +55,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignU" latin:parentStyle="moreKeysDevanagariVowelSignU" - latin:keyLabel="◌ु" - latin:code="0x0941" + latin:keySpec="◌ु|ु" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml b/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml index a95ab822d..73ab63c89 100644 --- a/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml @@ -36,6 +36,15 @@ latin:styleName="moreKeysDevanagariVowelSignUu" latin:moreKeys="◌ूं|ूं,◌ूँ|ूँ,%" /> </case> + <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+25CC: "◌" DOTTED CIRCLE + U+0942: "ू" DEVANAGARI VOWEL SIGN UU --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignUu" + latin:moreKeys="◌ू|ू,%" /> + </case> <default> <key-style latin:styleName="moreKeysDevanagariVowelSignUu" /> @@ -46,7 +55,6 @@ <key-style latin:styleName="baseKeyDevanagariVowelSignUu" latin:parentStyle="moreKeysDevanagariVowelSignUu" - latin:keyLabel="◌ू" - latin:code="0x0942" + latin:keySpec="◌ू|ू" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml b/java/res/xml/keystyle_devanagari_vowel_sign_vocalic_r.xml index f150d7ed9..29b083eb3 100644 --- a/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml +++ b/java/res/xml/keystyle_devanagari_vowel_sign_vocalic_r.xml @@ -36,6 +36,16 @@ latin:moreKeys="◌ॄ|ॄ" /> </case> <case + latin:keyboardLayoutSet="hindi_compact" + > + <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + U+25CC: "◌" DOTTED CIRCLE + U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R --> + <key-style + latin:styleName="moreKeysDevanagariVowelSignVocalicR" + latin:moreKeys="ऋ,◌ृ|ृ" /> + </case> + <case latin:keyboardLayoutSet="nepali_traditional" > <!-- U+0913: "ओ" DEVANAGARI LETTER O --> @@ -50,9 +60,9 @@ </switch> <!-- U+25CC: "◌" DOTTED CIRCLE U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R --> - <Key - latin:keyStyle="moreKeysDevanagariVowelSignVocalicR" - latin:keyLabel="◌ृ" - latin:code="0x0943" + <key-style + latin:styleName="baseKeyDevanagariVowelSignVocalicR" + latin:parentStyle="moreKeysDevanagariVowelSignVocalicR" + latin:keySpec="◌ृ|ृ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </merge> diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 0a27da93f..28eceb8db 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -24,52 +24,60 @@ keyboard_locale: script_name/keyboard_layout_set af: Afrikaans/qwerty ar: Arabic/arabic - (az: Azerbaijani/qwerty) # disabled temporarily. waiting for string resources. - be: Belarusian/east_slavic + az_AZ: Azerbaijani (Azerbaijan)/qwerty + be_BY: Belarusian (Belarus)/east_slavic bg: Bulgarian/bulgarian bg: Bulgarian/bulgarian_bds ca: Catalan/spanish cs: Czech/qwertz da: Danish/nordic de: German/qwertz + de_CH: German (Switzerland)/swiss el: Greek/greek - en_US: English United States/qwerty - en_GB: English Great Britain/qwerty + en_IN: English (India)/qwerty + en_US: English (United States)/qwerty + en_GB: English (Great Britain)/qwerty eo: Esperanto/spanish es: Spanish/spanish - es_US: Spanish United States/spanish - (es_419: Spanish Latin America/qwerty) - et_EE: Estonian/nordic - fa: Persian/arabic + es_US: Spanish (United States)/spanish + es_419: Spanish (Latin America)/spanish + et_EE: Estonian (Estonia)/nordic + eu_ES: Basque (Spain)/spanish + fa: Persian/farsi fi: Finnish/nordic fr: French/azerty - fr_CA: French Canada/qwerty + fr_CA: French (Canada)/qwerty + fr_CH: French (Switzerland)/swiss + gl_ES: Galician (Spain)/spanish hi: Hindi/hindi + (hi: Hindi/hindi_compact) # This is a preliminary keyboard layout. hr: Croatian/qwertz hu: Hungarian/qwertz - hy_AM: Armenian Phonetic/armenian_phonetic - in: Indonesian/qwerty # "id" is official language code of Indonesian. + hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic + in: Indonesian/qwerty # "id" is the official language code of Indonesian. is: Icelandic/qwerty it: Italian/qwerty - iw: Hebrew/hebrew # "he" is official language code of Hebrew. - ka_GE: Georgian/georgian - (kk: Kazakh/east_slavic) # disabled temporarily. waiting for string resources. - km_KH: Khmer/khmer + it_CH: Italian (Switzerland)/swiss + iw: Hebrew/hebrew # "he" is the official language code of Hebrew. + ka_GE: Georgian (Georgia)/georgian + kk: Kazakh/east_slavic + km_KH: Khmer (Cambodia)/khmer ky: Kyrgyz/east_slavic - lo_LA: Lao/lao + lo_LA: Lao (Laos)/lao lt: Lithuanian/qwerty lv: Latvian/qwerty mk: Macedonian/south_slavic - mn_MN: Mongolian/mongolian - ms_MY: Malay/qwerty + mn_MN: Mongolian (Mongolia)/mongolian + ms_MY: Malay (Malaysia)/qwerty + (my_MM: Myanmar (Myanmar)/myanmar) # This is a preliminary keyboard layout. nb: Norwegian Bokmål/nordic - (ne: Nepali Romanized/nepali_romanized) # disabled temporarily - (ne: Nepali Traditional/nepali_traditional) # disabled temporarily + ne_NP: Nepali (Nepal) Romanized/nepali_romanized + ne_NP: Nepali (Nepal) Traditional/nepali_traditional nl: Dutch/qwerty - nl_BE: Dutch Belgium/azerty + nl_BE: Dutch (Belgium)/azerty pl: Polish/qwerty - pt_BR: Portuguese Brazil/qwerty - pt_PT: Portuguese Portugal/qwerty + pt_BR: Portuguese (Brazil)/qwerty + pt_PT: Portuguese (Portugal)/qwerty ro: Romanian/qwerty ru: Russian/east_slavic sk: Slovak/qwerty @@ -88,19 +96,22 @@ (zz: Emoji/emoji) --> <!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. --> +<!-- TODO: Remove "AsciiCapable" from the extra values when we can stop supporting JB-MR1 --> <!-- Note: SupportTouchPositionCorrection extra value is obsolete and maintained for backward compatibility. --> <!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default subtype.--> <input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity" - android:isDefault="@bool/im_is_default"> + android:isDefault="@bool/im_is_default" + android:supportsSwitchingToNextInputMethod="true"> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_en_US" android:subtypeId="0xc9194f98" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_en_GB" @@ -108,6 +119,7 @@ android:imeSubtypeLocale="en_GB" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -115,6 +127,7 @@ android:imeSubtypeLocale="af" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -122,22 +135,23 @@ android:imeSubtypeLocale="ar" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="false" /> - <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x70b0f974" - android:imeSubtypeLocale="az" + android:imeSubtypeLocale="az_AZ" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> - --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x1dc3a859" - android:imeSubtypeLocale="be" + android:imeSubtypeLocale="be_BY" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -145,6 +159,7 @@ android:imeSubtypeLocale="bg" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_bulgarian_bds" @@ -152,6 +167,7 @@ android:imeSubtypeLocale="bg" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -159,6 +175,7 @@ android:imeSubtypeLocale="ca" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -166,6 +183,7 @@ android:imeSubtypeLocale="cs" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -173,6 +191,7 @@ android:imeSubtypeLocale="da" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -180,6 +199,15 @@ android:imeSubtypeLocale="de" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0x7acfd0aa" + android:imeSubtypeLocale="de_CH" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -187,6 +215,15 @@ android:imeSubtypeLocale="el" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=greek,EmojiCapable" + android:isAsciiCapable="false" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0x8d58fc2d" + android:imeSubtypeLocale="en_IN" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -194,6 +231,7 @@ android:imeSubtypeLocale="eo" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -201,6 +239,7 @@ android:imeSubtypeLocale="es" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_es_US" @@ -208,22 +247,31 @@ android:imeSubtypeLocale="es_US" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> - <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" - android:subtypeId="0x623f9286" + android:subtypeId="0xa23e5d19" android:imeSubtypeLocale="es_419" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> - --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xec2d3955" android:imeSubtypeLocale="et_EE" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=nordic,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0x070e5c07" + android:imeSubtypeLocale="eu_ES" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -231,6 +279,7 @@ android:imeSubtypeLocale="fa" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=farsi,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -238,6 +287,7 @@ android:imeSubtypeLocale="fi" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -245,6 +295,7 @@ android:imeSubtypeLocale="fr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -252,6 +303,23 @@ android:imeSubtypeLocale="fr_CA" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0xeadc55f5" + android:imeSubtypeLocale="fr_CH" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0xb939573c" + android:imeSubtypeLocale="gl_ES" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -259,6 +327,17 @@ android:imeSubtypeLocale="hi" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi,EmojiCapable" + android:isAsciiCapable="false" + /> + <!-- TODO: This hindi_compact keyboard is a preliminary layout. + This isn't based on the final specification. --> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic_compact" + android:subtypeId="0xe49c89a1" + android:imeSubtypeLocale="hi" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi_compact,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -266,6 +345,7 @@ android:imeSubtypeLocale="hr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -273,6 +353,7 @@ android:imeSubtypeLocale="hu" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -280,6 +361,7 @@ android:imeSubtypeLocale="hy_AM" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=armenian_phonetic,EmojiCapable" + android:isAsciiCapable="false" /> <!-- Java uses the deprecated "in" code instead of the standard "id" code for Indonesian. --> <subtype android:icon="@drawable/ic_ime_switcher_dark" @@ -288,6 +370,7 @@ android:imeSubtypeLocale="in" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -295,6 +378,7 @@ android:imeSubtypeLocale="is" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -302,6 +386,15 @@ android:imeSubtypeLocale="it" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" + /> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0xd914fe1a" + android:imeSubtypeLocale="it_CH" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <!-- Java uses the deprecated "iw" code instead of the standard "he" code for Hebrew. --> <subtype android:icon="@drawable/ic_ime_switcher_dark" @@ -310,6 +403,7 @@ android:imeSubtypeLocale="iw" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -317,22 +411,23 @@ android:imeSubtypeLocale="ka_GE" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=georgian,EmojiCapable" + android:isAsciiCapable="false" /> - <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x2d73d2f6" android:imeSubtypeLocale="kk" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable" + android:isAsciiCapable="false" /> - --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x1365683a" android:imeSubtypeLocale="km_KH" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=khmer,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -340,6 +435,7 @@ android:imeSubtypeLocale="ky" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -347,6 +443,7 @@ android:imeSubtypeLocale="lo_LA" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=lao,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -354,6 +451,7 @@ android:imeSubtypeLocale="lt" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -361,6 +459,7 @@ android:imeSubtypeLocale="lv" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -368,6 +467,7 @@ android:imeSubtypeLocale="mk" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -375,6 +475,7 @@ android:imeSubtypeLocale="mn_MN" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -382,6 +483,17 @@ android:imeSubtypeLocale="ms_MY" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" + /> + <!-- TODO: This Myanmar keyboard is a preliminary layout. + This isn't based on the final specification. --> + <subtype android:icon="@drawable/ic_ime_switcher_dark" + android:label="@string/subtype_generic" + android:subtypeId="0xea266ea4" + android:imeSubtypeLocale="my_MM" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -389,29 +501,31 @@ android:imeSubtypeLocale="nb" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> - <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xd80a4cee" - android:imeSubtypeLocale="ne" + android:imeSubtypeLocale="ne_NP" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_romanized,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" - android:label="@string/subtype_nepali_traditional" + android:label="@string/subtype_generic_traditional" android:subtypeId="0x5fafea88" - android:imeSubtypeLocale="ne" + android:imeSubtypeLocale="ne_NP" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_traditional,EmojiCapable" + android:isAsciiCapable="false" /> - --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x3f9fd91e" android:imeSubtypeLocale="nl" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -419,6 +533,7 @@ android:imeSubtypeLocale="nl_BE" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=azerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -426,6 +541,7 @@ android:imeSubtypeLocale="pl" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -433,6 +549,7 @@ android:imeSubtypeLocale="pt_BR" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -440,6 +557,7 @@ android:imeSubtypeLocale="pt_PT" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -447,6 +565,7 @@ android:imeSubtypeLocale="ro" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -454,6 +573,7 @@ android:imeSubtypeLocale="ru" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -461,6 +581,7 @@ android:imeSubtypeLocale="sk" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -468,6 +589,7 @@ android:imeSubtypeLocale="sl" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -475,6 +597,7 @@ android:imeSubtypeLocale="sr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="false" /> <!-- TODO: Uncomment once we can handle IETF language tag with script name specified. <subtype android:icon="@drawable/ic_ime_switcher_dark" @@ -483,6 +606,7 @@ android:imeSubtypeLocale="sr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_serbian_latin" @@ -490,6 +614,7 @@ android:imeSubtypeLocale="sr-Latn" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> --> <subtype android:icon="@drawable/ic_ime_switcher_dark" @@ -498,6 +623,7 @@ android:imeSubtypeLocale="sv" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -505,6 +631,7 @@ android:imeSubtypeLocale="sw" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -512,6 +639,7 @@ android:imeSubtypeLocale="th" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=thai,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -519,6 +647,7 @@ android:imeSubtypeLocale="tl" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -526,6 +655,7 @@ android:imeSubtypeLocale="tr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -533,6 +663,7 @@ android:imeSubtypeLocale="uk" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable" + android:isAsciiCapable="false" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -540,6 +671,7 @@ android:imeSubtypeLocale="vi" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" @@ -547,6 +679,7 @@ android:imeSubtypeLocale="zu" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_no_language_qwerty" @@ -554,6 +687,7 @@ android:imeSubtypeLocale="zz" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable,EmojiCapable" + android:isAsciiCapable="true" /> <!-- Emoji subtype has to be an addtional subtype added at boot time because ICS doesn't support Emoji. --> @@ -564,6 +698,7 @@ android:imeSubtypeLocale="zz" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=emoji,EmojiCapable" + android:isAsciiCapable="false" /> --> </input-method> diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index bf3b62353..7d86dbd5d 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -89,6 +89,12 @@ android:entryValues="@array/prefs_suggestion_visibility_values" android:entries="@array/prefs_suggestion_visibilities" android:defaultValue="@string/prefs_suggestion_visibility_default_value" /> + <CheckBoxPreference + android:key="pref_key_use_personalized_dicts" + android:title="@string/use_personalized_dicts" + android:summary="@string/use_personalized_dicts_summary" + android:persistent="true" + android:defaultValue="true" /> </PreferenceCategory> <PreferenceCategory android:title="@string/gesture_typing_category" @@ -151,34 +157,22 @@ android:summary="@string/include_other_imes_in_language_switch_list_summary" android:persistent="true" android:defaultValue="false" /> - <!-- Values for popup dismiss delay are added programmatically --> - <CheckBoxPreference - android:key="pref_sliding_key_input_preview" - android:title="@string/sliding_key_input_preview" - android:summary="@string/sliding_key_input_preview_summary" - android:persistent="true" - android:defaultValue="true" /> <ListPreference android:key="pref_keyboard_layout_20110916" android:title="@string/keyboard_color_scheme" android:persistent="true" - android:entryValues="@array/keyboard_color_schemes_values" - android:entries="@array/keyboard_color_schemes" - android:defaultValue="@string/config_default_keyboard_theme_index" /> + android:entryValues="@array/keyboard_theme_ids" + android:entries="@array/keyboard_theme_names" + android:defaultValue="@string/config_default_keyboard_theme_id" /> <PreferenceScreen android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings" android:key="custom_input_styles" android:title="@string/custom_input_styles_title" /> + <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. --> <ListPreference android:key="pref_key_preview_popup_dismiss_delay" android:title="@string/key_preview_popup_dismiss_delay" /> <com.android.inputmethod.latin.settings.SeekBarDialogPreference - android:key="pref_key_longpress_timeout" - android:title="@string/prefs_key_longpress_timeout_settings" - latin:minValue="@integer/config_min_longpress_timeout" - latin:maxValue="@integer/config_max_longpress_timeout" - latin:stepValue="@integer/config_longpress_timeout_step" /> - <com.android.inputmethod.latin.settings.SeekBarDialogPreference android:key="pref_vibration_duration_settings" android:title="@string/prefs_keypress_vibration_duration_settings" latin:maxValue="@integer/config_max_vibration_duration" /> diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml index 8d9508e38..c333b0751 100644 --- a/java/res/xml/prefs_for_debug.xml +++ b/java/res/xml/prefs_for_debug.xml @@ -14,51 +14,74 @@ limitations under the License. --> -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - android:title="@string/prefs_debug_mode" - android:key="english_ime_debug_settings"> - +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + android:title="@string/prefs_debug_mode" + android:key="english_ime_debug_settings" +> <CheckBoxPreference - android:key="enable_logging" - android:title="@string/prefs_enable_log" - android:summary="@string/prefs_description_log" - android:persistent="true" - android:defaultValue="false" /> - - <ListPreference - android:key="pref_keyboard_layout_20110916" - android:title="@string/keyboard_layout" - android:summary="%s" - android:persistent="true" - android:entryValues="@array/keyboard_layout_modes_values" - android:entries="@array/keyboard_layout_modes" - android:defaultValue="@string/config_default_keyboard_theme_index" /> - + android:key="enable_logging" + android:title="@string/prefs_enable_log" + android:summary="@string/prefs_description_log" + android:persistent="true" + android:defaultValue="false" /> <CheckBoxPreference - android:key="debug_mode" - android:title="@string/prefs_debug_mode" - android:persistent="true" - android:defaultValue="false" /> - + android:key="debug_mode" + android:title="@string/prefs_debug_mode" + android:persistent="true" + android:defaultValue="false" /> <CheckBoxPreference - android:key="force_non_distinct_multitouch" - android:title="@string/prefs_force_non_distinct_multitouch" - android:persistent="true" - android:defaultValue="false" /> - + android:key="force_non_distinct_multitouch" + android:title="@string/prefs_force_non_distinct_multitouch" + android:persistent="true" + android:defaultValue="false" /> <CheckBoxPreference - android:key="usability_study_mode" - android:title="@string/prefs_usability_study_mode" - android:persistent="true" - android:defaultValue="false" /> - + android:key="usability_study_mode" + android:title="@string/prefs_usability_study_mode" + android:persistent="true" + android:defaultValue="false" /> <CheckBoxPreference - android:defaultValue="false" - android:key="use_only_personalization_dictionary_for_debug" + android:key="pref_sliding_key_input_preview" + android:title="@string/sliding_key_input_preview" + android:summary="@string/sliding_key_input_preview_summary" android:persistent="true" - android:title="@string/prefs_use_only_personalization_dictionary" /> - + android:defaultValue="true" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_key_longpress_timeout" + android:title="@string/prefs_key_longpress_timeout_settings" + latin:minValue="@integer/config_min_longpress_timeout" + latin:maxValue="@integer/config_max_longpress_timeout" + latin:stepValue="@integer/config_longpress_timeout_step" /> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_key_preview_show_up_start_scale" + android:title="@string/prefs_key_popup_show_up_start_scale_settings" + latin:maxValue="100" /> <!-- percent --> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_key_preview_dismiss_end_scale" + android:title="@string/prefs_key_popup_dismiss_end_scale_settings" + latin:maxValue="100" /> <!-- percent --> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_key_preview_show_up_duration" + android:title="@string/prefs_key_popup_show_up_duration_settings" + latin:maxValue="100" /> <!-- milliseconds --> + <com.android.inputmethod.latin.settings.SeekBarDialogPreference + android:key="pref_key_preview_dismiss_duration" + android:title="@string/prefs_key_popup_dismiss_duration_settings" + latin:maxValue="100" /> <!-- milliseconds --> <PreferenceScreen android:key="read_external_dictionary" android:title="@string/prefs_read_external_dictionary" /> + <PreferenceScreen + android:key="dump_contacts_dict" + android:title="@string/prefs_dump_contacts_dict" /> + <PreferenceScreen + android:key="dump_user_dict" + android:title="@string/prefs_dump_user_dict" /> + <PreferenceScreen + android:key="dump_user_history_dict" + android:title="@string/prefs_dump_user_history_dict" /> + <PreferenceScreen + android:key="dump_personalization_dict" + android:title="@string/prefs_dump_personalization_dict" /> </PreferenceScreen> diff --git a/java/res/xml/row_dvorak4.xml b/java/res/xml/row_dvorak4.xml index b78872fe4..91462cb9c 100644 --- a/java/res/xml/row_dvorak4.xml +++ b/java/res/xml/row_dvorak4.xml @@ -28,17 +28,17 @@ latin:keyStyle="toSymbolKeyStyle" latin:keyWidth="15%p" /> <Key - latin:keyLabel="q" + latin:keySpec="q" latin:backgroundType="normal" - latin:additionalMoreKeys="!text/shortcut_as_more_key" + latin:additionalMoreKeys="!text/keyspec_shortcut" latin:keyStyle="f1MoreKeysStyle" /> <include latin:keyXPos="25%p" latin:keyboardLayout="@xml/key_space_5kw" /> <Key - latin:keyLabel="z" + latin:keySpec="z" latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_punctuation,!text/more_keys_for_z" /> + latin:moreKeys="!text/morekeys_punctuation,!text/morekeys_z" /> <Key latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> diff --git a/java/res/xml/row_pcqwerty5.xml b/java/res/xml/row_pcqwerty5.xml index 4ec908ba1..3782763a8 100644 --- a/java/res/xml/row_pcqwerty5.xml +++ b/java/res/xml/row_pcqwerty5.xml @@ -24,23 +24,21 @@ <Row latin:keyWidth="7.692%p" > - <Spacer - latin:keyWidth="11.538%p" /> <switch> <case - latin:shortcutKeyEnabled="true" + latin:hasShortcutKey="true" > <Key latin:keyStyle="shortcutKeyStyle" latin:keyWidth="11.538%p" /> - </case> + </case> <case latin:clobberSettingsKey="false" > <Key latin:keyStyle="settingsKeyStyle" latin:keyWidth="11.538%p" /> - </case> + </case> </switch> <switch> <case @@ -48,33 +46,23 @@ > <Key latin:keyStyle="languageSwitchKeyStyle" + latin:keyXPos="19.231%p" latin:keyWidth="11.538%p" /> <Key latin:keyStyle="spaceKeyStyle" - latin:keyWidth="38.464%p" /> - </case> + latin:keyWidth="42.308%p" /> + </case> <!-- languageSwitchKeyEnabled="false" --> <default> <Key latin:keyStyle="spaceKeyStyle" - latin:keyWidth="50.002%p" /> + latin:keyXPos="26.923%p" + latin:keyWidth="46.154%p" /> </default> </switch> <Key - latin:keyStyle="defaultEnterKeyStyle" - latin:keyWidth="15.384%p" /> - <switch> - <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" - > - <Spacer /> - </case> - <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> - <default> - <Key - latin:keyStyle="emojiKeyStyle" - latin:keyWidth="fillRight" /> - </default> - </switch> + latin:keyStyle="enterKeyStyle" + latin:keyXPos="-19.231%p" + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml index 578bc1234..509092d96 100644 --- a/java/res/xml/row_qwerty4.xml +++ b/java/res/xml/row_qwerty4.xml @@ -32,36 +32,8 @@ <include latin:keyXPos="25%p" latin:keyboardLayout="@xml/key_space_5kw" /> - <switch> - <case - latin:languageCode="ar|fa" - > - <Key - latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics" - latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint" - latin:moreKeys="!text/more_keys_for_arabic_diacritics" - latin:keyStyle="punctuationKeyStyle" /> - </case> - <case - latin:languageCode="ne" - latin:keyboardLayoutSet="nepali_traditional" - > - <include - latin:keyboardLayout="@xml/key_nepali_traditional_period" /> - </case> - <case - latin:languageCode="hy" - > - <!-- U+0589: "։" ARMENIAN FULL STOP --> - <Key - latin:keyLabel="։" - latin:keyStyle="punctuationKeyStyle" /> - </case> - <default> - <Key - latin:keyStyle="punctuationKeyStyle" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/key_period" /> <Key latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> diff --git a/java/res/xml/row_symbols4.xml b/java/res/xml/row_symbols4.xml index fbfdc5f72..09f6b628c 100644 --- a/java/res/xml/row_symbols4.xml +++ b/java/res/xml/row_symbols4.xml @@ -19,24 +19,12 @@ --> <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <Key - latin:backgroundType="functional" - latin:keyLabel="_" /> + latin:keySpec="_" /> <Key - latin:backgroundType="functional" - latin:keyLabel="/" /> - - <switch> - <case latin:hasShortcutKey="true" > - <Key latin:keyStyle="shortcutKeyStyle" /> - </case> - <!-- latin:hasShortcutKey="false" --> - <default> - </default> - </switch> - - <include latin:keyboardLayout="@xml/key_space_symbols" /> - <include latin:keyboardLayout="@xml/keys_comma_period" /> - + latin:keySpec="/" /> + <include + latin:keyboardLayout="@xml/key_space_symbols" /> + <include + latin:keyboardLayout="@xml/keys_comma_period_symbols" /> </merge> diff --git a/java/res/xml/row_symbols_shift4.xml b/java/res/xml/row_symbols_shift4.xml index 0909374f4..f75575bc6 100644 --- a/java/res/xml/row_symbols_shift4.xml +++ b/java/res/xml/row_symbols_shift4.xml @@ -22,5 +22,5 @@ <include latin:keyboardLayout="@xml/keys_less_greater" /> <include latin:keyboardLayout="@xml/key_space_symbols" /> - <include latin:keyboardLayout="@xml/keys_comma_period" /> + <include latin:keyboardLayout="@xml/keys_comma_period_symbols" /> </merge> diff --git a/java/res/xml/rowkeys_arabic1.xml b/java/res/xml/rowkeys_arabic1.xml index 3c0acf112..266bba407 100644 --- a/java/res/xml/rowkeys_arabic1.xml +++ b/java/res/xml/rowkeys_arabic1.xml @@ -24,43 +24,43 @@ <!-- U+0636: "ض" ARABIC LETTER DAD U+0661: "١" ARABIC-INDIC DIGIT ONE --> <Key - latin:keyLabel="ض" + latin:keySpec="ض" latin:keyHintLabel="1" latin:additionalMoreKeys="1,١" latin:keyLabelFlags="fontNormal" /> <!-- U+0635: "ص" ARABIC LETTER SAD U+0662: "٢" ARABIC-INDIC DIGIT TWO --> <Key - latin:keyLabel="ص" + latin:keySpec="ص" latin:keyHintLabel="2" latin:additionalMoreKeys="2,٢" latin:keyLabelFlags="fontNormal" /> <!-- U+062B: "ث" ARABIC LETTER THEH U+0663: "٣" ARABIC-INDIC DIGIT THREE --> <Key - latin:keyLabel="ث" + latin:keySpec="ث" latin:keyHintLabel="3" latin:additionalMoreKeys="3,٣" latin:keyLabelFlags="fontNormal" /> <!-- U+0642: "ق" ARABIC LETTER QAF - U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE - U+0664: "٤" ARABIC-INDIC DIGIT FOUR --> + U+0664: "٤" ARABIC-INDIC DIGIT FOUR + U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE --> <!-- TODO: DroidSansArabic lacks the glyph of U+06A8 ARABIC LETTER QAF WITH THREE DOTS ABOVE --> <Key - latin:keyLabel="ق" + latin:keySpec="ق" latin:keyHintLabel="4" latin:additionalMoreKeys="4,٤" latin:moreKeys="ڨ" latin:keyLabelFlags="fontNormal" /> <!-- U+0641: "ف" ARABIC LETTER FEH + U+0665: "٥" ARABIC-INDIC DIGIT FIVE U+06A4: "ڤ" ARABIC LETTER VEH U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW - U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW - U+0665: "٥" ARABIC-INDIC DIGIT FIVE --> + U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW --> <!-- TODO: DroidSansArabic lacks the glyph of U+06A2 ARABIC LETTER FEH WITH DOT MOVED BELOW --> <!-- TODO: DroidSansArabic lacks the glyph of U+06A5 ARABIC LETTER FEH WITH THREE DOTS BELOW --> <Key - latin:keyLabel="ف" + latin:keySpec="ف" latin:keyHintLabel="5" latin:additionalMoreKeys="5,٥" latin:moreKeys="ڤ,ڢ,ڥ" @@ -68,23 +68,23 @@ <!-- U+063A: "غ" ARABIC LETTER GHAIN U+0666: "٦" ARABIC-INDIC DIGIT SIX --> <Key - latin:keyLabel="غ" + latin:keySpec="غ" latin:keyHintLabel="6" latin:additionalMoreKeys="6,٦" latin:keyLabelFlags="fontNormal" /> <!-- U+0639: "ع" ARABIC LETTER AIN U+0667: "٧" ARABIC-INDIC DIGIT SEVEN --> <Key - latin:keyLabel="ع" + latin:keySpec="ع" latin:keyHintLabel="7" latin:additionalMoreKeys="7,٧" latin:keyLabelFlags="fontNormal" /> <!-- U+0647: "ه" ARABIC LETTER HEH + U+0668: "٨" ARABIC-INDIC DIGIT EIGHT U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM - U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER - U+0668: "٨" ARABIC-INDIC DIGIT EIGHT --> + U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER --> <Key - latin:keyLabel="ه" + latin:keySpec="ه" latin:keyHintLabel="8" latin:additionalMoreKeys="8,٨" latin:moreKeys="ﻫ|ه‍" @@ -92,21 +92,21 @@ <!-- U+062E: "خ" ARABIC LETTER KHAH U+0669: "٩" ARABIC-INDIC DIGIT NINE --> <Key - latin:keyLabel="خ" + latin:keySpec="خ" latin:keyHintLabel="9" latin:additionalMoreKeys="9,٩" latin:keyLabelFlags="fontNormal" /> <!-- U+062D: "ح" ARABIC LETTER HAH U+0660: "٠" ARABIC-INDIC DIGIT ZERO --> <Key - latin:keyLabel="ح" + latin:keySpec="ح" latin:keyHintLabel="0" latin:additionalMoreKeys="0,٠" latin:keyLabelFlags="fontNormal" /> <!-- U+062C: "ج" ARABIC LETTER JEEM U+0686: "چ" ARABIC LETTER TCHEH --> <Key - latin:keyLabel="ج" + latin:keySpec="ج" latin:moreKeys="چ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_arabic2.xml b/java/res/xml/rowkeys_arabic2.xml index 4f8090d01..9bc91e8c7 100644 --- a/java/res/xml/rowkeys_arabic2.xml +++ b/java/res/xml/rowkeys_arabic2.xml @@ -25,24 +25,24 @@ U+069C: "ڜ" ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE --> <!-- TODO: DroidSansArabic lacks the glyph of U+069C ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE --> <Key - latin:keyLabel="ش" + latin:keySpec="ش" latin:moreKeys="ڜ" latin:keyLabelFlags="fontNormal" /> <!-- U+0633: "س" ARABIC LETTER SEEN --> <Key - latin:keyLabel="س" + latin:keySpec="س" latin:keyLabelFlags="fontNormal" /> <!-- U+064A: "ي" ARABIC LETTER YEH U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE U+0649: "ى" ARABIC LETTER ALEF MAKSURA --> <Key - latin:keyLabel="ي" + latin:keySpec="ي" latin:moreKeys="ئ,ى" latin:keyLabelFlags="fontNormal" /> <!-- U+0628: "ب" ARABIC LETTER BEH U+067E: "پ" ARABIC LETTER PEH --> <Key - latin:keyLabel="ب" + latin:keySpec="ب" latin:moreKeys="پ" latin:keyLabelFlags="fontNormal" /> <!-- U+0644: "ل" ARABIC LETTER LAM @@ -55,7 +55,7 @@ U+FEF5: "ﻵ" ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE --> <Key - latin:keyLabel="ل" + latin:keySpec="ل" latin:moreKeys="ﻻ|لا,ﻷ|لأ,ﻹ|لإ,ﻵ|لآ" latin:keyLabelFlags="fontNormal" /> <!-- U+0627: "ا" ARABIC LETTER ALEF @@ -65,30 +65,30 @@ U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW U+0671: "ٱ" ARABIC LETTER ALEF WASLA --> <Key - latin:keyLabel="ا" + latin:keySpec="ا" latin:moreKeys="!fixedColumnOrder!5,آ,ء,أ,إ,ٱ" latin:keyLabelFlags="fontNormal" /> <!-- U+062A: "ت" ARABIC LETTER TEH --> <Key - latin:keyLabel="ت" + latin:keySpec="ت" latin:keyLabelFlags="fontNormal" /> <!-- U+0646: "ن" ARABIC LETTER NOON --> <Key - latin:keyLabel="ن" + latin:keySpec="ن" latin:keyLabelFlags="fontNormal" /> <!-- U+0645: "م" ARABIC LETTER MEEM --> <Key - latin:keyLabel="م" + latin:keySpec="م" latin:keyLabelFlags="fontNormal" /> <!-- U+0643: "ك" ARABIC LETTER KAF U+06AF: "گ" ARABIC LETTER GAF U+06A9: "ک" ARABIC LETTER KEHEH --> <Key - latin:keyLabel="ك" + latin:keySpec="ك" latin:moreKeys="گ,ک" latin:keyLabelFlags="fontNormal" /> <!-- U+0637: "ط" ARABIC LETTER TAH --> <Key - latin:keyLabel="ط" + latin:keySpec="ط" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_arabic3.xml b/java/res/xml/rowkeys_arabic3.xml index 8a17b4b98..0bfc66a7d 100644 --- a/java/res/xml/rowkeys_arabic3.xml +++ b/java/res/xml/rowkeys_arabic3.xml @@ -25,42 +25,42 @@ latin:keyboardLayout="@xml/keys_arabic3_left" /> <!-- U+0621: "ء" ARABIC LETTER HAMZA --> <Key - latin:keyLabel="ء" + latin:keySpec="ء" latin:keyLabelFlags="fontNormal" /> <!-- U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE --> <Key - latin:keyLabel="ؤ" + latin:keySpec="ؤ" latin:keyLabelFlags="fontNormal" /> <!-- U+0631: "ر" ARABIC LETTER REH --> <Key - latin:keyLabel="ر" + latin:keySpec="ر" latin:keyLabelFlags="fontNormal" /> <!-- U+0649: "ى" ARABIC LETTER ALEF MAKSURA U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE --> <Key - latin:keyLabel="ى" + latin:keySpec="ى" latin:moreKeys="ئ" latin:keyLabelFlags="fontNormal" /> <!-- U+0629: "ة" ARABIC LETTER TEH MARBUTA --> <Key - latin:keyLabel="ة" + latin:keySpec="ة" latin:keyLabelFlags="fontNormal" /> <!-- U+0648: "و" ARABIC LETTER WAW --> <Key - latin:keyLabel="و" + latin:keySpec="و" latin:keyLabelFlags="fontNormal" /> <!-- U+0632: "ز" ARABIC LETTER ZAIN U+0698: "ژ" ARABIC LETTER JEH --> <Key - latin:keyLabel="ز" + latin:keySpec="ز" latin:moreKeys="ژ" latin:keyLabelFlags="fontNormal" /> <!-- U+0638: "ظ" ARABIC LETTER ZAH --> <Key - latin:keyLabel="ظ" + latin:keySpec="ظ" latin:keyLabelFlags="fontNormal" /> <!-- U+062F: "د" ARABIC LETTER DAL --> <Key - latin:keyLabel="د" + latin:keySpec="د" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_armenian_phonetic1.xml b/java/res/xml/rowkeys_armenian_phonetic1.xml index 1984fae8a..8ca78dab4 100644 --- a/java/res/xml/rowkeys_armenian_phonetic1.xml +++ b/java/res/xml/rowkeys_armenian_phonetic1.xml @@ -23,61 +23,61 @@ > <!-- U+0567: "է" ARMENIAN SMALL LETTER EH --> <Key - latin:keyLabel="է" + latin:keySpec="է" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:keyLabelFlags="fontNormal" /> <!-- U+0569: "թ" ARMENIAN SMALL LETTER TO --> <Key - latin:keyLabel="թ" + latin:keySpec="թ" latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:keyLabelFlags="fontNormal" /> <!-- U+0583: "փ" ARMENIAN SMALL LETTER PIWR --> <Key - latin:keyLabel="փ" + latin:keySpec="փ" latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:keyLabelFlags="fontNormal" /> <!-- U+0571: "ձ" ARMENIAN SMALL LETTER JA --> <Key - latin:keyLabel="ձ" + latin:keySpec="ձ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" latin:keyLabelFlags="fontNormal" /> <!-- U+057B: "ջ" ARMENIAN SMALL LETTER JHEH --> <Key - latin:keyLabel="ջ" + latin:keySpec="ջ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" latin:keyLabelFlags="fontNormal" /> <!-- U+0580: "ր" ARMENIAN SMALL LETTER REH --> <Key - latin:keyLabel="ր" + latin:keySpec="ր" latin:keyHintLabel="6" latin:additionalMoreKeys="6" latin:keyLabelFlags="fontNormal" /> <!-- U+0579: "չ" ARMENIAN SMALL LETTER CHA --> <Key - latin:keyLabel="չ" + latin:keySpec="չ" latin:keyHintLabel="7" latin:additionalMoreKeys="7" latin:keyLabelFlags="fontNormal" /> <!-- U+0573: "ճ" ARMENIAN SMALL LETTER CHEH --> <Key - latin:keyLabel="ճ" + latin:keySpec="ճ" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:keyLabelFlags="fontNormal" /> <!-- U+056A: "ժ" ARMENIAN SMALL LETTER ZHE --> <Key - latin:keyLabel="ժ" + latin:keySpec="ժ" latin:keyHintLabel="9" latin:additionalMoreKeys="9" latin:keyLabelFlags="fontNormal" /> <!-- U+056E: "ծ" ARMENIAN SMALL LETTER CA --> <Key - latin:keyLabel="ծ" + latin:keySpec="ծ" latin:keyHintLabel="0" latin:additionalMoreKeys="0" latin:keyLabelFlags="fontNormal" /> diff --git a/java/res/xml/rowkeys_armenian_phonetic2.xml b/java/res/xml/rowkeys_armenian_phonetic2.xml index 5dcabc301..9991f739d 100644 --- a/java/res/xml/rowkeys_armenian_phonetic2.xml +++ b/java/res/xml/rowkeys_armenian_phonetic2.xml @@ -23,44 +23,45 @@ > <!-- U+0584: "ք" ARMENIAN SMALL LETTER KEH --> <Key - latin:keyLabel="ք" + latin:keySpec="ք" latin:keyLabelFlags="fontNormal" /> <!-- U+0578: "ո" ARMENIAN SMALL LETTER VO --> <Key - latin:keyLabel="ո" + latin:keySpec="ո" latin:keyLabelFlags="fontNormal" /> <!-- U+0565: "ե" ARMENIAN SMALL LETTER ECH U+0587: "և" ARMENIAN SMALL LIGATURE ECH YIWN --> <Key - latin:keyLabel="ե" + latin:keySpec="ե" latin:moreKeys="և" + latin:keyHintLabel="և" latin:keyLabelFlags="fontNormal" /> <!-- U+057C: "ռ" ARMENIAN SMALL LETTER RA --> <Key - latin:keyLabel="ռ" + latin:keySpec="ռ" latin:keyLabelFlags="fontNormal" /> <!-- U+057F: "տ" ARMENIAN SMALL LETTER TIWN --> <Key - latin:keyLabel="տ" + latin:keySpec="տ" latin:keyLabelFlags="fontNormal" /> <!-- U+0568: "ը" ARMENIAN SMALL LETTER ET --> <Key - latin:keyLabel="ը" + latin:keySpec="ը" latin:keyLabelFlags="fontNormal" /> <!-- U+0582: "ւ" ARMENIAN SMALL LETTER YIWN --> <Key - latin:keyLabel="ւ" + latin:keySpec="ւ" latin:keyLabelFlags="fontNormal" /> <!-- U+056B: "ի" ARMENIAN SMALL LETTER INI --> <Key - latin:keyLabel="ի" + latin:keySpec="ի" latin:keyLabelFlags="fontNormal" /> <!-- U+0585: "օ" ARMENIAN SMALL LETTER OH --> <Key - latin:keyLabel="օ" + latin:keySpec="օ" latin:keyLabelFlags="fontNormal" /> <!-- U+057A: "պ" ARMENIAN SMALL LETTER PEH --> <Key - latin:keyLabel="պ" + latin:keySpec="պ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_armenian_phonetic3.xml b/java/res/xml/rowkeys_armenian_phonetic3.xml index 3116811b3..2b79386ac 100644 --- a/java/res/xml/rowkeys_armenian_phonetic3.xml +++ b/java/res/xml/rowkeys_armenian_phonetic3.xml @@ -23,38 +23,38 @@ > <!-- U+0561: "ա" ARMENIAN SMALL LETTER AYB --> <Key - latin:keyLabel="ա" + latin:keySpec="ա" latin:keyLabelFlags="fontNormal" /> <!-- U+057D: "ս" ARMENIAN SMALL LETTER SEH --> <Key - latin:keyLabel="ս" + latin:keySpec="ս" latin:keyLabelFlags="fontNormal" /> <!-- U+0564: "դ" ARMENIAN SMALL LETTER DA --> <Key - latin:keyLabel="դ" + latin:keySpec="դ" latin:keyLabelFlags="fontNormal" /> <!-- U+0586: "ֆ" ARMENIAN SMALL LETTER FEH --> <Key - latin:keyLabel="ֆ" + latin:keySpec="ֆ" latin:keyLabelFlags="fontNormal" /> <!-- U+0563: "գ" ARMENIAN SMALL LETTER GIM --> <Key - latin:keyLabel="գ" + latin:keySpec="գ" latin:keyLabelFlags="fontNormal" /> <!-- U+0570: "հ" ARMENIAN SMALL LETTER HO --> <Key - latin:keyLabel="հ" + latin:keySpec="հ" latin:keyLabelFlags="fontNormal" /> <!-- U+0575: "յ" ARMENIAN SMALL LETTER YI --> <Key - latin:keyLabel="յ" + latin:keySpec="յ" latin:keyLabelFlags="fontNormal" /> <!-- U+056F: "կ" ARMENIAN SMALL LETTER KEN --> <Key - latin:keyLabel="կ" + latin:keySpec="կ" latin:keyLabelFlags="fontNormal" /> <!-- U+056C: "լ" ARMENIAN SMALL LETTER LIWN --> <Key - latin:keyLabel="լ" + latin:keySpec="լ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_armenian_phonetic4.xml b/java/res/xml/rowkeys_armenian_phonetic4.xml index 922481add..f8cdd1221 100644 --- a/java/res/xml/rowkeys_armenian_phonetic4.xml +++ b/java/res/xml/rowkeys_armenian_phonetic4.xml @@ -23,30 +23,30 @@ > <!-- U+0566: "զ" ARMENIAN SMALL LETTER ZA --> <Key - latin:keyLabel="զ" + latin:keySpec="զ" latin:keyLabelFlags="fontNormal" /> <!-- U+0572: "ղ" ARMENIAN SMALL LETTER GHAD --> <Key - latin:keyLabel="ղ" + latin:keySpec="ղ" latin:keyLabelFlags="fontNormal" /> <!-- U+0581: "ց" ARMENIAN SMALL LETTER CO --> <Key - latin:keyLabel="ց" + latin:keySpec="ց" latin:keyLabelFlags="fontNormal" /> <!-- U+057E: "վ" ARMENIAN SMALL LETTER VEW --> <Key - latin:keyLabel="վ" + latin:keySpec="վ" latin:keyLabelFlags="fontNormal" /> <!-- U+0562: "բ" ARMENIAN SMALL LETTER BEN --> <Key - latin:keyLabel="բ" + latin:keySpec="բ" latin:keyLabelFlags="fontNormal" /> <!-- U+0576: "ն" ARMENIAN SMALL LETTER NOW --> <Key - latin:keyLabel="ն" + latin:keySpec="ն" latin:keyLabelFlags="fontNormal" /> <!-- U+0574: "մ" ARMENIAN SMALL LETTER MEN --> <Key - latin:keyLabel="մ" + latin:keySpec="մ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_azerty1.xml b/java/res/xml/rowkeys_azerty1.xml index 42b27463f..67be342c0 100644 --- a/java/res/xml/rowkeys_azerty1.xml +++ b/java/res/xml/rowkeys_azerty1.xml @@ -22,52 +22,52 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="a" + latin:keySpec="a" latin:keyHintLabel="1" latin:additionalMoreKeys="1" - latin:moreKeys="!text/more_keys_for_a" /> + latin:moreKeys="!text/morekeys_a" /> <Key - latin:keyLabel="z" + latin:keySpec="z" latin:keyHintLabel="2" latin:additionalMoreKeys="2" - latin:moreKeys="!text/more_keys_for_z" /> + latin:moreKeys="!text/morekeys_z" /> <Key - latin:keyLabel="e" + latin:keySpec="e" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_e" /> + latin:moreKeys="!text/morekeys_e" /> <Key - latin:keyLabel="r" + latin:keySpec="r" latin:keyHintLabel="4" latin:additionalMoreKeys="4" - latin:moreKeys="!text/more_keys_for_r" /> + latin:moreKeys="!text/morekeys_r" /> <Key - latin:keyLabel="t" + latin:keySpec="t" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_t" /> + latin:moreKeys="!text/morekeys_t" /> <Key - latin:keyLabel="y" + latin:keySpec="y" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_y" /> + latin:moreKeys="!text/morekeys_y" /> <Key - latin:keyLabel="u" + latin:keySpec="u" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_u" /> + latin:moreKeys="!text/morekeys_u" /> <Key - latin:keyLabel="i" + latin:keySpec="i" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_i" /> + latin:moreKeys="!text/morekeys_i" /> <Key - latin:keyLabel="o" + latin:keySpec="o" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="!text/more_keys_for_o" /> + latin:moreKeys="!text/morekeys_o" /> <Key - latin:keyLabel="p" + latin:keySpec="p" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </merge> diff --git a/java/res/xml/rowkeys_azerty2.xml b/java/res/xml/rowkeys_azerty2.xml index 2eee214e5..116417f08 100644 --- a/java/res/xml/rowkeys_azerty2.xml +++ b/java/res/xml/rowkeys_azerty2.xml @@ -22,30 +22,30 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="q" /> + latin:keySpec="q" /> <Key - latin:keyLabel="s" - latin:moreKeys="!text/more_keys_for_s" /> + latin:keySpec="s" + latin:moreKeys="!text/morekeys_s" /> <Key - latin:keyLabel="d" - latin:moreKeys="!text/more_keys_for_d" /> + latin:keySpec="d" + latin:moreKeys="!text/morekeys_d" /> <Key - latin:keyLabel="f" /> + latin:keySpec="f" /> <Key - latin:keyLabel="g" - latin:moreKeys="!text/more_keys_for_g" /> + latin:keySpec="g" + latin:moreKeys="!text/morekeys_g" /> <Key - latin:keyLabel="h" - latin:moreKeys="!text/more_keys_for_h" /> + latin:keySpec="h" + latin:moreKeys="!text/morekeys_h" /> <Key - latin:keyLabel="j" - latin:moreKeys="!text/more_keys_for_j" /> + latin:keySpec="j" + latin:moreKeys="!text/morekeys_j" /> <Key - latin:keyLabel="k" - latin:moreKeys="!text/more_keys_for_k" /> + latin:keySpec="k" + latin:moreKeys="!text/morekeys_k" /> <Key - latin:keyLabel="l" - latin:moreKeys="!text/more_keys_for_l" /> + latin:keySpec="l" + latin:moreKeys="!text/morekeys_l" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> </merge> diff --git a/java/res/xml/rowkeys_azerty3.xml b/java/res/xml/rowkeys_azerty3.xml index 2643f3283..48d3a5280 100644 --- a/java/res/xml/rowkeys_azerty3.xml +++ b/java/res/xml/rowkeys_azerty3.xml @@ -22,21 +22,32 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="w" - latin:moreKeys="!text/more_keys_for_w" /> + latin:keySpec="w" + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="x" /> + latin:keySpec="x" /> <Key - latin:keyLabel="c" - latin:moreKeys="!text/more_keys_for_c" /> + latin:keySpec="c" + latin:moreKeys="!text/morekeys_c" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="n" - latin:moreKeys="!text/more_keys_for_n" /> - <include - latin:keyboardLayout="@xml/key_azerty3_right" /> + latin:keySpec="n" + latin:moreKeys="!text/morekeys_n" /> + <switch> + <case + latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <Key + latin:keySpec="\?" /> + </case> + <default> + <Key + latin:keySpec="\'" + latin:moreKeys="!text/morekeys_single_quote" /> + </default> + </switch> </merge> diff --git a/java/res/xml/rowkeys_bulgarian1.xml b/java/res/xml/rowkeys_bulgarian1.xml index 441b079f1..e84719302 100644 --- a/java/res/xml/rowkeys_bulgarian1.xml +++ b/java/res/xml/rowkeys_bulgarian1.xml @@ -23,57 +23,57 @@ > <!-- U+044F: "я" CYRILLIC SMALL LETTER YA --> <Key - latin:keyLabel="я" + latin:keySpec="я" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+0432: "в" CYRILLIC SMALL LETTER VE --> <Key - latin:keyLabel="в" + latin:keySpec="в" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+0435: "е" CYRILLIC SMALL LETTER IE --> <Key - latin:keyLabel="е" + latin:keySpec="е" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> <!-- U+0440: "р" CYRILLIC SMALL LETTER ER --> <Key - latin:keyLabel="р" + latin:keySpec="р" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+0442: "т" CYRILLIC SMALL LETTER TE --> <Key - latin:keyLabel="т" + latin:keySpec="т" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <Key - latin:keyLabel="ъ" + latin:keySpec="ъ" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <!-- U+0443: "у" CYRILLIC SMALL LETTER U --> <Key - latin:keyLabel="у" + latin:keySpec="у" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+0438: "и" CYRILLIC SMALL LETTER I U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE --> <Key - latin:keyLabel="и" + latin:keySpec="и" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:moreKeys="ѝ" /> <!-- U+043E: "о" CYRILLIC SMALL LETTER O --> <Key - latin:keyLabel="о" + latin:keySpec="о" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+043F: "п" CYRILLIC SMALL LETTER PE --> <Key - latin:keyLabel="п" + latin:keySpec="п" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE --> <Key - latin:keyLabel="ч" /> + latin:keySpec="ч" /> </merge> diff --git a/java/res/xml/rowkeys_bulgarian2.xml b/java/res/xml/rowkeys_bulgarian2.xml index a4e93d862..e572a221d 100644 --- a/java/res/xml/rowkeys_bulgarian2.xml +++ b/java/res/xml/rowkeys_bulgarian2.xml @@ -23,35 +23,35 @@ > <!-- U+0430: "а" CYRILLIC SMALL LETTER A --> <Key - latin:keyLabel="а" /> + latin:keySpec="а" /> <!-- U+0441: "с" CYRILLIC SMALL LETTER ES --> <Key - latin:keyLabel="с" /> + latin:keySpec="с" /> <!-- U+0434: "д" CYRILLIC SMALL LETTER DE --> <Key - latin:keyLabel="д" /> + latin:keySpec="д" /> <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF --> <Key - latin:keyLabel="ф" /> + latin:keySpec="ф" /> <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE --> <Key - latin:keyLabel="г" /> + latin:keySpec="г" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" /> + latin:keySpec="х" /> <!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I --> <Key - latin:keyLabel="й" /> + latin:keySpec="й" /> <!-- U+043A: "к" CYRILLIC SMALL LETTER KA --> <Key - latin:keyLabel="к" /> + latin:keySpec="к" /> <!-- U+043B: "л" CYRILLIC SMALL LETTER EL --> <Key - latin:keyLabel="л" /> + latin:keySpec="л" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA --> <Key - latin:keyLabel="ш" /> + latin:keySpec="ш" /> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <Key - latin:keyLabel="щ" /> + latin:keySpec="щ" /> </merge> diff --git a/java/res/xml/rowkeys_bulgarian3.xml b/java/res/xml/rowkeys_bulgarian3.xml index 258219c27..2509793b2 100644 --- a/java/res/xml/rowkeys_bulgarian3.xml +++ b/java/res/xml/rowkeys_bulgarian3.xml @@ -23,26 +23,26 @@ > <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> <Key - latin:keyLabel="з" /> + latin:keySpec="з" /> <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN --> <Key - latin:keyLabel="ь" /> + latin:keySpec="ь" /> <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE --> <Key - latin:keyLabel="ц" /> + latin:keySpec="ц" /> <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key - latin:keyLabel="ж" /> + latin:keySpec="ж" /> <!-- U+0431: "б" CYRILLIC SMALL LETTER BE --> <Key - latin:keyLabel="б" /> + latin:keySpec="б" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key - latin:keyLabel="н" /> + latin:keySpec="н" /> <!-- U+043C: "м" CYRILLIC SMALL LETTER EM --> <Key - latin:keyLabel="м" /> + latin:keySpec="м" /> <!-- U+044E: "ю" CYRILLIC SMALL LETTER YU --> <Key - latin:keyLabel="ю" /> + latin:keySpec="ю" /> </merge> diff --git a/java/res/xml/rowkeys_bulgarian_bds1.xml b/java/res/xml/rowkeys_bulgarian_bds1.xml index eed1fcb8f..9d6428268 100644 --- a/java/res/xml/rowkeys_bulgarian_bds1.xml +++ b/java/res/xml/rowkeys_bulgarian_bds1.xml @@ -23,57 +23,57 @@ > <!-- U+0443: "у" CYRILLIC SMALL LETTER U --> <Key - latin:keyLabel="у" + latin:keySpec="у" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+0435: "е" CYRILLIC SMALL LETTER IE --> <Key - latin:keyLabel="е" + latin:keySpec="е" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+0438: "и" CYRILLIC SMALL LETTER I U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE --> <Key - latin:keyLabel="и" + latin:keySpec="и" latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys="ѝ" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA --> <Key - latin:keyLabel="ш" + latin:keySpec="ш" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <Key - latin:keyLabel="щ" + latin:keySpec="щ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <!-- U+043A: "к" CYRILLIC SMALL LETTER KA --> <Key - latin:keyLabel="к" + latin:keySpec="к" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <!-- U+0441: "с" CYRILLIC SMALL LETTER ES --> <Key - latin:keyLabel="с" + latin:keySpec="с" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+0434: "д" CYRILLIC SMALL LETTER DE --> <Key - latin:keyLabel="д" + latin:keySpec="д" latin:keyHintLabel="8" latin:additionalMoreKeys="8" /> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> <Key - latin:keyLabel="з" + latin:keySpec="з" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE --> <Key - latin:keyLabel="ц" + latin:keySpec="ц" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> <!-- U+0431: "б" CYRILLIC SMALL LETTER BE --> <Key - latin:keyLabel="б" /> + latin:keySpec="б" /> </merge> diff --git a/java/res/xml/rowkeys_bulgarian_bds2.xml b/java/res/xml/rowkeys_bulgarian_bds2.xml index ff1bff895..e078ae7d3 100644 --- a/java/res/xml/rowkeys_bulgarian_bds2.xml +++ b/java/res/xml/rowkeys_bulgarian_bds2.xml @@ -23,35 +23,35 @@ > <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN --> <Key - latin:keyLabel="ь" /> + latin:keySpec="ь" /> <!-- U+044F: "я" CYRILLIC SMALL LETTER YA --> <Key - latin:keyLabel="я" /> + latin:keySpec="я" /> <!-- U+0430: "а" CYRILLIC SMALL LETTER A --> <Key - latin:keyLabel="а" /> + latin:keySpec="а" /> <!-- U+043E: "о" CYRILLIC SMALL LETTER O --> <Key - latin:keyLabel="о" /> + latin:keySpec="о" /> <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key - latin:keyLabel="ж" /> + latin:keySpec="ж" /> <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE --> <Key - latin:keyLabel="г" /> + latin:keySpec="г" /> <!-- U+0442: "т" CYRILLIC SMALL LETTER TE --> <Key - latin:keyLabel="т" /> + latin:keySpec="т" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key - latin:keyLabel="н" /> + latin:keySpec="н" /> <!-- U+0432: "в" CYRILLIC SMALL LETTER VE --> <Key - latin:keyLabel="в" /> + latin:keySpec="в" /> <!-- U+043C: "м" CYRILLIC SMALL LETTER EM --> <Key - latin:keyLabel="м" /> + latin:keySpec="м" /> <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE --> <Key - latin:keyLabel="ч" /> + latin:keySpec="ч" /> </merge> diff --git a/java/res/xml/rowkeys_bulgarian_bds3.xml b/java/res/xml/rowkeys_bulgarian_bds3.xml index 7bb780ac7..8302d6922 100644 --- a/java/res/xml/rowkeys_bulgarian_bds3.xml +++ b/java/res/xml/rowkeys_bulgarian_bds3.xml @@ -23,29 +23,29 @@ > <!-- U+044E: "ю" CYRILLIC SMALL LETTER YU --> <Key - latin:keyLabel="ю" /> + latin:keySpec="ю" /> <!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I --> <Key - latin:keyLabel="й" /> + latin:keySpec="й" /> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <Key - latin:keyLabel="ъ" /> + latin:keySpec="ъ" /> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> <Key - latin:keyLabel="э" /> + latin:keySpec="э" /> <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF --> <Key - latin:keyLabel="ф" /> + latin:keySpec="ф" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" /> + latin:keySpec="х" /> <!-- U+043F: "п" CYRILLIC SMALL LETTER PE --> <Key - latin:keyLabel="п" /> + latin:keySpec="п" /> <!-- U+0440: "р" CYRILLIC SMALL LETTER ER --> <Key - latin:keyLabel="р" /> + latin:keySpec="р" /> <!-- U+043B: "л" CYRILLIC SMALL LETTER EL --> <Key - latin:keyLabel="л" /> + latin:keySpec="л" /> </merge> diff --git a/java/res/xml/rowkeys_colemak1.xml b/java/res/xml/rowkeys_colemak1.xml index f1c30756b..199d285f9 100644 --- a/java/res/xml/rowkeys_colemak1.xml +++ b/java/res/xml/rowkeys_colemak1.xml @@ -22,45 +22,62 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="q" + latin:keySpec="q" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <Key - latin:keyLabel="w" + latin:keySpec="w" latin:keyHintLabel="2" latin:additionalMoreKeys="2" - latin:moreKeys="!text/more_keys_for_w" /> + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="f" + latin:keySpec="f" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> <Key - latin:keyLabel="p" + latin:keySpec="p" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <Key - latin:keyLabel="g" + latin:keySpec="g" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_g" /> + latin:moreKeys="!text/morekeys_g" /> <Key - latin:keyLabel="j" + latin:keySpec="j" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_j" /> + latin:moreKeys="!text/morekeys_j" /> <Key - latin:keyLabel="l" + latin:keySpec="l" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_l" /> + latin:moreKeys="!text/morekeys_l" /> <Key - latin:keyLabel="u" + latin:keySpec="u" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_u" /> + latin:moreKeys="!text/morekeys_u" /> <Key - latin:keyLabel="y" + latin:keySpec="y" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="!text/more_keys_for_y" /> + latin:moreKeys="!text/morekeys_y" /> + <switch> + <case + latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <Key + latin:keySpec=":" + latin:keyHintLabel="0" + latin:additionalMoreKeys="0" /> + </case> + <default> + <Key + latin:keySpec=";" + latin:keyHintLabel="0" + latin:additionalMoreKeys="0" + latin:moreKeys=":" /> + </default> + </switch> </merge> diff --git a/java/res/xml/rowkeys_colemak2.xml b/java/res/xml/rowkeys_colemak2.xml index f73d7e95f..a8e93bf0e 100644 --- a/java/res/xml/rowkeys_colemak2.xml +++ b/java/res/xml/rowkeys_colemak2.xml @@ -22,33 +22,33 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="a" - latin:moreKeys="!text/more_keys_for_a" /> + latin:keySpec="a" + latin:moreKeys="!text/morekeys_a" /> <Key - latin:keyLabel="r" - latin:moreKeys="!text/more_keys_for_r" /> + latin:keySpec="r" + latin:moreKeys="!text/morekeys_r" /> <Key - latin:keyLabel="s" - latin:moreKeys="!text/more_keys_for_s" /> + latin:keySpec="s" + latin:moreKeys="!text/morekeys_s" /> <Key - latin:keyLabel="t" - latin:moreKeys="!text/more_keys_for_t" /> + latin:keySpec="t" + latin:moreKeys="!text/morekeys_t" /> <Key - latin:keyLabel="d" - latin:moreKeys="!text/more_keys_for_d" /> + latin:keySpec="d" + latin:moreKeys="!text/morekeys_d" /> <Key - latin:keyLabel="h" - latin:moreKeys="!text/more_keys_for_h" /> + latin:keySpec="h" + latin:moreKeys="!text/morekeys_h" /> <Key - latin:keyLabel="n" - latin:moreKeys="!text/more_keys_for_n" /> + latin:keySpec="n" + latin:moreKeys="!text/morekeys_n" /> <Key - latin:keyLabel="e" - latin:moreKeys="!text/more_keys_for_e" /> + latin:keySpec="e" + latin:moreKeys="!text/morekeys_e" /> <Key - latin:keyLabel="i" - latin:moreKeys="!text/more_keys_for_i" /> + latin:keySpec="i" + latin:moreKeys="!text/morekeys_i" /> <Key - latin:keyLabel="o" - latin:moreKeys="!text/more_keys_for_o" /> + latin:keySpec="o" + latin:moreKeys="!text/morekeys_o" /> </merge> diff --git a/java/res/xml/rowkeys_colemak3.xml b/java/res/xml/rowkeys_colemak3.xml index f0f915142..df4d9936e 100644 --- a/java/res/xml/rowkeys_colemak3.xml +++ b/java/res/xml/rowkeys_colemak3.xml @@ -22,21 +22,21 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="z" - latin:moreKeys="!text/more_keys_for_z" /> + latin:keySpec="z" + latin:moreKeys="!text/morekeys_z" /> <Key - latin:keyLabel="x" /> + latin:keySpec="x" /> <Key - latin:keyLabel="c" - latin:moreKeys="!text/more_keys_for_c" /> + latin:keySpec="c" + latin:moreKeys="!text/morekeys_c" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="k" - latin:moreKeys="!text/more_keys_for_k" /> + latin:keySpec="k" + latin:moreKeys="!text/morekeys_k" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> </merge> diff --git a/java/res/xml/rowkeys_dvorak1.xml b/java/res/xml/rowkeys_dvorak1.xml index 033308acb..170e31664 100644 --- a/java/res/xml/rowkeys_dvorak1.xml +++ b/java/res/xml/rowkeys_dvorak1.xml @@ -24,36 +24,36 @@ <include latin:keyboardLayout="@xml/keys_dvorak_123" /> <Key - latin:keyLabel="p" + latin:keySpec="p" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <Key - latin:keyLabel="y" + latin:keySpec="y" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_y" /> + latin:moreKeys="!text/morekeys_y" /> <Key - latin:keyLabel="f" + latin:keySpec="f" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <Key - latin:keyLabel="g" + latin:keySpec="g" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_g" /> + latin:moreKeys="!text/morekeys_g" /> <Key - latin:keyLabel="c" + latin:keySpec="c" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_c" /> + latin:moreKeys="!text/morekeys_c" /> <Key - latin:keyLabel="r" + latin:keySpec="r" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="!text/more_keys_for_r" /> + latin:moreKeys="!text/morekeys_r" /> <Key - latin:keyLabel="l" + latin:keySpec="l" latin:keyHintLabel="0" latin:additionalMoreKeys="0" - latin:moreKeys="!text/more_keys_for_l" /> + latin:moreKeys="!text/morekeys_l" /> </merge> diff --git a/java/res/xml/rowkeys_dvorak2.xml b/java/res/xml/rowkeys_dvorak2.xml index 943e3f549..0840a6cfc 100644 --- a/java/res/xml/rowkeys_dvorak2.xml +++ b/java/res/xml/rowkeys_dvorak2.xml @@ -22,33 +22,33 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="a" - latin:moreKeys="!text/more_keys_for_a" /> + latin:keySpec="a" + latin:moreKeys="!text/morekeys_a" /> <Key - latin:keyLabel="o" - latin:moreKeys="!text/more_keys_for_o" /> + latin:keySpec="o" + latin:moreKeys="!text/morekeys_o" /> <Key - latin:keyLabel="e" - latin:moreKeys="!text/more_keys_for_e" /> + latin:keySpec="e" + latin:moreKeys="!text/morekeys_e" /> <Key - latin:keyLabel="u" - latin:moreKeys="!text/more_keys_for_u" /> + latin:keySpec="u" + latin:moreKeys="!text/morekeys_u" /> <Key - latin:keyLabel="i" - latin:moreKeys="!text/more_keys_for_i" /> + latin:keySpec="i" + latin:moreKeys="!text/morekeys_i" /> <Key - latin:keyLabel="d" - latin:moreKeys="!text/more_keys_for_d" /> + latin:keySpec="d" + latin:moreKeys="!text/morekeys_d" /> <Key - latin:keyLabel="h" - latin:moreKeys="!text/more_keys_for_h" /> + latin:keySpec="h" + latin:moreKeys="!text/morekeys_h" /> <Key - latin:keyLabel="t" - latin:moreKeys="!text/more_keys_for_t" /> + latin:keySpec="t" + latin:moreKeys="!text/morekeys_t" /> <Key - latin:keyLabel="n" - latin:moreKeys="!text/more_keys_for_n" /> + latin:keySpec="n" + latin:moreKeys="!text/morekeys_n" /> <Key - latin:keyLabel="s" - latin:moreKeys="!text/more_keys_for_s" /> + latin:keySpec="s" + latin:moreKeys="!text/morekeys_s" /> </merge> diff --git a/java/res/xml/rowkeys_dvorak3.xml b/java/res/xml/rowkeys_dvorak3.xml index b035f41cd..e53908c91 100644 --- a/java/res/xml/rowkeys_dvorak3.xml +++ b/java/res/xml/rowkeys_dvorak3.xml @@ -22,21 +22,21 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="j" - latin:moreKeys="!text/more_keys_for_j" /> + latin:keySpec="j" + latin:moreKeys="!text/morekeys_j" /> <Key - latin:keyLabel="k" - latin:moreKeys="!text/more_keys_for_k" /> + latin:keySpec="k" + latin:moreKeys="!text/morekeys_k" /> <Key - latin:keyLabel="x" /> + latin:keySpec="x" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> <Key - latin:keyLabel="w" - latin:moreKeys="!text/more_keys_for_w" /> + latin:keySpec="w" + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> </merge> diff --git a/java/res/xml/rowkeys_east_slavic1.xml b/java/res/xml/rowkeys_east_slavic1.xml index 5b3b4b48d..88d95fffb 100644 --- a/java/res/xml/rowkeys_east_slavic1.xml +++ b/java/res/xml/rowkeys_east_slavic1.xml @@ -23,59 +23,59 @@ > <!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I --> <Key - latin:keyLabel="й" + latin:keySpec="й" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE --> <Key - latin:keyLabel="ц" + latin:keySpec="ц" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+0443: "у" CYRILLIC SMALL LETTER U --> <Key - latin:keyLabel="у" + latin:keySpec="у" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_cyrillic_u" /> + latin:moreKeys="!text/morekeys_cyrillic_u" /> <!-- U+043A: "к" CYRILLIC SMALL LETTER KA --> <Key - latin:keyLabel="к" + latin:keySpec="к" latin:keyHintLabel="4" latin:additionalMoreKeys="4" - latin:moreKeys="!text/more_keys_for_cyrillic_ka" /> + latin:moreKeys="!text/morekeys_cyrillic_ka" /> <!-- U+0435: "е" CYRILLIC SMALL LETTER IE --> <Key - latin:keyLabel="е" + latin:keySpec="е" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_cyrillic_ie" /> + latin:moreKeys="!text/morekeys_cyrillic_ie" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key - latin:keyLabel="н" + latin:keySpec="н" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_cyrillic_en" /> + latin:moreKeys="!text/morekeys_cyrillic_en" /> <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE --> <Key - latin:keyLabel="г" + latin:keySpec="г" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_cyrillic_ghe" /> + latin:moreKeys="!text/morekeys_cyrillic_ghe" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA --> <Key - latin:keyLabel="ш" + latin:keySpec="ш" latin:keyHintLabel="8" latin:additionalMoreKeys="8" /> <Key - latin:keyLabel="!text/keylabel_for_east_slavic_row1_9" + latin:keySpec="!text/keyspec_east_slavic_row1_9" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> <Key - latin:keyLabel="з" + latin:keySpec="з" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" /> + latin:keySpec="х" /> </merge> diff --git a/java/res/xml/rowkeys_east_slavic2.xml b/java/res/xml/rowkeys_east_slavic2.xml index 2e412f08c..21463fb7d 100644 --- a/java/res/xml/rowkeys_east_slavic2.xml +++ b/java/res/xml/rowkeys_east_slavic2.xml @@ -23,37 +23,37 @@ > <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF --> <Key - latin:keyLabel="ф" /> + latin:keySpec="ф" /> <Key - latin:keyLabel="!text/keylabel_for_east_slavic_row2_1" - latin:moreKeys="!text/more_keys_for_east_slavic_row2_1" /> + latin:keySpec="!text/keyspec_east_slavic_row2_2" + latin:moreKeys="!text/morekeys_east_slavic_row2_2" /> <!-- U+0432: "в" CYRILLIC SMALL LETTER VE --> <Key - latin:keyLabel="в" /> + latin:keySpec="в" /> <!-- U+0430: "а" CYRILLIC SMALL LETTER A --> <Key - latin:keyLabel="а" - latin:moreKeys="!text/more_keys_for_cyrillic_a" /> + latin:keySpec="а" + latin:moreKeys="!text/morekeys_cyrillic_a" /> <!-- U+043F: "п" CYRILLIC SMALL LETTER PE --> <Key - latin:keyLabel="п" /> + latin:keySpec="п" /> <!-- U+0440: "р" CYRILLIC SMALL LETTER ER --> <Key - latin:keyLabel="р" /> + latin:keySpec="р" /> <!-- U+043E: "о" CYRILLIC SMALL LETTER O --> <Key - latin:keyLabel="о" - latin:moreKeys="!text/more_keys_for_cyrillic_o" /> + latin:keySpec="о" + latin:moreKeys="!text/morekeys_cyrillic_o" /> <!-- U+043B: "л" CYRILLIC SMALL LETTER EL --> <Key - latin:keyLabel="л" /> + latin:keySpec="л" /> <!-- U+0434: "д" CYRILLIC SMALL LETTER DE --> <Key - latin:keyLabel="д" /> + latin:keySpec="д" /> <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key - latin:keyLabel="ж" /> + latin:keySpec="ж" /> <Key - latin:keyLabel="!text/keylabel_for_east_slavic_row2_11" - latin:moreKeys="!text/more_keys_for_east_slavic_row2_11" /> + latin:keySpec="!text/keyspec_east_slavic_row2_11" + latin:moreKeys="!text/morekeys_east_slavic_row2_11" /> </merge> diff --git a/java/res/xml/rowkeys_east_slavic3.xml b/java/res/xml/rowkeys_east_slavic3.xml index c3a171b49..54802e878 100644 --- a/java/res/xml/rowkeys_east_slavic3.xml +++ b/java/res/xml/rowkeys_east_slavic3.xml @@ -23,29 +23,29 @@ > <!-- U+044F: "я" CYRILLIC SMALL LETTER YA --> <Key - latin:keyLabel="я" /> + latin:keySpec="я" /> <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE --> <Key - latin:keyLabel="ч" /> + latin:keySpec="ч" /> <!-- U+0441: "с" CYRILLIC SMALL LETTER ES --> <Key - latin:keyLabel="с" /> + latin:keySpec="с" /> <!-- U+043C: "м" CYRILLIC SMALL LETTER EM --> <Key - latin:keyLabel="м" /> + latin:keySpec="м" /> <Key - latin:keyLabel="!text/keylabel_for_east_slavic_row3_5" /> + latin:keySpec="!text/keyspec_east_slavic_row3_5" /> <!-- U+0442: "т" CYRILLIC SMALL LETTER TE --> <Key - latin:keyLabel="т" /> + latin:keySpec="т" /> <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN --> <Key - latin:keyLabel="ь" - latin:moreKeys="!text/more_keys_for_cyrillic_soft_sign" /> + latin:keySpec="ь" + latin:moreKeys="!text/morekeys_cyrillic_soft_sign" /> <!-- U+0431: "б" CYRILLIC SMALL LETTER BE --> <Key - latin:keyLabel="б" /> + latin:keySpec="б" /> <!-- U+044E: "ю" CYRILLIC SMALL LETTER YU --> <Key - latin:keyLabel="ю" /> + latin:keySpec="ю" /> </merge> diff --git a/java/res/xml/rowkeys_farsi1.xml b/java/res/xml/rowkeys_farsi1.xml index 5a22a2462..46fef4236 100644 --- a/java/res/xml/rowkeys_farsi1.xml +++ b/java/res/xml/rowkeys_farsi1.xml @@ -24,49 +24,49 @@ <!-- U+0636: "ض" ARABIC LETTER DAD U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE --> <Key - latin:keyLabel="ض" + latin:keySpec="ض" latin:keyHintLabel="۱" latin:additionalMoreKeys="۱,1" latin:keyLabelFlags="fontNormal" /> <!-- U+0635: "ص" ARABIC LETTER SAD U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO --> <Key - latin:keyLabel="ص" + latin:keySpec="ص" latin:keyHintLabel="۲" latin:additionalMoreKeys="۲,2" latin:keyLabelFlags="fontNormal" /> <!-- U+062B: "ث" ARABIC LETTER THEH U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE --> <Key - latin:keyLabel="ث" + latin:keySpec="ث" latin:keyHintLabel="۳" latin:additionalMoreKeys="۳,3" latin:keyLabelFlags="fontNormal" /> <!-- U+0642: "ق" ARABIC LETTER QAF U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR --> <Key - latin:keyLabel="ق" + latin:keySpec="ق" latin:keyHintLabel="۴" latin:additionalMoreKeys="۴,4" latin:keyLabelFlags="fontNormal" /> <!-- U+0641: "ف" ARABIC LETTER FEH U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE --> <Key - latin:keyLabel="ف" + latin:keySpec="ف" latin:keyHintLabel="۵" latin:additionalMoreKeys="۵,5" latin:keyLabelFlags="fontNormal" /> <!-- U+063A: "غ" ARABIC LETTER GHAIN U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX --> <Key - latin:keyLabel="غ" + latin:keySpec="غ" latin:keyHintLabel="۶" latin:additionalMoreKeys="۶,6" latin:keyLabelFlags="fontNormal" /> <!-- U+0639: "ع" ARABIC LETTER AIN U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN --> <Key - latin:keyLabel="ع" + latin:keySpec="ع" latin:keyHintLabel="۷" latin:additionalMoreKeys="۷,7" latin:keyLabelFlags="fontNormal" /> @@ -77,7 +77,7 @@ U+0629: "ة" ARABIC LETTER TEH MARBUTA U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT --> <Key - latin:keyLabel="ه" + latin:keySpec="ه" latin:moreKeys="ﻫ|ه‍,هٔ,ة,%" latin:keyHintLabel="۸" latin:additionalMoreKeys="۸,8" @@ -85,19 +85,19 @@ <!-- U+062E: "خ" ARABIC LETTER KHAH U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE --> <Key - latin:keyLabel="خ" + latin:keySpec="خ" latin:keyHintLabel="۹" latin:additionalMoreKeys="۹,9" latin:keyLabelFlags="fontNormal" /> <!-- U+062D: "ح" ARABIC LETTER HAH U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO --> <Key - latin:keyLabel="ح" + latin:keySpec="ح" latin:keyHintLabel="۰" latin:additionalMoreKeys="۰,0" latin:keyLabelFlags="fontNormal" /> <!-- U+062C: "ج" ARABIC LETTER JEEM --> <Key - latin:keyLabel="ج" + latin:keySpec="ج" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_farsi2.xml b/java/res/xml/rowkeys_farsi2.xml index 590161f62..f94ee8e49 100644 --- a/java/res/xml/rowkeys_farsi2.xml +++ b/java/res/xml/rowkeys_farsi2.xml @@ -23,11 +23,11 @@ > <!-- U+0634: "ش" ARABIC LETTER SHEEN --> <Key - latin:keyLabel="ش" + latin:keySpec="ش" latin:keyLabelFlags="fontNormal" /> <!-- U+0633: "س" ARABIC LETTER SEEN --> <Key - latin:keyLabel="س" + latin:keySpec="س" latin:keyLabelFlags="fontNormal" /> <!-- U+06CC: "ی" ARABIC LETTER FARSI YEH U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE @@ -35,16 +35,16 @@ U+FBE8: "ﯨ" ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM U+0649: "ى" ARABIC LETTER ALEF MAKSURA --> <Key - latin:keyLabel="ی" + latin:keySpec="ی" latin:moreKeys="ئ,ي,ﯨ|ى" latin:keyLabelFlags="fontNormal" /> <!-- U+0628: "ب" ARABIC LETTER BEH --> <Key - latin:keyLabel="ب" + latin:keySpec="ب" latin:keyLabelFlags="fontNormal" /> <!-- U+0644: "ل" ARABIC LETTER LAM --> <Key - latin:keyLabel="ل" + latin:keySpec="ل" latin:keyLabelFlags="fontNormal" /> <!-- U+0627: "ا" ARABIC LETTER ALEF U+0671: "ٱ" ARABIC LETTER ALEF WASLA @@ -53,31 +53,31 @@ U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW --> <Key - latin:keyLabel="ا" + latin:keySpec="ا" latin:moreKeys="!fixedColumnOrder!5,ٱ,ء,آ,أ,إ" latin:keyLabelFlags="fontNormal" /> <!-- U+062A: "ت" ARABIC LETTER TEH U+0629: "ة": ARABIC LETTER TEH MARBUTA --> <Key - latin:keyLabel="ت" + latin:keySpec="ت" latin:moreKeys="ة" latin:keyLabelFlags="fontNormal" /> <!-- U+0646: "ن" ARABIC LETTER NOON --> <Key - latin:keyLabel="ن" + latin:keySpec="ن" latin:keyLabelFlags="fontNormal" /> <!-- U+0645: "م" ARABIC LETTER MEEM --> <Key - latin:keyLabel="م" + latin:keySpec="م" latin:keyLabelFlags="fontNormal" /> <!-- U+06A9: "ک" ARABIC LETTER KEHEH U+0643: "ك" ARABIC LETTER KAF --> <Key - latin:keyLabel="ک" + latin:keySpec="ک" latin:moreKeys="ك" latin:keyLabelFlags="fontNormal" /> <!-- U+06AF: "گ" ARABIC LETTER GAF --> <Key - latin:keyLabel="گ" + latin:keySpec="گ" latin:keyLabelFlags="fontNormal" /> </merge> diff --git a/java/res/xml/rowkeys_farsi3.xml b/java/res/xml/rowkeys_farsi3.xml index 98949f4c0..edc22f95a 100644 --- a/java/res/xml/rowkeys_farsi3.xml +++ b/java/res/xml/rowkeys_farsi3.xml @@ -23,40 +23,40 @@ > <!-- U+0638: "ظ" ARABIC LETTER ZAH --> <Key - latin:keyLabel="ظ" + latin:keySpec="ظ" latin:keyLabelFlags="fontNormal" /> <!-- U+0637: "ط" ARABIC LETTER TAH --> <Key - latin:keyLabel="ط" + latin:keySpec="ط" latin:keyLabelFlags="fontNormal" /> <!-- U+0698: "ژ" ARABIC LETTER JEH --> <Key - latin:keyLabel="ژ" + latin:keySpec="ژ" latin:keyLabelFlags="fontNormal" /> <!-- U+0632: "ز" ARABIC LETTER ZAIN --> <Key - latin:keyLabel="ز" + latin:keySpec="ز" latin:keyLabelFlags="fontNormal" /> <!-- U+0631: "ر" ARABIC LETTER REH --> <Key - latin:keyLabel="ر" + latin:keySpec="ر" latin:keyLabelFlags="fontNormal" /> <!-- U+0630: "ذ" ARABIC LETTER THAL --> <Key - latin:keyLabel="ذ" + latin:keySpec="ذ" latin:keyLabelFlags="fontNormal" /> <!-- U+062F: "د" ARABIC LETTER DAL --> <Key - latin:keyLabel="د" + latin:keySpec="د" latin:keyLabelFlags="fontNormal" /> <!-- U+067E: "پ" ARABIC LETTER PEH --> <Key - latin:keyLabel="پ" + latin:keySpec="پ" latin:keyLabelFlags="fontNormal" /> <!-- U+0648: "و" ARABIC LETTER WAW U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE --> <Key - latin:keyLabel="و" + latin:keySpec="و" latin:moreKeys="ؤ" latin:keyLabelFlags="fontNormal" /> <include diff --git a/java/res/xml/rowkeys_georgian1.xml b/java/res/xml/rowkeys_georgian1.xml index d31a4c79c..c412aa3fa 100644 --- a/java/res/xml/rowkeys_georgian1.xml +++ b/java/res/xml/rowkeys_georgian1.xml @@ -26,104 +26,104 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel="Q" + latin:keySpec="Q" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+10ED: "ჭ" GEORGIAN LETTER CHAR --> <Key - latin:keyLabel="ჭ" + latin:keySpec="ჭ" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <Key - latin:keyLabel="E" + latin:keySpec="E" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> <!-- U+10E6: "ღ" GEORGIAN LETTER GHAN --> <Key - latin:keyLabel="ღ" + latin:keySpec="ღ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+10D7: "თ" GEORGIAN LETTER TAN --> <Key - latin:keyLabel="თ" + latin:keySpec="თ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <Key - latin:keyLabel="Y" + latin:keySpec="Y" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <Key - latin:keyLabel="U" + latin:keySpec="U" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <Key - latin:keyLabel="I" + latin:keySpec="I" latin:keyHintLabel="8" latin:additionalMoreKeys="8" /> <Key - latin:keyLabel="O" + latin:keySpec="O" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <Key - latin:keyLabel="P" + latin:keySpec="P" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </case> <default> <!-- U+10E5: "ქ" GEORGIAN LETTER GHAN --> <Key - latin:keyLabel="ქ" + latin:keySpec="ქ" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+10EC: "წ" GEORGIAN LETTER CIL --> <Key - latin:keyLabel="წ" + latin:keySpec="წ" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+10D4: "ე" GEORGIAN LETTER EN U+10F1: "ჱ" GEORGIAN LETTER HE --> <Key - latin:keyLabel="ე" + latin:keySpec="ე" latin:moreKeys="ჱ" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> <!-- U+10E0: "რ" GEORGIAN LETTER RAE --> <Key - latin:keyLabel="რ" + latin:keySpec="რ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+10E2: "ტ" GEORGIAN LETTER TAR --> <Key - latin:keyLabel="ტ" + latin:keySpec="ტ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <!-- U+10E7: "ყ" GEORGIAN LETTER QAR U+10F8: "ჸ" GEORGIAN LETTER ELIFI --> <Key - latin:keyLabel="ყ" + latin:keySpec="ყ" latin:moreKeys="ჸ" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <!-- U+10E3: "უ" GEORGIAN LETTER UN --> <Key - latin:keyLabel="უ" + latin:keySpec="უ" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+10D8: "ი" GEORGIAN LETTER IN U+10F2: "ჲ" GEORGIAN LETTER HIE --> <Key - latin:keyLabel="ი" + latin:keySpec="ი" latin:moreKeys="ჲ" latin:keyHintLabel="8" latin:additionalMoreKeys="8" /> <!-- U+10DD: "ო" GEORGIAN LETTER ON --> <Key - latin:keyLabel="ო" + latin:keySpec="ო" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+10DE: "პ" GEORGIAN LETTER PAR --> <Key - latin:keyLabel="პ" + latin:keySpec="პ" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </default> diff --git a/java/res/xml/rowkeys_georgian2.xml b/java/res/xml/rowkeys_georgian2.xml index cdccda31f..162960d75 100644 --- a/java/res/xml/rowkeys_georgian2.xml +++ b/java/res/xml/rowkeys_georgian2.xml @@ -26,64 +26,64 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel="A" /> + latin:keySpec="A" /> <!-- U+10E8: "შ" GEORGIAN LETTER SHIN --> <Key - latin:keyLabel="შ" /> + latin:keySpec="შ" /> <Key - latin:keyLabel="D" /> + latin:keySpec="D" /> <Key - latin:keyLabel="F" /> + latin:keySpec="F" /> <Key - latin:keyLabel="G" /> + latin:keySpec="G" /> <Key - latin:keyLabel="H" /> + latin:keySpec="H" /> <!-- U+10DF: "ჟ" GEORGIAN LETTER ZHAR --> <Key - latin:keyLabel="ჟ" /> + latin:keySpec="ჟ" /> <Key - latin:keyLabel="K" /> + latin:keySpec="K" /> <Key - latin:keyLabel="L" /> + latin:keySpec="L" /> </case> <default> <!-- U+10D0: "ა" GEORGIAN LETTER AN U+10FA: "ჺ" GEORGIAN LETTER AIN --> <Key - latin:keyLabel="ა" + latin:keySpec="ა" latin:moreKeys="ჺ" /> <!-- U+10E1: "ს" GEORGIAN LETTER SAN --> <Key - latin:keyLabel="ს" /> + latin:keySpec="ს" /> <!-- U+10D3: "დ" GEORGIAN LETTER DON --> <Key - latin:keyLabel="დ" /> + latin:keySpec="დ" /> <!-- U+10E4: "ფ" GEORGIAN LETTER PHAR U+10F6: "ჶ" GEORGIAN LETTER FI --> <Key - latin:keyLabel="ფ" + latin:keySpec="ფ" latin:moreKeys="ჶ" /> <!-- U+10D2: "გ" GEORGIAN LETTER GAN U+10F9: "ჹ" GEORGIAN LETTER TURNED GAN --> <Key - latin:keyLabel="გ" + latin:keySpec="გ" latin:moreKeys="ჹ" /> <!-- U+10F0: "ჰ" GEORGIAN LETTER HAE U+10F5: "ჵ" GEORGIAN LETTER HOE --> <Key - latin:keyLabel="ჰ" + latin:keySpec="ჰ" latin:moreKeys="ჵ" /> <!-- U+10EF: "ჯ" GEORGIAN LETTER JHAN U+10F7: "ჷ" GEORGIAN LETTER YN --> <Key - latin:keyLabel="ჯ" + latin:keySpec="ჯ" latin:moreKeys="ჷ" /> <!-- U+10D9: "კ" GEORGIAN LETTER KAN --> <Key - latin:keyLabel="კ" /> + latin:keySpec="კ" /> <!-- U+10DA: "ლ" GEORGIAN LETTER LAS --> <Key - latin:keyLabel="ლ" /> + latin:keySpec="ლ" /> </default> </switch> </merge> diff --git a/java/res/xml/rowkeys_georgian3.xml b/java/res/xml/rowkeys_georgian3.xml index a3714586f..a16acf8d3 100644 --- a/java/res/xml/rowkeys_georgian3.xml +++ b/java/res/xml/rowkeys_georgian3.xml @@ -27,49 +27,49 @@ > <!-- U+10EB: "ძ" GEORGIAN LETTER JIL --> <Key - latin:keyLabel="ძ" /> + latin:keySpec="ძ" /> <Key - latin:keyLabel="X" /> + latin:keySpec="X" /> <!-- U+10E9: "ჩ" GEORGIAN LETTER CHIN --> <Key - latin:keyLabel="ჩ" /> + latin:keySpec="ჩ" /> <Key - latin:keyLabel="V" /> + latin:keySpec="V" /> <Key - latin:keyLabel="B" /> + latin:keySpec="B" /> <Key - latin:keyLabel="N" /> + latin:keySpec="N" /> <Key - latin:keyLabel="M" /> + latin:keySpec="M" /> </case> <default> <!-- U+10D6: "ზ" GEORGIAN LETTER ZEN --> <Key - latin:keyLabel="ზ" /> + latin:keySpec="ზ" /> <!-- U+10EE: "ხ" GEORGIAN LETTER XAN U+10F4: "ჴ" GEORGIAN LETTER HAR --> <Key - latin:keyLabel="ხ" + latin:keySpec="ხ" latin:moreKeys="ჴ" /> <!-- U+10EA: "ც" GEORGIAN LETTER CAN --> <Key - latin:keyLabel="ც" /> + latin:keySpec="ც" /> <!-- U+10D5: "ვ" GEORGIAN LETTER VIN U+10F3: "ჳ" GEORGIAN LETTER WE --> <Key - latin:keyLabel="ვ" + latin:keySpec="ვ" latin:moreKeys="ჳ" /> <!-- U+10D1: "ბ" GEORGIAN LETTER BAN --> <Key - latin:keyLabel="ბ" /> + latin:keySpec="ბ" /> <!-- U+10DC: "ნ" GEORGIAN LETTER NAR U+10FC: "ჼ" MODIFIER LETTER GEORGIAN NAR --> <Key - latin:keyLabel="ნ" + latin:keySpec="ნ" latin:moreKeys="ჼ" /> <!-- U+10DB: "მ" GEORGIAN LETTER MAN --> <Key - latin:keyLabel="მ" /> + latin:keySpec="მ" /> </default> </switch> </merge> diff --git a/java/res/xml/rowkeys_greek1.xml b/java/res/xml/rowkeys_greek1.xml index 5777d3b85..6d767794c 100644 --- a/java/res/xml/rowkeys_greek1.xml +++ b/java/res/xml/rowkeys_greek1.xml @@ -21,6 +21,24 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > + <switch> + <case + latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <Key + latin:keySpec=":" + latin:keyHintLabel="1" + latin:moreKeys=";" + latin:additionalMoreKeys="1" /> + </case> + <default> + <Key + latin:keySpec=";" + latin:keyHintLabel="1" + latin:moreKeys=":" + latin:additionalMoreKeys="1" /> + </default> + </switch> <!-- TODO: Should find a way to compound Greek dialytika tonos and other Greek letters. --> <!-- <switch> @@ -29,7 +47,7 @@ > U+0385: "΅" GREEK DIALYTIKA TONOS <Key - latin:keyLabel="΅" + latin:keySpec="΅" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> </case> @@ -37,7 +55,7 @@ --> <!-- U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA --> <Key - latin:keyLabel="ς" + latin:keySpec="ς" latin:keyLabelFlags="preserveCase" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> @@ -48,18 +66,18 @@ <!-- U+03B5: "ε" GREEK SMALL LETTER EPSILON U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS --> <Key - latin:keyLabel="ε" + latin:keySpec="ε" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="έ" /> + latin:moreKeys="έ,%" /> <!-- U+03C1: "ρ" GREEK SMALL LETTER RHO --> <Key - latin:keyLabel="ρ" + latin:keySpec="ρ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+03C4: "τ" GREEK SMALL LETTER TAU --> <Key - latin:keyLabel="τ" + latin:keySpec="τ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <!-- U+03C5: "υ" GREEK SMALL LETTER UPSILON @@ -67,13 +85,13 @@ U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS --> <Key - latin:keyLabel="υ" + latin:keySpec="υ" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="ύ,ϋ,ΰ" /> + latin:moreKeys="ύ,%,ϋ,ΰ" /> <!-- U+03B8: "θ" GREEK SMALL LETTER THETA --> <Key - latin:keyLabel="θ" + latin:keySpec="θ" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+03B9: "ι" GREEK SMALL LETTER IOTA @@ -81,20 +99,20 @@ U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS --> <Key - latin:keyLabel="ι" + latin:keySpec="ι" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="ί,ϊ,ΐ" /> + latin:moreKeys="ί,%,ϊ,ΐ" /> <!-- U+03BF: "ο" GREEK SMALL LETTER OMICRON U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS --> <Key - latin:keyLabel="ο" + latin:keySpec="ο" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="ό" /> + latin:moreKeys="ό,%" /> <!-- U+03C0: "π" GREEK SMALL LETTER PI --> <Key - latin:keyLabel="π" + latin:keySpec="π" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </merge> diff --git a/java/res/xml/rowkeys_greek2.xml b/java/res/xml/rowkeys_greek2.xml index 91bdc1165..d8769caa9 100644 --- a/java/res/xml/rowkeys_greek2.xml +++ b/java/res/xml/rowkeys_greek2.xml @@ -24,32 +24,32 @@ <!-- U+03B1: "α" GREEK SMALL LETTER ALPHA U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS --> <Key - latin:keyLabel="α" + latin:keySpec="α" latin:moreKeys="ά" /> <!-- U+03C3: "σ" GREEK SMALL LETTER SIGMA --> <Key - latin:keyLabel="σ" /> + latin:keySpec="σ" /> <!-- U+03B4: "δ" GREEK SMALL LETTER DELTA --> <Key - latin:keyLabel="δ" /> + latin:keySpec="δ" /> <!-- U+03C6: "φ" GREEK SMALL LETTER PHI --> <Key - latin:keyLabel="φ" /> + latin:keySpec="φ" /> <!-- U+03B3: "γ" GREEK SMALL LETTER GAMMA --> <Key - latin:keyLabel="γ" /> + latin:keySpec="γ" /> <!-- U+03B7: "η" GREEK SMALL LETTER ETA U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS --> <Key - latin:keyLabel="η" + latin:keySpec="η" latin:moreKeys="ή" /> <!-- U+03BE: "ξ" GREEK SMALL LETTER XI --> <Key - latin:keyLabel="ξ" /> + latin:keySpec="ξ" /> <!-- U+03BA: "κ" GREEK SMALL LETTER KAPPA --> <Key - latin:keyLabel="κ" /> + latin:keySpec="κ" /> <!-- U+03BB: "λ" GREEK SMALL LETTER LAMDA --> <Key - latin:keyLabel="λ" /> + latin:keySpec="λ" /> </merge> diff --git a/java/res/xml/rowkeys_greek3.xml b/java/res/xml/rowkeys_greek3.xml index 8a99db925..3f989bc9c 100644 --- a/java/res/xml/rowkeys_greek3.xml +++ b/java/res/xml/rowkeys_greek3.xml @@ -23,25 +23,25 @@ > <!-- U+03B6: "ζ" GREEK SMALL LETTER ZETA --> <Key - latin:keyLabel="ζ" /> + latin:keySpec="ζ" /> <!-- U+03C7: "χ" GREEK SMALL LETTER CHI --> <Key - latin:keyLabel="χ" /> + latin:keySpec="χ" /> <!-- U+03C8: "ψ" GREEK SMALL LETTER PSI --> <Key - latin:keyLabel="ψ" /> + latin:keySpec="ψ" /> <!-- U+03C9: "ω" GREEK SMALL LETTER OMEGA U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS --> <Key - latin:keyLabel="ω" + latin:keySpec="ω" latin:moreKeys="ώ" /> <!-- U+03B2: "β" GREEK SMALL LETTER BETA --> <Key - latin:keyLabel="β" /> + latin:keySpec="β" /> <!-- U+03BD: "ν" GREEK SMALL LETTER NU --> <Key - latin:keyLabel="ν" /> + latin:keySpec="ν" /> <!-- U+03BC: "μ" GREEK SMALL LETTER MU --> <Key - latin:keyLabel="μ" /> + latin:keySpec="μ" /> </merge> diff --git a/java/res/xml/rowkeys_hebrew1.xml b/java/res/xml/rowkeys_hebrew1.xml index 81a00e367..e888977ae 100644 --- a/java/res/xml/rowkeys_hebrew1.xml +++ b/java/res/xml/rowkeys_hebrew1.xml @@ -26,22 +26,22 @@ latin:mode="email|url" > <Key - latin:keyLabel="-" + latin:keySpec="-" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <Key - latin:keyLabel="_" + latin:keySpec="_" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> </case> <default> <Key - latin:keyLabel="\'" + latin:keySpec="\'" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys=""" /> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="_" /> @@ -49,42 +49,42 @@ </switch> <!-- U+05E7: "ק" HEBREW LETTER QOF --> <Key - latin:keyLabel="ק" + latin:keySpec="ק" latin:keyHintLabel="3" latin:additionalMoreKeys="3" /> <!-- U+05E8: "ר" HEBREW LETTER RESH --> <Key - latin:keyLabel="ר" + latin:keySpec="ר" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+05D0: "א" HEBREW LETTER ALEF --> <Key - latin:keyLabel="א" + latin:keySpec="א" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <!-- U+05D8: "ט" HEBREW LETTER TET --> <Key - latin:keyLabel="ט" + latin:keySpec="ט" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <!-- U+05D5: "ו" HEBREW LETTER VAV --> <Key - latin:keyLabel="ו" + latin:keySpec="ו" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+05DF: "ן" HEBREW LETTER FINAL NUN --> <Key - latin:keyLabel="ן" + latin:keySpec="ן" latin:keyHintLabel="8" latin:additionalMoreKeys="8" /> <!-- U+05DD: "ם" HEBREW LETTER FINAL MEM --> <Key - latin:keyLabel="ם" + latin:keySpec="ם" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+05E4: "פ" HEBREW LETTER PE --> <Key - latin:keyLabel="פ" + latin:keySpec="פ" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </merge> diff --git a/java/res/xml/rowkeys_hebrew2.xml b/java/res/xml/rowkeys_hebrew2.xml index e4ecac335..d43f5a8f2 100644 --- a/java/res/xml/rowkeys_hebrew2.xml +++ b/java/res/xml/rowkeys_hebrew2.xml @@ -23,38 +23,38 @@ > <!-- U+05E9: "ש" HEBREW LETTER SHIN --> <Key - latin:keyLabel="ש" /> + latin:keySpec="ש" /> <!-- U+05D3: "ד" HEBREW LETTER DALET --> <Key - latin:keyLabel="ד" /> + latin:keySpec="ד" /> <!-- U+05D2: "ג" HEBREW LETTER GIMEL U+05D2 U+05F3: "ג׳" HEBREW LETTER GIMEL + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="ג" + latin:keySpec="ג" latin:moreKeys="ג׳" /> <!-- U+05DB: "כ" HEBREW LETTER KAF --> <Key - latin:keyLabel="כ" /> + latin:keySpec="כ" /> <!-- U+05E2: "ע" HEBREW LETTER AYIN --> <Key - latin:keyLabel="ע" /> + latin:keySpec="ע" /> <!-- U+05D9: "י" HEBREW LETTER YOD U+05F2 U+05B7: "ײַ" HEBREW LIGATURE YIDDISH DOUBLE YOD + HEBREW POINT PATAH --> <Key - latin:keyLabel="י" + latin:keySpec="י" latin:moreKeys="ײַ" /> <!-- U+05D7: "ח" HEBREW LETTER HET U+05D7 U+05F3: "ח׳" HEBREW LETTER HET + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="ח" + latin:keySpec="ח" latin:moreKeys="ח׳" /> <!-- U+05DC: "ל" HEBREW LETTER LAMED --> <Key - latin:keyLabel="ל" /> + latin:keySpec="ל" /> <!-- U+05DA: "ך" HEBREW LETTER FINAL KAF --> <Key - latin:keyLabel="ך" /> + latin:keySpec="ך" /> <!-- U+05E3: "ף" HEBREW LETTER FINAL PE --> <Key - latin:keyLabel="ף" /> + latin:keySpec="ף" /> </merge> diff --git a/java/res/xml/rowkeys_hebrew3.xml b/java/res/xml/rowkeys_hebrew3.xml index 805a7a596..928e6b255 100644 --- a/java/res/xml/rowkeys_hebrew3.xml +++ b/java/res/xml/rowkeys_hebrew3.xml @@ -24,36 +24,36 @@ <!-- U+05D6: "ז" HEBREW LETTER ZAYIN U+05D6 U+05F3: "ז׳" HEBREW LETTER ZAYIN + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="ז" + latin:keySpec="ז" latin:moreKeys="ז׳" /> <!-- U+05E1: "ס" HEBREW LETTER SAMEKH --> <Key - latin:keyLabel="ס" /> + latin:keySpec="ס" /> <!-- U+05D1: "ב" HEBREW LETTER BET --> <Key - latin:keyLabel="ב" /> + latin:keySpec="ב" /> <!-- U+05D4: "ה" HEBREW LETTER HE --> <Key - latin:keyLabel="ה" /> + latin:keySpec="ה" /> <!-- U+05E0: "נ" HEBREW LETTER NUN --> <Key - latin:keyLabel="נ" /> + latin:keySpec="נ" /> <!-- U+05DE: "מ" HEBREW LETTER MEM --> <Key - latin:keyLabel="מ" /> + latin:keySpec="מ" /> <!-- U+05E6: "צ" HEBREW LETTER TSADI U+05E6 U+05F3: "צ׳" HEBREW LETTER TSADI + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="צ" + latin:keySpec="צ" latin:moreKeys="צ׳" /> <!-- U+05EA: "ת" HEBREW LETTER TAV U+05EA U+05F3: "ת׳" HEBREW LETTER TAV + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="ת" + latin:keySpec="ת" latin:moreKeys="ת׳" /> <!-- U+05E5: "ץ" HEBREW LETTER FINAL TSADI U+05E5 U+05F3: "ץ׳" HEBREW LETTER FINAL TSADI + HEBREW PUNCTUATION GERESH --> <Key - latin:keyLabel="ץ" + latin:keySpec="ץ" latin:moreKeys="ץ׳" /> </merge> diff --git a/java/res/xml/rowkeys_hindi1.xml b/java/res/xml/rowkeys_hindi1.xml index c0b3cb913..cff9756cf 100644 --- a/java/res/xml/rowkeys_hindi1.xml +++ b/java/res/xml/rowkeys_hindi1.xml @@ -28,38 +28,38 @@ <!-- U+0914: "औ" DEVANAGARI LETTER AU U+0912/U+0902: "ऒं" DEVANAGARI LETTER SHORT O//DEVANAGARI SIGN ANUSVARA --> <Key - latin:keyLabel="औ" + latin:keySpec="औ" latin:moreKeys="ऒं" latin:keyLabelFlags="fontNormal" /> <!-- U+0910: "ऐ" DEVANAGARI LETTER AI U+0910/U+0902: "ऐं" DEVANAGARI LETTER AI/DEVANAGARI SIGN ANUSVARA --> <Key - latin:keyLabel="ऐ" + latin:keySpec="ऐ" latin:moreKeys="ऐं" latin:keyLabelFlags="fontNormal" /> <!-- U+0906: "आ" DEVANAGARI LETTER AA U+0906/U+0902: "आं" DEVANAGARI LETTER AA/DEVANAGARI SIGN ANUSVARA U+0906/U+0901: "आँ" DEVANAGARI LETTER AA/DEVANAGARI SIGN CANDRABINDU --> <Key - latin:keyLabel="आ" + latin:keySpec="आ" latin:moreKeys="आं,आँ" latin:keyLabelFlags="fontNormal" /> <!-- U+0908: "ई" DEVANAGARI LETTER II U+0908/U+0902: "ईं" DEVANAGARI LETTER II/DEVANAGARI SIGN ANUSVARA --> <Key - latin:keyLabel="ई" + latin:keySpec="ई" latin:moreKeys="ईं" latin:keyLabelFlags="fontNormal" /> <!-- U+090A: "ऊ" DEVANAGARI LETTER UU U+090A/U+0902: "ऊं" DEVANAGARI LETTER UU/DEVANAGARI SIGN ANUSVARA U+090A/U+0901: "ऊँ" DEVANAGARI LETTER UU/DEVANAGARI SIGN CANDRABINDU --> <Key - latin:keyLabel="ऊ" + latin:keySpec="ऊ" latin:moreKeys="ऊं,ऊँ" latin:keyLabelFlags="fontNormal" /> <!-- U+092D: "भ" DEVANAGARI LETTER BHA --> <Key - latin:keyLabel="भ" + latin:keySpec="भ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -70,31 +70,31 @@ latin:keyStyle="baseKeyDevanagariSignVisarga" /> <!-- U+0918: "घ" DEVANAGARI LETTER GHA --> <Key - latin:keyLabel="घ" + latin:keySpec="घ" latin:keyLabelFlags="fontNormal" /> <!-- U+0927: "ध" DEVANAGARI LETTER DHA U+0915/U+094D/U+0937: "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> <Key - latin:keyLabel="ध" + latin:keySpec="ध" latin:moreKeys="क्ष,श्र" latin:keyLabelFlags="fontNormal" /> <!-- U+091D: "झ" DEVANAGARI LETTER JHA --> <Key - latin:keyLabel="झ" + latin:keySpec="झ" latin:keyLabelFlags="fontNormal" /> <!-- U+0922: "ढ" DEVANAGARI LETTER DDHA --> <Key - latin:keyLabel="ढ" + latin:keySpec="ढ" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+0967: "१" DEVANAGARI DIGIT ONE --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" /> + <!-- U+0967: "१" DEVANAGARI DIGIT ONE --> <Key latin:keyStyle="baseKeyDevanagariVowelSignAu" latin:keyHintLabel="1" @@ -102,9 +102,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" /> + <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> <Key latin:keyStyle="baseKeyDevanagariVowelSignAi" latin:keyHintLabel="2" @@ -112,9 +112,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_aa" /> + <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> <Key latin:keyStyle="baseKeyDevanagariVowelSignAa" latin:keyHintLabel="3" @@ -122,9 +122,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+096A: "४" DEVANAGARI DIGIT FOUR --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ii" /> + <!-- U+096A: "४" DEVANAGARI DIGIT FOUR --> <Key latin:keyStyle="baseKeyDevanagariVowelSignIi" latin:keyHintLabel="4" @@ -132,18 +132,18 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+096B: "५" DEVANAGARI DIGIT FIVE --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_uu" /> + <!-- U+096B: "५" DEVANAGARI DIGIT FIVE --> <Key latin:keyStyle="baseKeyDevanagariVowelSignUu" latin:keyHintLabel="5" latin:additionalMoreKeys="५,5" /> <!-- U+092C: "ब" DEVANAGARI LETTER BA - U+096C: "६" DEVANAGARI DIGIT SIX - U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA --> + U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA + U+096C: "६" DEVANAGARI DIGIT SIX --> <Key - latin:keyLabel="ब" + latin:keySpec="ब" latin:moreKeys="ब॒,%" latin:keyHintLabel="6" latin:additionalMoreKeys="६,6" @@ -151,7 +151,7 @@ <!-- U+0939: "ह" DEVANAGARI LETTER HA U+096D: "७" DEVANAGARI DIGIT SEVEN --> <Key - latin:keyLabel="ह" + latin:keySpec="ह" latin:keyHintLabel="7" latin:additionalMoreKeys="७,7" latin:keyLabelFlags="fontNormal" /> @@ -161,7 +161,7 @@ U+0917/U+0952: "ग॒" DEVANAGARI LETTER GA/DEVANAGARI STRESS SIGN ANUDATTA U+096E: "८" DEVANAGARI DIGIT EIGHT --> <Key - latin:keyLabel="ग" + latin:keySpec="ग" latin:moreKeys="ज्ञ,ग़,ग॒,%" latin:keyHintLabel="8" latin:additionalMoreKeys="८,8" @@ -169,7 +169,7 @@ <!-- U+0926: "द" DEVANAGARI LETTER DA U+096F: "९" DEVANAGARI DIGIT NINE --> <Key - latin:keyLabel="द" + latin:keySpec="द" latin:keyHintLabel="9" latin:additionalMoreKeys="९,9" latin:keyLabelFlags="fontNormal" /> @@ -179,7 +179,7 @@ U+091C/U+093C: "ज़" DEVANAGARI LETTER JA/DEVANAGARI SIGN NUKTA U+0966: "०" DEVANAGARI DIGIT ZERO --> <Key - latin:keyLabel="ज" + latin:keySpec="ज" latin:moreKeys="ज॒,ज्ञ,ज़,%" latin:keyHintLabel="0" latin:additionalMoreKeys="०,0" @@ -188,7 +188,7 @@ U+0921/U+0952: "ड॒" DEVANAGARI LETTER DDA/DEVANAGARI STRESS SIGN ANUDATTA U+0921/U+093C: "ड़" DEVANAGARI LETTER DDA/DEVANAGARI SIGN NUKTA --> <Key - latin:keyLabel="ड" + latin:keySpec="ड" latin:moreKeys="ड॒,ड़" latin:keyLabelFlags="fontNormal" /> </default> diff --git a/java/res/xml/rowkeys_hindi2.xml b/java/res/xml/rowkeys_hindi2.xml index 70ac66ee4..7ba4ee1ec 100644 --- a/java/res/xml/rowkeys_hindi2.xml +++ b/java/res/xml/rowkeys_hindi2.xml @@ -30,7 +30,7 @@ U+0911: "ऑ" DEVANAGARI LETTER CANDRA O U+0912: "ऒ" DEVANAGARI LETTER SHORT O --> <Key - latin:keyLabel="ओ" + latin:keySpec="ओ" latin:moreKeys="ओं,ऑ,ऒ" latin:keyLabelFlags="fontNormal" /> <!-- U+090F: "ए" DEVANAGARI LETTER E @@ -39,60 +39,60 @@ U+090D: "ऍ" DEVANAGARI LETTER CANDRA E U+090E: "ऎ" DEVANAGARI LETTER SHORT E --> <Key - latin:keyLabel="ए" + latin:keySpec="ए" latin:moreKeys="एं,एँ,ऍ,ऎ" latin:keyLabelFlags="fontNormal" /> <!-- U+0905: "अ" DEVANAGARI LETTER A U+0905/U+0902: "अं" DEVANAGARI LETTER A/DEVANAGARI SIGN ANUSVARA U+0905/U+0901: "अँ" DEVANAGARI LETTER A/DEVANAGARI SIGN CANDRABINDU --> <Key - latin:keyLabel="अ" + latin:keySpec="अ" latin:moreKeys="अं,अँ" latin:keyLabelFlags="fontNormal" /> <!-- U+0907: "इ" DEVANAGARI LETTER I U+0907/U+0902: "इं" DEVANAGARI LETTER I/DEVANAGARI SIGN ANUSVARA U+0907/U+0901: "इं" DEVANAGARI LETTER I/DEVANAGARI SIGN CANDRABINDU --> <Key - latin:keyLabel="इ" + latin:keySpec="इ" latin:moreKeys="इं,इँ" latin:keyLabelFlags="fontNormal" /> <!-- U+0909: "उ" DEVANAGARI LETTER U U+0909/U+0902: "उं" DEVANAGARI LETTER U/DEVANAGARI SIGN ANUSVARA U+0909/U+0901: "उँ" DEVANAGARI LETTER U/DEVANAGARI SIGN CANDRABINDU --> <Key - latin:keyLabel="उ" + latin:keySpec="उ" latin:moreKeys="उं,उँ" latin:keyLabelFlags="fontNormal" /> <!-- U+092B: "फ" DEVANAGARI LETTER PHA U+092B/U+093C: "फ़" DEVANAGARI LETTER PHA/DEVANAGARI SIGN NUKTA --> <Key - latin:keyLabel="फ" + latin:keySpec="फ" latin:moreKeys="फ़" latin:keyLabelFlags="fontNormal" /> <!-- U+0931: "ऱ" DEVANAGARI LETTER RRA U+094D/U+0930: "्र" DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA U+0930/U+094D: "र्" DEVANAGARI LETTER RA/DEVANAGARI SIGN VIRAMA --> <Key - latin:keyLabel="ऱ" + latin:keySpec="ऱ" latin:moreKeys="्र,र्" latin:keyLabelFlags="fontNormal" /> <!-- U+0916: "ख" DEVANAGARI LETTER KHA U+0916/U+093C: "ख़" DEVANAGARI LETTER KHA/DEVANAGARI SIGN NUKTA --> <Key - latin:keyLabel="ख" + latin:keySpec="ख" latin:moreKeys="ख़" latin:keyLabelFlags="fontNormal" /> <!-- U+0925: "थ" DEVANAGARI LETTER THA --> <Key - latin:keyLabel="थ" + latin:keySpec="थ" latin:keyLabelFlags="fontNormal" /> <!-- U+091B: "छ" DEVANAGARI LETTER CHA --> <Key - latin:keyLabel="छ" + latin:keySpec="छ" latin:keyLabelFlags="fontNormal" /> <!-- U+0920: "ठ" DEVANAGARI LETTER TTHA --> <Key - latin:keyLabel="ठ" + latin:keySpec="ठ" latin:keyLabelFlags="fontNormal" /> </case> <default> @@ -133,35 +133,35 @@ latin:keyStyle="baseKeyDevanagariVowelSignU" /> <!-- U+092A: "प" DEVANAGARI LETTER PA --> <Key - latin:keyLabel="प" + latin:keySpec="प" latin:keyLabelFlags="fontNormal" /> <!-- U+0930: "र" DEVANAGARI LETTER RA U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R U+0930/U+093C: "ऱ" DEVANAGARI LETTER RA/DEVANAGARI SIGN NUKTA U+0960: "ॠ" DEVANAGARI LETTER VOCALIC RR --> <Key - latin:keyLabel="र" + latin:keySpec="र" latin:moreKeys="ऋ,ऱ,ॠ" latin:keyLabelFlags="fontNormal" /> <!-- U+0915: "क" DEVANAGARI LETTER KA U+0915/U+093C: "क़" DEVANAGARI LETTER KA/DEVANAGARI SIGN NUKTA --> <Key - latin:keyLabel="क" + latin:keySpec="क" latin:moreKeys="क़" latin:keyLabelFlags="fontNormal" /> <!-- U+0924: "त" DEVANAGARI LETTER TA U+0924/U+094D/U+0930: "त्र" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> <Key - latin:keyLabel="त" + latin:keySpec="त" latin:moreKeys="त्र" latin:keyLabelFlags="fontNormal" /> <!-- U+091A: "च" DEVANAGARI LETTER CA --> <Key - latin:keyLabel="च" + latin:keySpec="च" latin:keyLabelFlags="fontNormal" /> <!-- U+091F: "ट" DEVANAGARI LETTER TTA --> <Key - latin:keyLabel="ट" + latin:keySpec="ट" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_hindi3.xml b/java/res/xml/rowkeys_hindi3.xml index 136bc5f22..cf36fc5d4 100644 --- a/java/res/xml/rowkeys_hindi3.xml +++ b/java/res/xml/rowkeys_hindi3.xml @@ -27,42 +27,46 @@ > <!-- U+0911: "ऑ" DEVANAGARI LETTER CANDRA O --> <Key - latin:keyLabel="ऑ" + latin:keySpec="ऑ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_candrabindu" /> + <Key + latin:keyStyle="baseKeyDevanagariSignCandrabindu" /> <!-- U+0923: "ण" DEVANAGARI LETTER NNA --> <Key - latin:keyLabel="ण" + latin:keySpec="ण" latin:keyLabelFlags="fontNormal" /> <!-- U+0929: "ऩ" DEVANAGARI LETTER NNNA --> <Key - latin:keyLabel="ऩ" /> + latin:keySpec="ऩ" /> <!-- U+0933: "ळ" DEVANAGARI LETTER LLA U+0934: "ऴ" DEVANAGARI LETTER LLLA --> <Key - latin:keyLabel="ळ" + latin:keySpec="ळ" latin:moreKeys="ऴ" latin:keyLabelFlags="fontNormal" /> <!-- U+0936: "श" DEVANAGARI LETTER SHA --> <Key - latin:keyLabel="श" + latin:keySpec="श" latin:keyLabelFlags="fontNormal" /> <!-- U+0937: "ष" DEVANAGARI LETTER SSA --> <Key - latin:keyLabel="ष" + latin:keySpec="ष" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" /> + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_vocalic_r" /> + <Key + latin:keyStyle="baseKeyDevanagariVowelSignVocalicR" /> <!-- U+091E: "ञ" DEVANAGARI LETTER NYA --> <Key - latin:keyLabel="ञ" + latin:keySpec="ञ" latin:keyLabelFlags="fontNormal" /> </case> <default> @@ -70,13 +74,20 @@ render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_vowel_sign_candra_o" /> + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_candra_o" /> + <Key + latin:keyStyle="baseKeyDevanagariVowelSignCandraO" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" /> + <Key + latin:keyStyle="baseKeyDevanagariSignAnusvara" /> <!-- U+092E: "म" DEVANAGARI LETTER MA U+0950: "ॐ" DEVANAGARI OM --> <Key - latin:keyLabel="म" + latin:keySpec="म" latin:moreKeys="ॐ" latin:keyLabelFlags="fontNormal" /> <!-- U+0928: "न" DEVANAGARI LETTER NA @@ -84,35 +95,37 @@ U+0919: "ङ" DEVANAGARI LETTER NGA U+0928/U+093C: "ऩ" DEVANAGARI LETTER NA/DEVANAGARI SIGN NUKTA --> <Key - latin:keyLabel="न" + latin:keySpec="न" latin:moreKeys="ञ,ङ,ऩ" latin:keyLabelFlags="fontNormal" /> <!-- U+0935: "व" DEVANAGARI LETTER VA --> <Key - latin:keyLabel="व" + latin:keySpec="व" latin:keyLabelFlags="fontNormal" /> <!-- U+0932: "ल" DEVANAGARI LETTER LA U+090C: "ऌ" DEVANAGARI LETTER VOCALIC L U+0961: "ॡ" DEVANAGARI LETTER VOCALIC LL --> <Key - latin:keyLabel="ल" + latin:keySpec="ल" latin:moreKeys="ऌ,ॡ" latin:keyLabelFlags="fontNormal" /> <!-- U+0938: "स" DEVANAGARI LETTER SA --> <Key - latin:keyLabel="स" + latin:keySpec="स" latin:keyLabelFlags="fontNormal" /> <!-- U+092F: "य" DEVANAGARI LETTER YA U+095F: "य़" DEVANAGARI LETTER YYA --> <Key - latin:keyLabel="य" + latin:keySpec="य" latin:moreKeys="य़" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_nukta" /> - </default> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_nukta" /> + <Key + latin:keyStyle="baseKeyDevanagariSignNukta" /> + </default> </switch> </merge> diff --git a/java/res/xml/rowkeys_hindi_compact1.xml b/java/res/xml/rowkeys_hindi_compact1.xml new file mode 100644 index 000000000..c63de4f0b --- /dev/null +++ b/java/res/xml/rowkeys_hindi_compact1.xml @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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" +> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" /> + <!-- U+0914: "औ" DEVANAGARI LETTER AU + U+0967: "१" DEVANAGARI DIGIT ONE --> + <Key + latin:keySpec="औ" + latin:keyStyle="moreKeysDevanagariVowelSignAu" + latin:keyHintLabel="1" + latin:additionalMoreKeys="१,1" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" /> + <!-- U+0910: "ऐ" DEVANAGARI LETTER AI + U+0968: "२" DEVANAGARI DIGIT TWO --> + <Key + latin:keySpec="ऐ" + latin:keyStyle="moreKeysDevanagariVowelSignAi" + latin:keyHintLabel="2" + latin:additionalMoreKeys="२,2" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_aa" /> + <!-- U+0906: "आ" DEVANAGARI LETTER AA + U+0969: "३" DEVANAGARI DIGIT THREE --> + <Key + latin:keySpec="आ" + latin:keyStyle="moreKeysDevanagariVowelSignAa" + latin:keyHintLabel="3" + latin:additionalMoreKeys="३,3" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ii" /> + <!-- U+0908: "ई" DEVANAGARI LETTER II + U+096A: "४" DEVANAGARI DIGIT FOUR --> + <Key + latin:keySpec="ई" + latin:keyStyle="moreKeysDevanagariVowelSignIi" + latin:keyHintLabel="4" + latin:additionalMoreKeys="४,4" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_uu" /> + <!-- U+090A: "ऊ" DEVANAGARI LETTER UU + U+096B: "५" DEVANAGARI DIGIT FIVE --> + <Key + latin:keySpec="ऊ" + latin:keyStyle="moreKeysDevanagariVowelSignUu" + latin:keyHintLabel="5" + latin:additionalMoreKeys="५,5" + latin:keyLabelFlags="fontNormal" /> + <!-- U+092C: "ब" DEVANAGARI LETTER BA + U+092D: "भ" DEVANAGARI LETTER BHA + U+096C: "६" DEVANAGARI DIGIT SIX --> + <Key + latin:keySpec="ब" + latin:moreKeys="भ,%" + latin:keyHintLabel="6" + latin:additionalMoreKeys="६,6" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0939: "ह" DEVANAGARI LETTER HA + U+096D: "७" DEVANAGARI DIGIT SEVEN --> + <Key + latin:keySpec="ह" + latin:keyHintLabel="7" + latin:additionalMoreKeys="७,7" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0917: "ग" DEVANAGARI LETTER GA + U+0918: "घ" DEVANAGARI LETTER GHA + U+096E: "८" DEVANAGARI DIGIT EIGHT --> + <Key + latin:keySpec="ग" + latin:moreKeys="घ,%" + latin:keyHintLabel="8" + latin:additionalMoreKeys="८,8" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0926: "द" DEVANAGARI LETTER DA + U+0927: "ध" DEVANAGARI LETTER DHA + U+096F: "९" DEVANAGARI DIGIT NINE --> + <Key + latin:keySpec="द" + latin:moreKeys="ध,%" + latin:keyHintLabel="9" + latin:additionalMoreKeys="९,9" + latin:keyLabelFlags="fontNormal" /> + <!-- U+091C: "ज" DEVANAGARI LETTER JA + U+091D: "झ" DEVANAGARI LETTER JHA + U+091C/U+094D/U+091E: "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA + U+0966: "०" DEVANAGARI DIGIT ZERO --> + <Key + latin:keySpec="ज" + latin:moreKeys="झ,ज्ञ,%" + latin:keyHintLabel="0" + latin:additionalMoreKeys="०,0" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0921: "ड" DEVANAGARI LETTER DDA + U+0922: "ढ" DEVANAGARI LETTER DDHA --> + <Key + latin:keySpec="ड" + latin:moreKeys="ढ" + latin:keyLabelFlags="fontNormal" /> +</merge> diff --git a/java/res/xml/rowkeys_hindi_compact2.xml b/java/res/xml/rowkeys_hindi_compact2.xml new file mode 100644 index 000000000..06364c209 --- /dev/null +++ b/java/res/xml/rowkeys_hindi_compact2.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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" +> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_o" /> + <!-- U+0913: "ओ" DEVANAGARI LETTER O --> + <Key + latin:keySpec="ओ" + latin:keyStyle="moreKeysDevanagariVowelSignO" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" /> + <!-- U+090F: "ए" DEVANAGARI LETTER E --> + <Key + latin:keySpec="ए" + latin:keyStyle="moreKeysDevanagariVowelSignE" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" /> + <!-- U+0905: "अ" DEVANAGARI LETTER A --> + <Key + latin:keySpec="अ" + latin:keyStyle="moreKeysDevanagariSignVirama" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_i" /> + <!-- U+0907: "इ" DEVANAGARI LETTER I --> + <Key + latin:keySpec="इ" + latin:keyStyle="moreKeysDevanagariVowelSignI" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_u" /> + <!-- U+0909: "उ" DEVANAGARI LETTER U --> + <Key + latin:keySpec="उ" + latin:keyStyle="moreKeysDevanagariVowelSignU" + latin:keyLabelFlags="fontNormal" /> + <!-- U+092A: "प" DEVANAGARI LETTER PA + U+092B: "फ" DEVANAGARI LETTER PHA --> + <Key + latin:keySpec="प" + latin:moreKeys="फ" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_vocalic_r" /> + <!-- U+0930: "र" DEVANAGARI LETTER RA --> + <Key + latin:keySpec="र" + latin:keyStyle="moreKeysDevanagariVowelSignVocalicR" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0915: "क" DEVANAGARI LETTER KA + U+0916: "ख" DEVANAGARI LETTER KHA --> + <Key + latin:keySpec="क" + latin:moreKeys="ख" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0924: "त" DEVANAGARI LETTER TA + U+0925: "थ" DEVANAGARI LETTER THA + U+0924/U+094D/U+0930: "त्र" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> + <Key + latin:keySpec="त" + latin:moreKeys="थ,त्र" + latin:keyLabelFlags="fontNormal" /> + <!-- U+091A: "च" DEVANAGARI LETTER CA + U+091B: "छ" DEVANAGARI LETTER CHA --> + <Key + latin:keySpec="च" + latin:moreKeys="छ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+091F: "ट" DEVANAGARI LETTER TTA + U+0920: "ठ" DEVANAGARI LETTER TTHA --> + <Key + latin:keySpec="ट" + latin:moreKeys="ठ" + latin:keyLabelFlags="fontNormal" /> +</merge> diff --git a/java/res/xml/rowkeys_hindi_compact3.xml b/java/res/xml/rowkeys_hindi_compact3.xml new file mode 100644 index 000000000..0e8165ecc --- /dev/null +++ b/java/res/xml/rowkeys_hindi_compact3.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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" +> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_candra_o" /> + <!-- U+0911: "ऑ" DEVANAGARI LETTER CANDRA O --> + <Key + latin:keySpec="ऑ" + latin:keyStyle="moreKeysDevanagariVowelSignCandraO" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_candra_e" /> + <!-- U+090D: "ऍ" DEVANAGARI LETTER CANDRA E --> + <Key + latin:keySpec="ऍ" + latin:keyStyle="moreKeysDevanagariVowelSignCandraE" + latin:keyLabelFlags="fontNormal" /> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" /> + <Key + latin:keyStyle="baseKeyDevanagariSignAnusvara" /> + <!-- U+092E: "म" DEVANAGARI LETTER MA + U+0950: "ॐ" DEVANAGARI OM --> + <Key + latin:keySpec="म" + latin:moreKeys="ॐ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0928: "न" DEVANAGARI LETTER NA + U+0923: "ण" DEVANAGARI LETTER NNA + U+091E: "ञ" DEVANAGARI LETTER NYA + U+0919: "ङ" DEVANAGARI LETTER NGA --> + <Key + latin:keySpec="न" + latin:moreKeys="ण,ञ,ङ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0935: "व" DEVANAGARI LETTER VA --> + <Key + latin:keySpec="व" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0932: "ल" DEVANAGARI LETTER LA --> + <Key + latin:keySpec="ल" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0938: "स" DEVANAGARI LETTER SA + U+0936: "श" DEVANAGARI LETTER SHA + U+0937: "ष" DEVANAGARI LETTER SSA + U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA --> + <Key + latin:keySpec="स" + latin:moreKeys="श,ष,श्र" + latin:keyLabelFlags="fontNormal" /> + <!-- U+092F: "य" DEVANAGARI LETTER YA --> + <Key + latin:keySpec="य" + latin:keyLabelFlags="fontNormal" /> + <!-- U+0915/U+094D/U+0937: "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA --> + <Key + latin:keySpec="क्ष" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> +</merge> diff --git a/java/res/xml/rowkeys_khmer1.xml b/java/res/xml/rowkeys_khmer1.xml index 25da66400..567c6aff0 100644 --- a/java/res/xml/rowkeys_khmer1.xml +++ b/java/res/xml/rowkeys_khmer1.xml @@ -27,78 +27,79 @@ > <!-- U+200D: ZERO WIDTH JOINER --> <Key - latin:keyLabel="!" + latin:keySpec="!" latin:moreKeys="!icon/zwj_key|‍" /> <!-- U+17D7: "ៗ" KHMER SIGN LEK TOO U+200C: ZERO WIDTH NON-JOINER --> <Key - latin:keyLabel="ៗ" + latin:keySpec="ៗ" latin:moreKeys="!icon/zwnj_key|‌" latin:keyLabelFlags="fontNormal" /> <!-- U+17D1: "៑" KHMER SIGN VIRIAM --> <Key - latin:keyLabel=""" + latin:keySpec=""" latin:keyHintLabel="៑" latin:moreKeys="៑" /> <!-- U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL U+20AC: "€" EURO SIGN --> <Key - latin:keyLabel="៛" + latin:keySpec="៛" latin:keyHintLabel="$" latin:moreKeys="$,€" latin:keyLabelFlags="fontNormal" /> <!-- U+17D6: "៖" KHMER SIGN CAMNUC PII KUUH --> <Key - latin:keyLabel="%" + latin:keySpec="%" latin:keyHintLabel="៖" latin:moreKeys="៖" /> <!-- U+17CD: "៍" KHMER SIGN TOANDAKHIAT U+17D9: "៙" KHMER SIGN PHNAEK MUAN --> <Key - latin:keyLabel="៍" + latin:keySpec="៍" latin:keyHintLabel="៙" latin:moreKeys="៙" latin:keyLabelFlags="fontNormal" /> <!-- U+17D0: "័" KHMER SIGN SAMYOK SANNYA U+17DA: "៚" KHMER SIGN KOOMUUT --> <Key - latin:keyLabel="័" + latin:keySpec="័" latin:keyHintLabel="៚" + latin:keyHintLabelVerticalAdjustment="-30%" latin:moreKeys="៚" latin:keyLabelFlags="fontNormal" /> <!-- U+17CF: "៏" KHMER SIGN AHSDA --> <Key - latin:keyLabel="៏" + latin:keySpec="៏" latin:keyHintLabel="*" latin:moreKeys="*" latin:keyLabelFlags="fontNormal" /> <!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel="(" + latin:keySpec="(" latin:keyHintLabel="{" latin:moreKeys="{,«" /> <!-- U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel=")" + latin:keySpec=")" latin:keyHintLabel="}" latin:moreKeys="},»" /> <!-- U+17CC: "៌" KHMER SIGN ROBAT U+00D7: "×" MULTIPLICATION SIGN --> <Key - latin:keyLabel="៌" + latin:keySpec="៌" latin:keyHintLabel="×" latin:moreKeys="×" latin:keyLabelFlags="fontNormal" /> <!-- U+17CE: "៎" KHMER SIGN KAKABAT --> <Key - latin:keyLabel="៎" + latin:keySpec="៎" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+17E1: "១" KHMER DIGIT ONE U+17F1: "៱" KHMER SYMBOL LEK ATTAK MUOY --> <Key - latin:keyLabel="១" + latin:keySpec="១" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys="៱" @@ -106,7 +107,7 @@ <!-- U+17E2: "២" KHMER DIGIT TWO U+17F2: "៲" KHMER SYMBOL LEK ATTAK PII --> <Key - latin:keyLabel="២" + latin:keySpec="២" latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="៲" @@ -114,7 +115,7 @@ <!-- U+17E3: "៣" KHMER DIGIT THREE U+17F3: "៳" KHMER SYMBOL LEK ATTAK BEI --> <Key - latin:keyLabel="៣" + latin:keySpec="៣" latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys="៳" @@ -122,7 +123,7 @@ <!-- U+17E4: "៤" KHMER DIGIT FOUR U+17F4: "៴" KHMER SYMBOL LEK ATTAK BUON --> <Key - latin:keyLabel="៤" + latin:keySpec="៤" latin:keyHintLabel="4" latin:additionalMoreKeys="4" latin:moreKeys="៴" @@ -130,7 +131,7 @@ <!-- U+17E5: "៥" KHMER DIGIT FIVE U+17F5: "៵" KHMER SYMBOL LEK ATTAK PRAM --> <Key - latin:keyLabel="៥" + latin:keySpec="៥" latin:keyHintLabel="5" latin:additionalMoreKeys="5" latin:moreKeys="៵" @@ -138,7 +139,7 @@ <!-- U+17E6: "៦" KHMER DIGIT SIX U+17F6: "៶" KHMER SYMBOL LEK ATTAK PRAM-MUOY --> <Key - latin:keyLabel="៦" + latin:keySpec="៦" latin:keyHintLabel="6" latin:additionalMoreKeys="6" latin:moreKeys="៶" @@ -146,7 +147,7 @@ <!-- U+17E7: "៧" KHMER DIGIT SEVEN U+17F7: "៷" KHMER SYMBOL LEK ATTAK PRAM-PII --> <Key - latin:keyLabel="៧" + latin:keySpec="៧" latin:keyHintLabel="7" latin:additionalMoreKeys="7" latin:moreKeys="៷" @@ -154,7 +155,7 @@ <!-- U+17E8: "៨" KHMER DIGIT EIGHT U+17F8: "៸" KHMER SYMBOL LEK ATTAK PRAM-BEI --> <Key - latin:keyLabel="៨" + latin:keySpec="៨" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:moreKeys="៸" @@ -162,7 +163,7 @@ <!-- U+17E9: "៩" KHMER DIGIT NINE U+17F9: "៹" KHMER SYMBOL LEK ATTAK PRAM-BUON --> <Key - latin:keyLabel="៩" + latin:keySpec="៩" latin:keyHintLabel="9" latin:additionalMoreKeys="9" latin:moreKeys="៹" @@ -170,7 +171,7 @@ <!-- U+17E0: "០" KHMER DIGIT ZERO U+17F0: "៰" KHMER SYMBOL LEK ATTAK SON --> <Key - latin:keyLabel="០" + latin:keySpec="០" latin:keyHintLabel="0" latin:additionalMoreKeys="0" latin:moreKeys="៰" @@ -178,14 +179,14 @@ <!-- U+17A5: "ឥ" KHMER INDEPENDENT VOWEL QI U+17A6: "ឦ" KHMER INDEPENDENT VOWEL QII --> <Key - latin:keyLabel="ឥ" + latin:keySpec="ឥ" latin:keyHintLabel="ឦ" latin:moreKeys=",ឦ" latin:keyLabelFlags="fontNormal" /> <!-- U+17B2: "ឲ" KHMER INDEPENDENT VOWEL QOO TYPE TWO U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE --> <Key - latin:keyLabel="ឲ" + latin:keySpec="ឲ" latin:keyHintLabel="ឱ" latin:moreKeys="ឱ" latin:keyLabelFlags="fontNormal" /> diff --git a/java/res/xml/rowkeys_khmer2.xml b/java/res/xml/rowkeys_khmer2.xml index cba2d3b90..4146895f7 100644 --- a/java/res/xml/rowkeys_khmer2.xml +++ b/java/res/xml/rowkeys_khmer2.xml @@ -28,106 +28,107 @@ <!-- U+1788: "ឈ" KHMER LETTER CHO U+17DC: "ៜ" KHMER SIGN AVAKRAHASANYA --> <Key - latin:keyLabel="ឈ" + latin:keySpec="ឈ" latin:keyHintLabel="ៜ" latin:moreKeys="ៜ" - latin:keyLabelFlags="fontNormal" /> + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+17BA: "ឺ" KHMER VOWEL SIGN YY U+17DD: "៝" KHMER SIGN ATTHACAN --> <Key - latin:keyLabel="ឺ" + latin:keySpec="ឺ" latin:keyHintLabel="៝" + latin:keyHintLabelVerticalAdjustment="40%" latin:moreKeys="៝" latin:keyLabelFlags="fontNormal" /> <!-- U+17C2: "ែ" KHMER VOWEL SIGN AE --> <Key - latin:keyLabel="ែ" + latin:keySpec="ែ" latin:keyLabelFlags="fontNormal" /> <!-- U+17AC: "ឬ" KHMER INDEPENDENT VOWEL RYY U+17AB: "ឫ" KHMER INDEPENDENT VOWEL RY --> <Key - latin:keyLabel="ឬ" + latin:keySpec="ឬ" latin:keyHintLabel="ឫ" latin:moreKeys="ឫ" latin:keyLabelFlags="fontNormal" /> <!-- U+1791: "ទ" KHMER LETTER TO --> <Key - latin:keyLabel="ទ" + latin:keySpec="ទ" latin:keyLabelFlags="fontNormal" /> <!-- U+17BD: "ួ" KHMER VOWEL SIGN UA --> <Key - latin:keyLabel="ួ" + latin:keySpec="ួ" latin:keyLabelFlags="fontNormal" /> <!-- U+17BC: "ូ" KHMER VOWEL SIGN UU --> <Key - latin:keyLabel="ូ" + latin:keySpec="ូ" latin:keyLabelFlags="fontNormal" /> <!-- U+17B8: "ី" KHMER VOWEL SIGN II --> <Key - latin:keyLabel="ី" + latin:keySpec="ី" latin:keyLabelFlags="fontNormal" /> <!-- U+17C5: "ៅ" KHMER VOWEL SIGN AU --> <Key - latin:keyLabel="ៅ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ៅ" + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+1797: "ភ" KHMER LETTER PHO --> <Key - latin:keyLabel="ភ" + latin:keySpec="ភ" latin:keyLabelFlags="fontNormal" /> <!-- U+17BF: "ឿ" KHMER VOWEL SIGN YA --> <Key - latin:keyLabel="ឿ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ឿ" + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI --> <Key - latin:keyLabel="ឰ" + latin:keySpec="ឰ" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+1786: "ឆ" KHMER LETTER CHA --> <Key - latin:keyLabel="ឆ" + latin:keySpec="ឆ" latin:keyLabelFlags="fontNormal" /> <!-- U+17B9: "ឹ" KHMER VOWEL SIGN Y --> <Key - latin:keyLabel="ឹ" + latin:keySpec="ឹ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C1: "េ" KHMER VOWEL SIGN E --> <Key - latin:keyLabel="េ" + latin:keySpec="េ" latin:keyLabelFlags="fontNormal" /> <!-- U+179A: "រ" KHMER LETTER RO --> <Key - latin:keyLabel="រ" + latin:keySpec="រ" latin:keyLabelFlags="fontNormal" /> <!-- U+178F: "ត" KHMER LETTER TA --> <Key - latin:keyLabel="ត" + latin:keySpec="ត" latin:keyLabelFlags="fontNormal" /> <!-- U+1799: "យ" KHMER LETTER YO --> <Key - latin:keyLabel="យ" + latin:keySpec="យ" latin:keyLabelFlags="fontNormal" /> <!-- U+17BB: "ុ" KHMER VOWEL SIGN U --> <Key - latin:keyLabel="ុ" + latin:keySpec="ុ" latin:keyLabelFlags="fontNormal" /> <!-- U+17B7: "ិ" KHMER VOWEL SIGN I --> <Key - latin:keyLabel="ិ" + latin:keySpec="ិ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C4: "ោ" KHMER VOWEL SIGN OO --> <Key - latin:keyLabel="ោ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ោ" + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+1795: "ផ" KHMER LETTER PHA --> <Key - latin:keyLabel="ផ" + latin:keySpec="ផ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C0: "ៀ" KHMER VOWEL SIGN IE --> <Key - latin:keyLabel="ៀ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ៀ" + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+17AA: "ឪ" KHMER INDEPENDENT VOWEL QUUV U+17A7: "ឧ" KHMER INDEPENDENT VOWEL QU U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE @@ -135,7 +136,7 @@ U+17A9: "ឩ" KHMER INDEPENDENT VOWEL QUU U+17A8: "ឨ" KHMER INDEPENDENT VOWEL QUK --> <Key - latin:keyLabel="ឪ" + latin:keySpec="ឪ" latin:keyHintLabel="ឧ" latin:moreKeys="ឧ,ឱ,ឳ,ឩ,ឨ" latin:keyLabelFlags="fontNormal" /> diff --git a/java/res/xml/rowkeys_khmer3.xml b/java/res/xml/rowkeys_khmer3.xml index ff6c9ca51..5e6d01fb2 100644 --- a/java/res/xml/rowkeys_khmer3.xml +++ b/java/res/xml/rowkeys_khmer3.xml @@ -27,109 +27,109 @@ > <!-- U+17B6/U+17C6: "ាំ" KHMER VOWEL SIGN AA/KHMER SIGN NIKAHIT --> <Key - latin:keyLabel="ាំ" + latin:keySpec="ាំ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+17C3: "ៃ" KHMER VOWEL SIGN AI --> <Key - latin:keyLabel="ៃ" + latin:keySpec="ៃ" latin:keyLabelFlags="fontNormal" /> <!-- U+178C: "ឌ" KHMER LETTER DO --> <Key - latin:keyLabel="ឌ" + latin:keySpec="ឌ" latin:keyLabelFlags="fontNormal" /> <!-- U+1792: "ធ" KHMER LETTER THO --> <Key - latin:keyLabel="ធ" + latin:keySpec="ធ" latin:keyLabelFlags="fontNormal" /> <!-- U+17A2: "អ" KHMER LETTER QA --> <Key - latin:keyLabel="អ" + latin:keySpec="អ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C7: "ះ" KHMER SIGN REAHMUK - U+17C8: "ៈ" KHMER SIGN YUUKALEAPINTU;--> + U+17C8: "ៈ" KHMER SIGN YUUKALEAPINTU --> <Key - latin:keyLabel="ះ" + latin:keySpec="ះ" latin:keyHintLabel="ៈ" latin:moreKeys="ៈ" latin:keyLabelFlags="fontNormal" /> <!-- U+1789: "ញ" KHMER LETTER NYO --> <Key - latin:keyLabel="ញ" + latin:keySpec="ញ" latin:keyLabelFlags="fontNormal" /> <!-- U+1782: "គ" KHMER LETTER KO U+179D: "ឝ" KHMER LETTER SHA --> <Key - latin:keyLabel="គ" + latin:keySpec="គ" latin:keyHintLabel="ឝ" latin:moreKeys="ឝ" latin:keyLabelFlags="fontNormal" /> <!-- U+17A1: "ឡ" KHMER LETTER LA --> <Key - latin:keyLabel="ឡ" + latin:keySpec="ឡ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C4/U+17C7: "ោះ" KHMER VOWEL SIGN OO/KHMER SIGN REAHMUK --> <Key - latin:keyLabel="ោះ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ោះ" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio|autoScale" /> <!-- U+17C9: "៉" KHMER SIGN MUUSIKATOAN --> <Key - latin:keyLabel="៉" + latin:keySpec="៉" latin:keyLabelFlags="fontNormal" /> <!-- U+17AF: "ឯ" KHMER INDEPENDENT VOWEL QE --> <Key - latin:keyLabel="ឯ" + latin:keySpec="ឯ" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+17B6: "ា" KHMER VOWEL SIGN AA --> <Key - latin:keyLabel="ា" + latin:keySpec="ា" latin:keyLabelFlags="fontNormal" /> <!-- U+179F: "ស" KHMER LETTER SA --> <Key - latin:keyLabel="ស" + latin:keySpec="ស" latin:keyLabelFlags="fontNormal" /> <!-- U+178A: "ដ" KHMER LETTER DA --> <Key - latin:keyLabel="ដ" + latin:keySpec="ដ" latin:keyLabelFlags="fontNormal" /> <!-- U+1790: "ថ" KHMER LETTER THA --> <Key - latin:keyLabel="ថ" + latin:keySpec="ថ" latin:keyLabelFlags="fontNormal" /> <!-- U+1784: "ង" KHMER LETTER NGO --> <Key - latin:keyLabel="ង" + latin:keySpec="ង" latin:keyLabelFlags="fontNormal" /> <!-- U+17A0: "ហ" KHMER LETTER HA --> <Key - latin:keyLabel="ហ" + latin:keySpec="ហ" latin:keyLabelFlags="fontNormal" /> <!-- U+17D2: "្" KHMER SIGN COENG --> <Key - latin:keyLabel="្" + latin:keySpec="្" latin:keyLabelFlags="fontNormal" /> <!-- U+1780: "ក" KHMER LETTER KA --> <Key - latin:keyLabel="ក" + latin:keySpec="ក" latin:keyLabelFlags="fontNormal" /> <!-- U+179B: "ល" KHMER LETTER LO --> <Key - latin:keyLabel="ល" + latin:keySpec="ល" latin:keyLabelFlags="fontNormal" /> <!-- U+17BE: "ើ" KHMER VOWEL SIGN OE --> <Key - latin:keyLabel="ើ" + latin:keySpec="ើ" latin:keyLabelFlags="fontNormal" /> <!-- U+17CB: "់" KHMER SIGN BANTOC --> <Key - latin:keyLabel="់" + latin:keySpec="់" latin:keyLabelFlags="fontNormal" /> <!-- U+17AE: "ឮ" KHMER INDEPENDENT VOWEL LYY U+17AD: "ឭ" KHMER INDEPENDENT VOWEL LY U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI --> <Key - latin:keyLabel="ឮ" + latin:keySpec="ឮ" latin:keyHintLabel="ឭ" latin:moreKeys="ឭ,ឰ" latin:keyLabelFlags="fontNormal" /> diff --git a/java/res/xml/rowkeys_khmer4.xml b/java/res/xml/rowkeys_khmer4.xml index fe6c59125..5523d86b7 100644 --- a/java/res/xml/rowkeys_khmer4.xml +++ b/java/res/xml/rowkeys_khmer4.xml @@ -27,86 +27,86 @@ > <!-- U+178D: "ឍ" KHMER LETTER TTHO --> <Key - latin:keyLabel="ឍ" + latin:keySpec="ឍ" latin:keyLabelFlags="fontNormal" /> <!-- U+1783: "ឃ" KHMER LETTER KHO --> <Key - latin:keyLabel="ឃ" + latin:keySpec="ឃ" latin:keyLabelFlags="fontNormal" /> <!-- U+1787: "ជ" KHMER LETTER CO --> <Key - latin:keyLabel="ជ" + latin:keySpec="ជ" latin:keyLabelFlags="fontNormal" /> <!-- U+17C1/U+17C7: "េះ" KHMER VOWEL SIGN E/KHMER SIGN REAHMUK --> <Key - latin:keyLabel="េះ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="េះ" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio|autoScale" /> <!-- U+1796: "ព" KHMER LETTER PO U+179E: "ឞ" KHMER LETTER SSO --> <Key - latin:keyLabel="ព" + latin:keySpec="ព" latin:keyHintLabel="ឞ" latin:moreKeys="ឞ" latin:keyLabelFlags="fontNormal" /> <!-- U+178E: "ណ" KHMER LETTER NNO --> <Key - latin:keyLabel="ណ" - latin:keyLabelFlags="fontNormal" /> + latin:keySpec="ណ" + latin:keyLabelFlags="fontNormal|autoScale" /> <!-- U+17C6: "ំ" KHMER SIGN NIKAHIT --> <Key - latin:keyLabel="ំ" + latin:keySpec="ំ" latin:keyLabelFlags="fontNormal" /> <!-- U+17BB/U+17C7: "ុះ" KHMER VOWEL SIGN U/KHMER SIGN REAHMUK --> <Key - latin:keyLabel="ុះ" + latin:keySpec="ុះ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+17D5: "៕" KHMER SIGN BARIYOOSAN --> <Key - latin:keyLabel="៕" + latin:keySpec="៕" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="\?" /> + latin:keySpec="\?" /> </case> <default> <!-- U+178B: "ឋ" KHMER LETTER TTHA --> <Key - latin:keyLabel="ឋ" + latin:keySpec="ឋ" latin:keyLabelFlags="fontNormal" /> <!-- U+1781: "ខ" KHMER LETTER KHA --> <Key - latin:keyLabel="ខ" + latin:keySpec="ខ" latin:keyLabelFlags="fontNormal" /> <!-- U+1785: "ច" KHMER LETTER CA --> <Key - latin:keyLabel="ច" + latin:keySpec="ច" latin:keyLabelFlags="fontNormal" /> <!-- U+179C: "វ" KHMER LETTER VO --> <Key - latin:keyLabel="វ" + latin:keySpec="វ" latin:keyLabelFlags="fontNormal" /> <!-- U+1794: "ប" KHMER LETTER BA --> <Key - latin:keyLabel="ប" + latin:keySpec="ប" latin:keyLabelFlags="fontNormal" /> <!-- U+1793: "ន" KHMER LETTER NO --> <Key - latin:keyLabel="ន" + latin:keySpec="ន" latin:keyLabelFlags="fontNormal" /> <!-- U+1798: "ម" KHMER LETTER MO --> <Key - latin:keyLabel="ម" + latin:keySpec="ម" latin:keyLabelFlags="fontNormal" /> <!-- U+17BB/U+17C6: "ុំ" KHMER VOWEL SIGN U/KHMER SIGN NIKAHIT --> <Key - latin:keyLabel="ុំ" + latin:keySpec="ុំ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+17D4: "។" KHMER SIGN KHAN --> <Key - latin:keyLabel="។" + latin:keySpec="។" latin:keyLabelFlags="fontNormal" /> <!-- U+17CA: "៊" KHMER SIGN TRIISAP --> <Key - latin:keyLabel="៊" + latin:keySpec="៊" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_lao1.xml b/java/res/xml/rowkeys_lao1.xml index fa1ad97d8..a5085a540 100644 --- a/java/res/xml/rowkeys_lao1.xml +++ b/java/res/xml/rowkeys_lao1.xml @@ -27,58 +27,58 @@ > <!-- U+0ED1: "໑" LAO DIGIT ONE --> <Key - latin:keyLabel="໑" + latin:keySpec="໑" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED2: "໒" LAO DIGIT TWO --> <Key - latin:keyLabel="໒" + latin:keySpec="໒" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED3: "໓" LAO DIGIT THREE --> <Key - latin:keyLabel="໓" + latin:keySpec="໓" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED4: "໔" LAO DIGIT FOUR --> <Key - latin:keyLabel="໔" + latin:keySpec="໔" latin:keyLabelFlags="fontNormal" /> <!-- U+0ECC: "໌" LAO CANCELLATION MARK --> <Key - latin:keyLabel="໌" + latin:keySpec="໌" latin:keyLabelFlags="fontNormal" /> <!-- U+0EBC: "ຼ" LAO SEMIVOWEL SIGN LO --> <Key - latin:keyLabel="ຼ" + latin:keySpec="ຼ" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED5: "໕" LAO DIGIT FIVE --> <Key - latin:keyLabel="໕" + latin:keySpec="໕" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED6: "໖" LAO DIGIT SIX --> <Key - latin:keyLabel="໖" + latin:keySpec="໖" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED7: "໗" LAO DIGIT SEVEN --> <Key - latin:keyLabel="໗" + latin:keySpec="໗" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED8: "໘" LAO DIGIT EIGHT --> <Key - latin:keyLabel="໘" + latin:keySpec="໘" latin:keyLabelFlags="fontNormal" /> <!-- U+0ED9: "໙" LAO DIGIT NINE --> <Key - latin:keyLabel="໙" + latin:keySpec="໙" latin:keyLabelFlags="fontNormal" /> <!-- U+0ECD/U+0EC8: "ໍ່" LAO NIGGAHITA/LAO TONE MAI EK --> <Key - latin:keyLabel="ໍ່" + latin:keySpec="ໍ່" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </case> <default> <!-- U+0EA2: "ຢ" LAO LETTER YO U+0ED1: "໑" LAO DIGIT ONE --> <Key - latin:keyLabel="ຢ" + latin:keySpec="ຢ" latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys="໑" @@ -86,7 +86,7 @@ <!-- U+0E9F: "ຟ" LAO LETTER FO SUNG U+0ED2: "໒" LAO DIGIT TWO --> <Key - latin:keyLabel="ຟ" + latin:keySpec="ຟ" latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="໒" @@ -94,7 +94,7 @@ <!-- U+0EC2: "ໂ" LAO VOWEL SIGN O U+0ED3: "໓" LAO DIGIT THREE --> <Key - latin:keyLabel="ໂ" + latin:keySpec="ໂ" latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys="໓" @@ -102,23 +102,23 @@ <!-- U+0E96: "ຖ" LAO LETTER THO SUNG U+0ED4: "໔" LAO DIGIT FOUR --> <Key - latin:keyLabel="ຖ" + latin:keySpec="ຖ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" latin:moreKeys="໔" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB8: "ຸ" LAO VOWEL SIGN U --> <Key - latin:keyLabel="ຸ" + latin:keySpec="ຸ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB9: "ູ" LAO VOWEL SIGN UU --> <Key - latin:keyLabel="ູ" + latin:keySpec="ູ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E84: "ຄ" LAO LETTER KHO TAM U+0ED5: "໕" LAO DIGIT FIVE --> <Key - latin:keyLabel="ຄ" + latin:keySpec="ຄ" latin:keyHintLabel="5" latin:additionalMoreKeys="5" latin:moreKeys="໕" @@ -126,7 +126,7 @@ <!-- U+0E95: "ຕ" LAO LETTER TO U+0ED6: "໖" LAO DIGIT SIX --> <Key - latin:keyLabel="ຕ" + latin:keySpec="ຕ" latin:keyHintLabel="6" latin:additionalMoreKeys="6" latin:moreKeys="໖" @@ -134,7 +134,7 @@ <!-- U+0E88: "ຈ" LAO LETTER CO U+0ED7: "໗" LAO DIGIT SEVEN --> <Key - latin:keyLabel="ຈ" + latin:keySpec="ຈ" latin:keyHintLabel="7" latin:additionalMoreKeys="7" latin:moreKeys="໗" @@ -142,7 +142,7 @@ <!-- U+0E82: "ຂ" LAO LETTER KHO SUNG U+0ED8: "໘" LAO DIGIT EIGHT --> <Key - latin:keyLabel="ຂ" + latin:keySpec="ຂ" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:moreKeys="໘" @@ -150,14 +150,14 @@ <!-- U+0E8A: "ຊ" LAO LETTER SO TAM U+0ED9: "໙" LAO DIGIT NINE --> <Key - latin:keyLabel="ຊ" + latin:keySpec="ຊ" latin:keyHintLabel="9" latin:additionalMoreKeys="9" latin:moreKeys="໙" latin:keyLabelFlags="fontNormal" /> <!-- U+0ECD: "ໍ" LAO NIGGAHITA --> <Key - latin:keyLabel="ໍ" + latin:keySpec="ໍ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_lao2.xml b/java/res/xml/rowkeys_lao2.xml index fca58ac0e..67c474f98 100644 --- a/java/res/xml/rowkeys_lao2.xml +++ b/java/res/xml/rowkeys_lao2.xml @@ -27,100 +27,100 @@ > <!-- U+0EBB/U+0EC9: "" LAO VOWEL SIGN MAI KON/LAO TONE MAI THO --> <Key - latin:keyLabel="ົ້" + latin:keySpec="ົ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0ED0: "໐" LAO DIGIT ZERO --> <Key - latin:keyLabel="໐" + latin:keySpec="໐" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB3/U+0EC9: "ຳ້" LAO VOWEL SIGN AM/LAO TONE MAI THO --> <Key - latin:keyLabel="ຳ້" + latin:keySpec="ຳ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <Key - latin:keyLabel="_" /> + latin:keySpec="_" /> <Key - latin:keyLabel="+" /> + latin:keySpec="+" /> <!-- U+0EB4/U+0EC9: "ິ້" LAO VOWEL SIGN I/LAO TONE MAI THO --> <Key - latin:keyLabel="ິ້" + latin:keySpec="ິ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0EB5/U+0EC9: "ີ້" LAO VOWEL SIGN II/LAO TONE MAI THO --> <Key - latin:keyLabel="ີ້" + latin:keySpec="ີ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0EA3: "ຣ" LAO LETTER LO LING --> <Key - latin:keyLabel="ຣ" + latin:keySpec="ຣ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EDC: "ໜ" LAO HO NO --> <Key - latin:keyLabel="ໜ" + latin:keySpec="ໜ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EBD: "ຽ" LAO SEMIVOWEL SIGN NYO --> <Key - latin:keyLabel="ຽ" + latin:keySpec="ຽ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EAB/U+0EBC: "" LAO LETTER HO SUNG/LAO SEMIVOWEL SIGN LO --> <Key - latin:keyLabel="ຫຼ" + latin:keySpec="ຫຼ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+201D: "”" RIGHT DOUBLE QUOTATION MARK --> <Key - latin:keyLabel="”" /> + latin:keySpec="”" /> </case> <default> <!-- U+0EBB: "ົ" LAO VOWEL SIGN MAI KON --> <Key - latin:keyLabel="ົ" + latin:keySpec="ົ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC4: "ໄ" LAO VOWEL SIGN AI U+0ED0: "໐" LAO DIGIT ZERO --> <Key - latin:keyLabel="ໄ" + latin:keySpec="ໄ" latin:keyHintLabel="0" latin:additionalMoreKeys="0" latin:moreKeys="໐" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB3: "ຳ" LAO VOWEL SIGN AM --> <Key - latin:keyLabel="ຳ" + latin:keySpec="ຳ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E9E: "ພ" LAO LETTER PHO TAM --> <Key - latin:keyLabel="ພ" + latin:keySpec="ພ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB0: "ະ" LAO VOWEL SIGN A --> <Key - latin:keyLabel="ະ" + latin:keySpec="ະ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB4: "ິ" LAO VOWEL SIGN I --> <Key - latin:keyLabel="ິ" + latin:keySpec="ິ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB5: "ີ" LAO VOWEL SIGN II --> <Key - latin:keyLabel="ີ" + latin:keySpec="ີ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EAE: "ຮ" LAO LETTER HO TAM --> <Key - latin:keyLabel="ຮ" + latin:keySpec="ຮ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E99: "ນ" LAO LETTER NO --> <Key - latin:keyLabel="ນ" + latin:keySpec="ນ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E8D: "ຍ" LAO LETTER NYO --> <Key - latin:keyLabel="ຍ" + latin:keySpec="ຍ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E9A: "ບ" LAO LETTER BO --> <Key - latin:keyLabel="ບ" + latin:keySpec="ບ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EA5: "ລ" LAO LETTER LO LOOT --> <Key - latin:keyLabel="ລ" + latin:keySpec="ລ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_lao3.xml b/java/res/xml/rowkeys_lao3.xml index 2a6c2d1dd..172716dde 100644 --- a/java/res/xml/rowkeys_lao3.xml +++ b/java/res/xml/rowkeys_lao3.xml @@ -27,84 +27,84 @@ > <!-- U+0EB1/U+0EC9: "ັ້" LAO VOWEL SIGN MAI KAN/LAO TONE MAI THO --> <Key - latin:keyLabel="ັ້" + latin:keySpec="ັ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <Key - latin:keyLabel=";" /> + latin:keySpec=";" /> <Key - latin:keyLabel="." /> + latin:keySpec="." /> <Key - latin:keyLabel="," /> + latin:keySpec="," /> <Key - latin:keyLabel=":" /> + latin:keySpec=":" /> <!-- U+0ECA: "໊" LAO TONE MAI TI --> <Key - latin:keyLabel="໊" + latin:keySpec="໊" latin:keyLabelFlags="fontNormal" /> <!-- U+0ECB: "໋" LAO TONE MAI CATAWA --> <Key - latin:keyLabel="໋" + latin:keySpec="໋" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="!" /> + latin:keySpec="!" /> <Key - latin:keyLabel="\?" /> + latin:keySpec="\?" /> <Key - latin:keyLabel="%" /> + latin:keySpec="%" /> <Key - latin:keyLabel="=" /> + latin:keySpec="=" /> <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK --> <Key - latin:keyLabel="“" /> + latin:keySpec="“" /> </case> <default> <!-- U+0EB1: "ັ" LAO VOWEL SIGN MAI KAN --> <Key - latin:keyLabel="ັ" + latin:keySpec="ັ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EAB: "ຫ" LAO LETTER HO SUNG --> <Key - latin:keyLabel="ຫ" + latin:keySpec="ຫ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E81: "ກ" LAO LETTER KO --> <Key - latin:keyLabel="ກ" + latin:keySpec="ກ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E94: "ດ" LAO LETTER DO --> <Key - latin:keyLabel="ດ" + latin:keySpec="ດ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC0: "ເ" LAO VOWEL SIGN E --> <Key - latin:keyLabel="ເ" + latin:keySpec="ເ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC9: "້" LAO TONE MAI THO --> <Key - latin:keyLabel="້" + latin:keySpec="້" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC8: "່" LAO TONE MAI EK --> <Key - latin:keyLabel="່" + latin:keySpec="່" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB2: "າ" LAO VOWEL SIGN AA --> <Key - latin:keyLabel="າ" + latin:keySpec="າ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EAA: "ສ" LAO LETTER SO SUNG --> <Key - latin:keyLabel="ສ" + latin:keySpec="ສ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EA7: "ວ" LAO LETTER WO --> <Key - latin:keyLabel="ວ" + latin:keySpec="ວ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E87: "ງ" LAO LETTER NGO --> <Key - latin:keyLabel="ງ" + latin:keySpec="ງ" latin:keyLabelFlags="fontNormal" /> <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK --> <Key - latin:keyLabel="“" /> + latin:keySpec="“" /> </default> </switch> </merge> diff --git a/java/res/xml/rowkeys_lao4.xml b/java/res/xml/rowkeys_lao4.xml index fae9cc923..ed4b9b1f1 100644 --- a/java/res/xml/rowkeys_lao4.xml +++ b/java/res/xml/rowkeys_lao4.xml @@ -27,76 +27,76 @@ > <!-- U+20AD: "₭" KIP SIGN --> <Key - latin:keyLabel="₭" /> + latin:keySpec="₭" /> <Key - latin:keyLabel="(" /> + latin:keySpec="(" /> <!-- U+0EAF: "ຯ" LAO ELLIPSIS --> <Key - latin:keyLabel="ຯ" + latin:keySpec="ຯ" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="\@" /> + latin:keySpec="\@" /> <!-- U+0EB6/U+0EC9: "ຶ້" LAO VOWEL SIGN Y/LAO TONE MAI THO --> <Key - latin:keyLabel="ຶ້" + latin:keySpec="ຶ້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0EB7/U+0EC9: "ື້" LAO VOWEL SIGN YY/LAO TONE MAI THO --> <Key - latin:keyLabel="ື້" + latin:keySpec="ື້" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0EC6: "ໆ" LAO KO LA --> <Key - latin:keyLabel="ໆ" + latin:keySpec="ໆ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EDD: "ໝ" LAO HO MO --> <Key - latin:keyLabel="ໝ" + latin:keySpec="ໝ" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="$" /> + latin:keySpec="$" /> <Key - latin:keyLabel=")" /> + latin:keySpec=")" /> </case> <default> <!-- U+0E9C: "ຜ" LAO LETTER PHO SUNG --> <Key - latin:keyLabel="ຜ" + latin:keySpec="ຜ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E9B: "ປ" LAO LETTER PO --> <Key - latin:keyLabel="ປ" + latin:keySpec="ປ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC1: "ແ" LAO VOWEL SIGN EI --> <Key - latin:keyLabel="ແ" + latin:keySpec="ແ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EAD: "ອ" LAO LETTER O --> <Key - latin:keyLabel="ອ" + latin:keySpec="ອ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB6: "ຶ" LAO VOWEL SIGN Y --> <Key - latin:keyLabel="ຶ" + latin:keySpec="ຶ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EB7: "ື" LAO VOWEL SIGN YY --> <Key - latin:keyLabel="ື" + latin:keySpec="ື" latin:keyLabelFlags="fontNormal" /> <!-- U+0E97: "ທ" LAO LETTER THO TAM --> <Key - latin:keyLabel="ທ" + latin:keySpec="ທ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EA1: "ມ" LAO LETTER MO --> <Key - latin:keyLabel="ມ" + latin:keySpec="ມ" latin:keyLabelFlags="fontNormal" /> <!-- U+0EC3: "ໃ" LAO VOWEL SIGN AY --> <Key - latin:keyLabel="ໃ" + latin:keySpec="ໃ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E9D: "ຝ" LAO LETTER FO TAM --> <Key - latin:keyLabel="ຝ" + latin:keySpec="ຝ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_mongolian1.xml b/java/res/xml/rowkeys_mongolian1.xml index 6c8c8e2fd..2bd8097e2 100644 --- a/java/res/xml/rowkeys_mongolian1.xml +++ b/java/res/xml/rowkeys_mongolian1.xml @@ -23,61 +23,61 @@ > <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF --> <Key - latin:keyLabel="ф" + latin:keySpec="ф" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE --> <Key - latin:keyLabel="ц" + latin:keySpec="ц" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+0443: "у" CYRILLIC SMALL LETTER U --> <Key - latin:keyLabel="у" + latin:keySpec="у" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_cyrillic_u" /> + latin:moreKeys="!text/morekeys_cyrillic_u" /> <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key - latin:keyLabel="ж" + latin:keySpec="ж" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> <Key - latin:keyLabel="э" + latin:keySpec="э" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_cyrillic_ie" /> + latin:moreKeys="!text/morekeys_cyrillic_ie" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key - latin:keyLabel="н" + latin:keySpec="н" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_cyrillic_en" /> + latin:moreKeys="!text/morekeys_cyrillic_en" /> <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE --> <Key - latin:keyLabel="г" + latin:keySpec="г" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_cyrillic_ghe" /> + latin:moreKeys="!text/morekeys_cyrillic_ghe" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> <Key - latin:keyLabel="ш" + latin:keySpec="ш" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:moreKeys="щ" /> <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U --> <Key - latin:keyLabel="ү" + latin:keySpec="ү" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> <Key - latin:keyLabel="з" + latin:keySpec="з" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> <!-- U+043A: "к" CYRILLIC SMALL LETTER KA --> <Key - latin:keyLabel="к" /> + latin:keySpec="к" /> </merge> diff --git a/java/res/xml/rowkeys_mongolian2.xml b/java/res/xml/rowkeys_mongolian2.xml index a8aa00620..f11f4f230 100644 --- a/java/res/xml/rowkeys_mongolian2.xml +++ b/java/res/xml/rowkeys_mongolian2.xml @@ -23,35 +23,35 @@ > <!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I --> <Key - latin:keyLabel="й" /> + latin:keySpec="й" /> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> <Key - latin:keyLabel="ы" /> + latin:keySpec="ы" /> <!-- U+0431: "б" CYRILLIC SMALL LETTER BE --> <Key - latin:keyLabel="б" /> + latin:keySpec="б" /> <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O --> <Key - latin:keyLabel="ө" /> + latin:keySpec="ө" /> <!-- U+0430: "а" CYRILLIC SMALL LETTER A --> <Key - latin:keyLabel="а" /> + latin:keySpec="а" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" /> + latin:keySpec="х" /> <!-- U+0440: "р" CYRILLIC SMALL LETTER ER --> <Key - latin:keyLabel="р" /> + latin:keySpec="р" /> <!-- U+043E: "о" CYRILLIC SMALL LETTER O --> <Key - latin:keyLabel="о" /> + latin:keySpec="о" /> <!-- U+043B: "л" CYRILLIC SMALL LETTER EL --> <Key - latin:keyLabel="л" /> + latin:keySpec="л" /> <!-- U+0434: "д" CYRILLIC SMALL LETTER DE --> <Key - latin:keyLabel="д" /> + latin:keySpec="д" /> <!-- U+043F: "п" CYRILLIC SMALL LETTER PE --> <Key - latin:keyLabel="п" /> + latin:keySpec="п" /> </merge> diff --git a/java/res/xml/rowkeys_mongolian3.xml b/java/res/xml/rowkeys_mongolian3.xml index dc80c37ab..cf57d1c2a 100644 --- a/java/res/xml/rowkeys_mongolian3.xml +++ b/java/res/xml/rowkeys_mongolian3.xml @@ -23,35 +23,35 @@ > <!-- U+044F: "я" CYRILLIC SMALL LETTER YA --> <Key - latin:keyLabel="я" /> + latin:keySpec="я" /> <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE --> <Key - latin:keyLabel="ч" /> + latin:keySpec="ч" /> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO U+0435: "е" CYRILLIC SMALL LETTER IE --> <Key - latin:keyLabel="ё" + latin:keySpec="ё" latin:moreKeys="е" /> <!-- U+0441: "с" CYRILLIC SMALL LETTER ES --> <Key - latin:keyLabel="с" /> + latin:keySpec="с" /> <!-- U+043C: "м" CYRILLIC SMALL LETTER EM --> <Key - latin:keyLabel="м" /> + latin:keySpec="м" /> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> <Key - latin:keyLabel="и" /> + latin:keySpec="и" /> <!-- U+0442: "т" CYRILLIC SMALL LETTER TE --> <Key - latin:keyLabel="т" /> + latin:keySpec="т" /> <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> <Key - latin:keyLabel="ь" + latin:keySpec="ь" latin:moreKeys="ъ" /> <!-- U+0432: "в" CYRILLIC SMALL LETTER VE U+044E: "ю" CYRILLIC SMALL LETTER YU --> <Key - latin:keyLabel="в" + latin:keySpec="в" latin:moreKeys="ю" /> </merge> diff --git a/java/res/xml/rowkeys_myanmar1.xml b/java/res/xml/rowkeys_myanmar1.xml new file mode 100644 index 000000000..b7c820922 --- /dev/null +++ b/java/res/xml/rowkeys_myanmar1.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" + > + <!-- U+1027: "ဧ" MYANMAR LETTER E --> + <Key + latin:keySpec="ဧ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+104F: "၏" MYANMAR SYMBOL GENITIVE --> + <Key + latin:keySpec="၏" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1024: "ဤ" MYANMAR LETTER II --> + <Key + latin:keySpec="ဤ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1023: "ဣ" MYANMAR LETTER I --> + <Key + latin:keySpec="ဣ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+104E: "၎" MYANMAR SYMBOL AFOREMENTIONED --> + <Key + latin:keySpec="၎" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1000/U+103B/U+1015/U+103A: "ကျပ်" + MYANMAR LETTER KA/MYANMAR CONSONANT SIGN MEDIAL YA/MYANMAR LETTER PA/MYANMAR SIGN ASAT --> + <Key + latin:keySpec="ကျပ်" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio|autoScale" /> + <!-- U+1029: "ဩ" MYANMAR LETTER O --> + <Key + latin:keySpec="ဩ" + latin:keyLabelFlags="fontNormal|autoScale" /> + <!-- U+102A: "ဪ" MYANMAR LETTER AU --> + <Key + latin:keySpec="ဪ" + latin:keyLabelFlags="fontNormal|autoScale" /> + <!-- U+104D: "၍" MYANMAR SYMBOL COMPLETED --> + <Key + latin:keySpec="၍" + latin:keyLabelFlags="fontNormal" /> + <!-- U+104C: "၌" MYANMAR SYMBOL LOCATIVE --> + <Key + latin:keySpec="၌" + latin:keyLabelFlags="fontNormal" /> + </case> + <default> + <!-- U+1041: "၁" MYANMAR DIGIT ONE --> + <Key + latin:keySpec="၁" + latin:keyHintLabel="1" + latin:additionalMoreKeys="1" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1042: "၂" MYANMAR DIGIT TWO --> + <Key + latin:keySpec="၂" + latin:keyHintLabel="2" + latin:additionalMoreKeys="2" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1043: "၃" MYANMAR DIGIT THREE --> + <Key + latin:keySpec="၃" + latin:keyHintLabel="3" + latin:additionalMoreKeys="3" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1044: "၄" MYANMAR DIGIT FOUR --> + <Key + latin:keySpec="၄" + latin:keyHintLabel="4" + latin:additionalMoreKeys="4" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1045: "၅" MYANMAR DIGIT FIVE --> + <Key + latin:keySpec="၅" + latin:keyHintLabel="5" + latin:additionalMoreKeys="5" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1046: "၆" MYANMAR DIGIT SIX --> + <Key + latin:keySpec="၆" + latin:keyHintLabel="6" + latin:additionalMoreKeys="6" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1047: "၇" MYANMAR DIGIT SEVEN --> + <Key + latin:keySpec="၇" + latin:keyHintLabel="7" + latin:additionalMoreKeys="7" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1048: "၈" MYANMAR DIGIT EIGHT --> + <Key + latin:keySpec="၈" + latin:keyHintLabel="8" + latin:additionalMoreKeys="8" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1049: "၉" MYANMAR DIGIT NINE --> + <Key + latin:keySpec="၉" + latin:keyHintLabel="9" + latin:additionalMoreKeys="9" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1040: "၀" MYANMAR DIGIT ZERO --> + <Key + latin:keySpec="၀" + latin:keyHintLabel="0" + latin:additionalMoreKeys="0" + latin:keyLabelFlags="fontNormal" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/rowkeys_myanmar2.xml b/java/res/xml/rowkeys_myanmar2.xml new file mode 100644 index 000000000..5f0115f39 --- /dev/null +++ b/java/res/xml/rowkeys_myanmar2.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" + > + <!-- U+1017: "ဗ" MYANMAR LETTER BA --> + <Key + latin:keySpec="ဗ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1012: "ဒ" MYANMAR LETTER DA --> + <Key + latin:keySpec="ဒ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1013: "ဓ" MYANMAR LETTER DHA --> + <Key + latin:keySpec="ဓ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1003: "ဃ" MYANMAR LETTER GHA --> + <Key + latin:keySpec="ဃ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100E: "ဎ" MYANMAR LETTER DDHA --> + <Key + latin:keySpec="ဎ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+103F: "ဿ" MYANMAR LETTER GREAT SA --> + <Key + latin:keySpec="ဿ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100F: "ဏ" MYANMAR LETTER NNA --> + <Key + latin:keySpec="ဏ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1008: "ဈ" MYANMAR LETTER JHA --> + <Key + latin:keySpec="ဈ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1007: "ဇ" MYANMAR LETTER JA --> + <Key + latin:keySpec="ဇ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1002: "ဂ" MYANMAR LETTER GA --> + <Key + latin:keySpec="ဂ" + latin:keyLabelFlags="fontNormal" /> + </case> + <default> + <!-- U+1006: "ဆ" MYANMAR LETTER CHA --> + <Key + latin:keySpec="ဆ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1010: "တ" MYANMAR LETTER TA --> + <Key + latin:keySpec="တ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1014: "န" MYANMAR LETTER NA --> + <Key + latin:keySpec="န" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1019: "မ" MYANMAR LETTER MA --> + <Key + latin:keySpec="မ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1021: "အ" MYANMAR LETTER A --> + <Key + latin:keySpec="အ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1015: "ပ" MYANMAR LETTER PA --> + <Key + latin:keySpec="ပ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1000: "က" MYANMAR LETTER KA --> + <Key + latin:keySpec="က" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1004: "င" MYANMAR LETTER NGA --> + <Key + latin:keySpec="င" + latin:keyLabelFlags="fontNormal" /> + <!-- U+101E: "သ" MYANMAR LETTER SA --> + <Key + latin:keySpec="သ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1005: "စ" MYANMAR LETTER CA --> + <Key + latin:keySpec="စ" + latin:keyLabelFlags="fontNormal" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/rowkeys_myanmar3.xml b/java/res/xml/rowkeys_myanmar3.xml new file mode 100644 index 000000000..612bcd31b --- /dev/null +++ b/java/res/xml/rowkeys_myanmar3.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" + > + <!-- U+101A: "ယ" MYANMAR LETTER YA --> + <Key + latin:keySpec="ယ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1039: "္" MYANMAR SIGN VIRAMA --> + <Key + latin:keySpec="္" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1004/U+103A/U+1039: "င်္င" MYANMAR LETTER NGA/MYANMAR SIGN ASAT/MYANMAR SIGN VIRAMA --> + <Key + latin:keySpec="င်္" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> + <!-- U+103E: "ှ" MYANMAR CONSONANT SIGN MEDIAL HA --> + <Key + latin:keySpec="ှ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+102E: "ီ" MYANMAR VOWEL SIGN II --> + <Key + latin:keySpec="ီ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1030: "ူ" MYANMAR VOWEL SIGN UU --> + <Key + latin:keySpec="ူ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+102B: "ါ" MYANMAR VOWEL SIGN TALL AA --> + <Key + latin:keySpec="ါ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1032: "ဲ" MYANMAR VOWEL SIGN AI --> + <Key + latin:keySpec="ဲ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1036: "ံ" MYANMAR SIGN ANUSVARA --> + <Key + latin:keySpec="ံ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+101F: "ဟ" MYANMAR LETTER HA --> + <Key + latin:keySpec="ဟ" + latin:keyLabelFlags="fontNormal" /> + </case> + <default> + <!-- U+1031: "ေ" MYANMAR VOWEL SIGN E --> + <Key + latin:keySpec="ေ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+103B: "ျ" MYANMAR CONSONANT SIGN MEDIAL YA --> + <Key + latin:keySpec="ျ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+103C: "ြ" MYANMAR CONSONANT SIGN MEDIAL RA --> + <Key + latin:keySpec="ြ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+103D: "ွ" MYANMAR CONSONANT SIGN MEDIAL WA + U+103E: "ှ" MYANMAR CONSONANT SIGN MEDIAL HA + U+103D/U+103E: "ွှ" MYANMAR CONSONANT SIGN MEDIAL WA/MYANMAR CONSONANT SIGN MEDIAL HA --> + <Key + latin:keySpec="ွ" + latin:moreKeys="ှ,ွှ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+102D: "ိ" MYANMAR VOWEL SIGN I + U+102E: "ီ" MYANMAR VOWEL SIGN II --> + <Key + latin:keySpec="ိ" + latin:moreKeys="ီ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+102F: "ု" MYANMAR VOWEL SIGN U + U+1030: "ူ" MYANMAR VOWEL SIGN UU --> + <Key + latin:keySpec="ု" + latin:moreKeys="ူ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+102C: "ာ" MYANMAR VOWEL SIGN AA --> + <Key + latin:keySpec="ာ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+103A: "်" MYANMAR SIGN ASAT + U+1032: "ဲ" MYANMAR VOWEL SIGN AI --> + <Key + latin:keySpec="်" + latin:moreKeys="ဲ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1037: "့" MYANMAR SIGN DOT BELOW + U+1036: "ံ" MYANMAR SIGN ANUSVARA --> + <Key + latin:keySpec="့" + latin:moreKeys="ံ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1038: "း" MYANMAR SIGN VISARGA --> + <Key + latin:keySpec="း" + latin:keyLabelFlags="fontNormal" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/rowkeys_myanmar4.xml b/java/res/xml/rowkeys_myanmar4.xml new file mode 100644 index 000000000..57466c565 --- /dev/null +++ b/java/res/xml/rowkeys_myanmar4.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" + > + <!-- U+1025: "ဥ" MYANMAR LETTER U --> + <Key + latin:keySpec="ဥ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1026: "ဦ" MYANMAR LETTER UU --> + <Key + latin:keySpec="ဦ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100C: "ဌ" MYANMAR LETTER TTHA --> + <Key + latin:keySpec="ဌ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100B: "ဋ" MYANMAR LETTER TTA --> + <Key + latin:keySpec="ဋ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100D: "ဍ" MYANMAR LETTER DDA --> + <Key + latin:keySpec="ဍ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1020: "ဠ" MYANMAR LETTER LLA --> + <Key + latin:keySpec="ဠ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100B/U+1039/U+100C: "ဋ္ဌ" MYANMAR LETTER TTA/MYANMAR SIGN VIRAMA/MYANMAR LETTER TTHA --> + <Key + latin:keySpec="ဋ္ဌ" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> + <!-- U+100F/U+1039/U+100D: "ဏ္ဍ" MYANMAR LETTER NNA/MYANMAR SIGN VIRAMA/MYANMAR LETTER DDA + U+100F/U+1039/U+100C: "ဏ္ဌ" MYANMAR LETTER NNA/MYANMAR SIGN VIRAMA/MYANMAR LETTER TTHA --> + <Key + latin:keySpec="ဏ္ဍ" + latin:moreKeys="ဏ္ဌ" + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> + </case> + <default> + <!-- U+1016: "ဖ" MYANMAR LETTER PHA --> + <Key + latin:keySpec="ဖ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1011: "ထ" MYANMAR LETTER THA --> + <Key + latin:keySpec="ထ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1001: "ခ" MYANMAR LETTER KHA --> + <Key + latin:keySpec="ခ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+101C: "လ" MYANMAR LETTER LA --> + <Key + latin:keySpec="လ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+1018: "ဘ" MYANMAR LETTER BHA --> + <Key + latin:keySpec="ဘ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+100A: "ည" MYANMAR LETTER NNYA + U+1009: "ဉ" MYANMAR LETTER NYA --> + <Key + latin:keySpec="ည" + latin:moreKeys="ဉ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+101B: "ရ" MYANMAR LETTER RA --> + <Key + latin:keySpec="ရ" + latin:keyLabelFlags="fontNormal" /> + <!-- U+101D: "ဝ" MYANMAR LETTER WA --> + <Key + latin:keySpec="ဝ" + latin:keyLabelFlags="fontNormal" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/rowkeys_nepali_romanized1.xml b/java/res/xml/rowkeys_nepali_romanized1.xml index 408a96648..616b259a3 100644 --- a/java/res/xml/rowkeys_nepali_romanized1.xml +++ b/java/res/xml/rowkeys_nepali_romanized1.xml @@ -27,11 +27,11 @@ > <!-- U+0920: "ठ" DEVANAGARI LETTER TTHA --> <Key - latin:keyLabel="ठ" + latin:keySpec="ठ" latin:keyLabelFlags="fontNormal" /> <!-- U+0914: "औ" DEVANAGARI LETTER AU --> <Key - latin:keyLabel="औ" + latin:keySpec="औ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -44,14 +44,16 @@ render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" /> + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_vocalic_r" /> + <Key + latin:keyStyle="baseKeyDevanagariVowelSignVocalicR" /> <!-- U+0925: "थ" DEVANAGARI LETTER THA --> <Key - latin:keyLabel="थ" + latin:keySpec="थ" latin:keyLabelFlags="fontNormal" /> <!-- U+091E: "ञ" DEVANAGARI LETTER NYA --> <Key - latin:keyLabel="ञ" + latin:keySpec="ञ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -69,33 +71,37 @@ latin:keyStyle="baseKeyDevanagariVowelSignIi" /> <!-- U+0913: "ओ" DEVANAGARI LETTER O --> <Key - latin:keyLabel="ओ" + latin:keySpec="ओ" latin:keyLabelFlags="fontNormal" /> <!-- U+092B: "फ" DEVANAGARI LETTER PHA --> <Key - latin:keyLabel="फ" + latin:keySpec="फ" latin:keyLabelFlags="fontNormal" /> <!-- U+0908: "ई" DEVANAGARI LETTER II --> <Key - latin:keyLabel="ई" + latin:keySpec="ई" latin:keyLabelFlags="fontNormal" /> </case> <default> + <!-- Because the font rendering system prior to API version 16 can't automatically + render dotted circle for incomplete combining letter of some scripts, different + set of Key definitions are needed based on the API version. --> + <include + latin:keyboardLayout="@xml/keystyle_devanagari_sign_nukta" /> <!-- U+091F: "ट" DEVANAGARI LETTER TTA - U+0967: "१" DEVANAGARI DIGIT ONE - U+093C: "़" DEVANAGARI SIGN NUKTA --> + U+0967: "१" DEVANAGARI DIGIT ONE --> <Key - latin:keyLabel="ट" + latin:keySpec="ट" latin:keyHintLabel="1" latin:additionalMoreKeys="१,1" - latin:moreKeys="़" + latin:keyStyle="moreKeysDevanagariSignNukta" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" /> + <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> <Key latin:keyStyle="baseKeyDevanagariVowelSignAu" latin:keyHintLabel="2" @@ -103,9 +109,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" /> + <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> <Key latin:keyStyle="baseKeyDevanagariVowelSignE" latin:keyHintLabel="3" @@ -113,30 +119,30 @@ <!-- U+0930: "र" DEVANAGARI LETTER RA U+096A: "४" DEVANAGARI DIGIT FOUR --> <Key - latin:keyLabel="र" + latin:keySpec="र" latin:keyHintLabel="4" latin:additionalMoreKeys="४,4" latin:keyLabelFlags="fontNormal" /> <!-- U+0924: "त" DEVANAGARI LETTER TA U+096B: "५" DEVANAGARI DIGIT FIVE --> <Key - latin:keyLabel="त" + latin:keySpec="त" latin:keyHintLabel="5" latin:additionalMoreKeys="५,5" latin:keyLabelFlags="fontNormal" /> <!-- U+092F: "य" DEVANAGARI LETTER YA U+096C: "६" DEVANAGARI DIGIT SIX --> <Key - latin:keyLabel="य" + latin:keySpec="य" latin:keyHintLabel="6" latin:additionalMoreKeys="६,6" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_u" /> + <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN --> <Key latin:keyStyle="baseKeyDevanagariVowelSignU" latin:keyHintLabel="7" @@ -144,9 +150,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_i" /> + <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT --> <Key latin:keyStyle="baseKeyDevanagariVowelSignI" latin:keyHintLabel="8" @@ -154,9 +160,9 @@ <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+096F: "९" DEVANAGARI DIGIT NINE --> <include latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_o" /> + <!-- U+096F: "९" DEVANAGARI DIGIT NINE --> <Key latin:keyStyle="baseKeyDevanagariVowelSignO" latin:keyHintLabel="9" @@ -164,13 +170,13 @@ <!-- U+092A: "प" DEVANAGARI LETTER PA U+0966: "०" DEVANAGARI DIGIT ZERO --> <Key - latin:keyLabel="प" + latin:keySpec="प" latin:keyHintLabel="0" latin:additionalMoreKeys="०,0" latin:keyLabelFlags="fontNormal" /> <!-- U+0907: "इ" DEVANAGARI LETTER I --> <Key - latin:keyLabel="इ" + latin:keySpec="इ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_nepali_romanized2.xml b/java/res/xml/rowkeys_nepali_romanized2.xml index 66359ffb5..561ae6c93 100644 --- a/java/res/xml/rowkeys_nepali_romanized2.xml +++ b/java/res/xml/rowkeys_nepali_romanized2.xml @@ -27,43 +27,43 @@ > <!-- U+0906: "आ" DEVANAGARI LETTER AA --> <Key - latin:keyLabel="आ" + latin:keySpec="आ" latin:keyLabelFlags="fontNormal" /> <!-- U+0936: "श" DEVANAGARI LETTER SHA --> <Key - latin:keyLabel="श" + latin:keySpec="श" latin:keyLabelFlags="fontNormal" /> <!-- U+0927: "ध" DEVANAGARI LETTER DHA --> <Key - latin:keyLabel="ध" + latin:keySpec="ध" latin:keyLabelFlags="fontNormal" /> <!-- U+090A: "ऊ" DEVANAGARI LETTER UU --> <Key - latin:keyLabel="ऊ" + latin:keySpec="ऊ" latin:keyLabelFlags="fontNormal" /> <!-- U+0918: "घ" DEVANAGARI LETTER GHA --> <Key - latin:keyLabel="घ" + latin:keySpec="घ" latin:keyLabelFlags="fontNormal" /> <!-- U+0905: "अ" DEVANAGARI LETTER A --> <Key - latin:keyLabel="अ" + latin:keySpec="अ" latin:keyLabelFlags="fontNormal" /> <!-- U+091D: "झ" DEVANAGARI LETTER JHA --> <Key - latin:keyLabel="झ" + latin:keySpec="झ" latin:keyLabelFlags="fontNormal" /> <!-- U+0916: "ख" DEVANAGARI LETTER KHA --> <Key - latin:keyLabel="ख" + latin:keySpec="ख" latin:keyLabelFlags="fontNormal" /> <!-- U+0965: "॥" DEVANAGARI DOUBLE DANDA --> <Key - latin:keyLabel="॥" + latin:keySpec="॥" latin:keyLabelFlags="fontNormal" /> <!-- U+0910: "ऐ" DEVANAGARI LETTER AI --> <Key - latin:keyLabel="ऐ" + latin:keySpec="ऐ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -83,43 +83,43 @@ latin:keyStyle="baseKeyDevanagariVowelSignAa" /> <!-- U+0938: "स" DEVANAGARI LETTER SA --> <Key - latin:keyLabel="स" + latin:keySpec="स" latin:keyLabelFlags="fontNormal" /> <!-- U+0926: "द" DEVANAGARI LETTER DA --> <Key - latin:keyLabel="द" + latin:keySpec="द" latin:keyLabelFlags="fontNormal" /> <!-- U+0909: "उ" DEVANAGARI LETTER U --> <Key - latin:keyLabel="उ" + latin:keySpec="उ" latin:keyLabelFlags="fontNormal" /> <!-- U+0917: "ग" DEVANAGARI LETTER GA --> <Key - latin:keyLabel="ग" + latin:keySpec="ग" latin:keyLabelFlags="fontNormal" /> <!-- U+0939: "ह" DEVANAGARI LETTER HA --> <Key - latin:keyLabel="ह" + latin:keySpec="ह" latin:keyLabelFlags="fontNormal" /> <!-- U+091C: "ज" DEVANAGARI LETTER JA --> <Key - latin:keyLabel="ज" + latin:keySpec="ज" latin:keyLabelFlags="fontNormal" /> <!-- U+0915: "क" DEVANAGARI LETTER KA --> <Key - latin:keyLabel="क" + latin:keySpec="क" latin:keyLabelFlags="fontNormal" /> <!-- U+0932: "ल" DEVANAGARI LETTER LA --> <Key - latin:keyLabel="ल" + latin:keySpec="ल" latin:keyLabelFlags="fontNormal" /> <!-- U+090F: "ए" DEVANAGARI LETTER E --> <Key - latin:keyLabel="ए" + latin:keySpec="ए" latin:keyLabelFlags="fontNormal" /> <!-- U+0950: "ॐ" DEVANAGARI OM --> <Key - latin:keyLabel="ॐ" + latin:keySpec="ॐ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_nepali_romanized3.xml b/java/res/xml/rowkeys_nepali_romanized3.xml index 166d028a3..cc2ca8c84 100644 --- a/java/res/xml/rowkeys_nepali_romanized3.xml +++ b/java/res/xml/rowkeys_nepali_romanized3.xml @@ -27,37 +27,41 @@ > <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R --> <Key - latin:keyLabel="ऋ" + latin:keySpec="ऋ" latin:keyLabelFlags="fontNormal" /> <!-- U+0922: "ढ" DEVANAGARI LETTER DDHA --> <Key - latin:keyLabel="ढ" + latin:keySpec="ढ" latin:keyLabelFlags="fontNormal" /> <!-- U+091B: "छ" DEVANAGARI LETTER CHA --> <Key - latin:keyLabel="छ" + latin:keySpec="छ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_candrabindu" /> + <Key + latin:keyStyle="baseKeyDevanagariSignCandrabindu" /> <!-- U+092D: "भ" DEVANAGARI LETTER BHA --> <Key - latin:keyLabel="भ" + latin:keySpec="भ" latin:keyLabelFlags="fontNormal" /> <!-- U+0923: "ण" DEVANAGARI LETTER NNA --> <Key - latin:keyLabel="ण" + latin:keySpec="ण" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" /> + <Key + latin:keyStyle="baseKeyDevanagariSignAnusvara" /> <!-- U+0919: "ङ" DEVANAGARI LETTER NGA --> <Key - latin:keyLabel="ङ" + latin:keySpec="ङ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -70,36 +74,36 @@ <default> <!-- U+0937: "ष" DEVANAGARI LETTER SSA --> <Key - latin:keyLabel="ष" + latin:keySpec="ष" latin:keyLabelFlags="fontNormal" /> <!-- U+0921: "ड" DEVANAGARI LETTER DDA --> <Key - latin:keyLabel="ड" + latin:keySpec="ड" latin:keyLabelFlags="fontNormal" /> <!-- U+091A: "च" DEVANAGARI LETTER CA --> <Key - latin:keyLabel="च" + latin:keySpec="च" latin:keyLabelFlags="fontNormal" /> <!-- U+0935: "व" DEVANAGARI LETTER VA --> <Key - latin:keyLabel="व" + latin:keySpec="व" latin:keyLabelFlags="fontNormal" /> <!-- U+092C: "ब" DEVANAGARI LETTER BHA --> <Key - latin:keyLabel="ब" + latin:keySpec="ब" latin:keyLabelFlags="fontNormal" /> <!-- U+0928: "न" DEVANAGARI LETTER NA --> <Key - latin:keyLabel="न" + latin:keySpec="न" latin:keyLabelFlags="fontNormal" /> <!-- U+092E: "म" DEVANAGARI LETTER MA --> <Key - latin:keyLabel="म" + latin:keySpec="म" latin:keyLabelFlags="fontNormal" /> <!-- U+0964: "।" DEVANAGARI DANDA U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA --> <Key - latin:keyLabel="।" + latin:keySpec="।" latin:moreKeys="ऽ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically diff --git a/java/res/xml/rowkeys_nepali_traditional1.xml b/java/res/xml/rowkeys_nepali_traditional1.xml index c7883c733..cf4bda982 100644 --- a/java/res/xml/rowkeys_nepali_traditional1.xml +++ b/java/res/xml/rowkeys_nepali_traditional1.xml @@ -30,144 +30,146 @@ U+091C/U+094D/U+091E: "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA U+0965: "॥" DEVANAGARI DOUBLE DANDA --> <Key - latin:keyLabel="त्त" + latin:keySpec="त्त" latin:moreKeys="ञ,ज्ञ,॥" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0921/U+094D/U+0922: "ड्ढ" DEVANAGARI LETTER DDA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DDHA U+0908: "ई" DEVANAGARI LETTER II --> <Key - latin:keyLabel="ड्ढ" + latin:keySpec="ड्ढ" latin:moreKeys="ई" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0910: "ऐ" DEVANAGARI LETTER AI U+0918: "घ" DEVANAGARI LETTER GHA --> <Key - latin:keyLabel="ऐ" + latin:keySpec="ऐ" latin:moreKeys="घ" latin:keyLabelFlags="fontNormal" /> <!-- U+0926/U+094D/U+0935: "द्व" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER VA U+0926/U+094D/U+0927: "द्ध" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DHA --> <Key - latin:keyLabel="द्व" + latin:keySpec="द्व" latin:moreKeys="द्ध" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+091F/U+094D/U+091F: "ट्ट" DEVANAGARI LETTER TTA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTA U+091B: "छ" DEVANAGARI LETTER CHA --> <Key - latin:keyLabel="ट्ट" + latin:keySpec="ट्ट" latin:moreKeys="छ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0920/U+094D/U+0920: "ठ्ठ" DEVANAGARI LETTER TTHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTHA U+091F: "ट" DEVANAGARI LETTER TTA --> <Key - latin:keyLabel="ठ्ठ" + latin:keySpec="ठ्ठ" latin:moreKeys="ट" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+090A: "ऊ" DEVANAGARI LETTER UU U+0920: "ठ" DEVANAGARI LETTER TTHA --> <Key - latin:keyLabel="ऊ" + latin:keySpec="ऊ" latin:moreKeys="ठ" latin:keyLabelFlags="fontNormal" /> <!-- U+0915/U+094D/U+0937: "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA U+0921: "ड" DEVANAGARI LETTER DDA --> <Key - latin:keyLabel="क्ष" + latin:keySpec="क्ष" latin:moreKeys="ड" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0907: "इ" DEVANAGARI LETTER I U+0922: "ढ" DEVANAGARI LETTER DDHA --> <Key - latin:keyLabel="इ" + latin:keySpec="इ" latin:moreKeys="ढ" latin:keyLabelFlags="fontNormal" /> <!-- U+090F: "ए" DEVANAGARI LETTER E U+0923: "ण" DEVANAGARI LETTER NNA --> <Key - latin:keyLabel="ए" + latin:keySpec="ए" latin:moreKeys="ण" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" /> + latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_vocalic_r" /> + <Key + latin:keyStyle="baseKeyDevanagariVowelSignVocalicR" /> </case> <default> <!-- U+091F: "ट" DEVANAGARI LETTER TTA U+0967: "१" DEVANAGARI DIGIT ONE --> <Key - latin:keyLabel="ट" + latin:keySpec="ट" latin:keyHintLabel="1" latin:additionalMoreKeys="१,1" latin:keyLabelFlags="fontNormal" /> <!-- U+0927: "ध" DEVANAGARI LETTER DHA U+0968: "२" DEVANAGARI DIGIT TWO --> <Key - latin:keyLabel="ध" + latin:keySpec="ध" latin:keyHintLabel="2" latin:additionalMoreKeys="२,2" latin:keyLabelFlags="fontNormal" /> <!-- U+092D: "भ" DEVANAGARI LETTER BHA U+0969: "३" DEVANAGARI DIGIT THREE --> <Key - latin:keyLabel="भ" + latin:keySpec="भ" latin:keyHintLabel="3" latin:additionalMoreKeys="३,3" latin:keyLabelFlags="fontNormal" /> <!-- U+091A: "च" DEVANAGARI LETTER CA U+096A: "४" DEVANAGARI DIGIT FOUR --> <Key - latin:keyLabel="च" + latin:keySpec="च" latin:keyHintLabel="4" latin:additionalMoreKeys="४,4" latin:keyLabelFlags="fontNormal" /> <!-- U+0924: "त" DEVANAGARI LETTER TA U+096B: "५" DEVANAGARI DIGIT FIVE --> <Key - latin:keyLabel="त" + latin:keySpec="त" latin:keyHintLabel="5" latin:additionalMoreKeys="५,5" latin:keyLabelFlags="fontNormal" /> <!-- U+0925: "थ" DEVANAGARI LETTER THA U+096C: "६" DEVANAGARI DIGIT SIX --> <Key - latin:keyLabel="थ" + latin:keySpec="थ" latin:keyHintLabel="6" latin:additionalMoreKeys="६,6" latin:keyLabelFlags="fontNormal" /> <!-- U+0917: "ग" DEVANAGARI LETTER G U+096D: "७" DEVANAGARI DIGIT SEVEN --> <Key - latin:keyLabel="ग" + latin:keySpec="ग" latin:keyHintLabel="7" latin:additionalMoreKeys="७,7" latin:keyLabelFlags="fontNormal" /> <!-- U+0937: "ष" DEVANAGARI LETTER SSA U+096E: "८" DEVANAGARI DIGIT EIGHT --> <Key - latin:keyLabel="ष" + latin:keySpec="ष" latin:keyHintLabel="8" latin:additionalMoreKeys="८,8" latin:keyLabelFlags="fontNormal" /> <!-- U+092F: "य" DEVANAGARI LETTER YA U+096F: "९" DEVANAGARI DIGIT NINE --> <Key - latin:keyLabel="य" + latin:keySpec="य" latin:keyHintLabel="9" latin:additionalMoreKeys="९,9" latin:keyLabelFlags="fontNormal" /> <!-- U+0909: "उ" DEVANAGARI LETTER U U+0966: "०" DEVANAGARI DIGIT ZERO --> <Key - latin:keyLabel="उ" + latin:keySpec="उ" latin:keyHintLabel="0" latin:additionalMoreKeys="०,0" latin:keyLabelFlags="fontNormal" /> <!-- U+0907: "इ" DEVANAGARI LETTER I U+0914: "औ" DEVANAGARI LETTER AU --> <Key - latin:keyLabel="इ" + latin:keySpec="इ" latin:moreKeys="औ" latin:keyLabelFlags="fontNormal" /> </default> diff --git a/java/res/xml/rowkeys_nepali_traditional2.xml b/java/res/xml/rowkeys_nepali_traditional2.xml index 45620a9d7..58a463e71 100644 --- a/java/res/xml/rowkeys_nepali_traditional2.xml +++ b/java/res/xml/rowkeys_nepali_traditional2.xml @@ -27,28 +27,30 @@ > <!-- U+0906: "आ" DEVANAGARI LETTER AA --> <Key - latin:keyLabel="आ" + latin:keySpec="आ" latin:keyLabelFlags="fontNormal" /> <!-- U+0919/U+094D: "ङ्" DEVANAGARI LETTER NGA/DEVANAGARI SIGN VIRAMA --> <Key - latin:keyLabel="ङ्" + latin:keySpec="ङ्" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0921/U+094D/U+0921: "ड्ड" DEVANAGARI LETTER DDA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DDA --> <Key - latin:keyLabel="ड्ड" + latin:keySpec="ड्ड" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_candrabindu" /> + <Key + latin:keyStyle="baseKeyDevanagariSignCandrabindu" /> <!-- U+0926/U+094D/U+0926: "द्द" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DA --> <Key - latin:keyLabel="द्द" + latin:keySpec="द्द" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+091D: "झ" DEVANAGARI LETTER JHA --> <Key - latin:keyLabel="झ" + latin:keySpec="झ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -59,7 +61,7 @@ latin:keyStyle="baseKeyDevanagariVowelSignO" /> <!-- U+092B: "फ" DEVANAGARI LETTER PHA --> <Key - latin:keyLabel="फ" + latin:keySpec="फ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -70,7 +72,7 @@ latin:keyStyle="baseKeyDevanagariVowelSignIi" /> <!-- U+091F/U+094D/U+0920: "ट्ठ" DEVANAGARI LETTER TTA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTHA --> <Key - latin:keyLabel="ट्ठ" + latin:keySpec="ट्ठ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -83,15 +85,15 @@ <default> <!-- U+092C: "ब" DEVANAGARI LETTER BA --> <Key - latin:keyLabel="ब" + latin:keySpec="ब" latin:keyLabelFlags="fontNormal" /> <!-- U+0915: "क" DEVANAGARI LETTER KA --> <Key - latin:keyLabel="क" + latin:keySpec="क" latin:keyLabelFlags="fontNormal" /> <!-- U+092E: "म" DEVANAGARI LETTER MA --> <Key - latin:keyLabel="म" + latin:keySpec="म" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -102,19 +104,19 @@ latin:keyStyle="baseKeyDevanagariVowelSignAa" /> <!-- U+0928: "न" DEVANAGARI LETTER NA --> <Key - latin:keyLabel="न" + latin:keySpec="न" latin:keyLabelFlags="fontNormal" /> <!-- U+091C: "ज" DEVANAGARI LETTER JA --> <Key - latin:keyLabel="ज" + latin:keySpec="ज" latin:keyLabelFlags="fontNormal" /> <!-- U+0935: "व" DEVANAGARI LETTER VA --> <Key - latin:keyLabel="व" + latin:keySpec="व" latin:keyLabelFlags="fontNormal" /> <!-- U+092A: "प" DEVANAGARI LETTER PA --> <Key - latin:keyLabel="प" + latin:keySpec="प" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -125,7 +127,7 @@ latin:keyStyle="baseKeyDevanagariVowelSignI" /> <!-- U+0938: "स" DEVANAGARI LETTER SA --> <Key - latin:keyLabel="स" + latin:keySpec="स" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different diff --git a/java/res/xml/rowkeys_nepali_traditional3_left6.xml b/java/res/xml/rowkeys_nepali_traditional3_left6.xml index 1cacced83..59f6e651a 100644 --- a/java/res/xml/rowkeys_nepali_traditional3_left6.xml +++ b/java/res/xml/rowkeys_nepali_traditional3_left6.xml @@ -27,19 +27,19 @@ > <!-- U+0915/U+094D: "क्" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA --> <Key - latin:keyLabel="क्" + latin:keySpec="क्" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0939/U+094D/U+092E: "ह्म" DEVANAGARI LETTER HA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER MA --> <Key - latin:keyLabel="ह्म" + latin:keySpec="ह्म" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R --> <Key - latin:keyLabel="ऋ" + latin:keySpec="ऋ" latin:keyLabelFlags="fontNormal" /> <!-- U+0950: "ॐ" DEVANAGARI OM --> <Key - latin:keyLabel="ॐ" + latin:keySpec="ॐ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -50,33 +50,33 @@ latin:keyStyle="baseKeyDevanagariVowelSignAu" /> <!-- U+0926/U+094D/U+092F: "द्य" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER YA --> <Key - latin:keyLabel="द्य" + latin:keySpec="द्य" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> </case> <default> <!-- U+0936: "श" DEVANAGARI LETTER SHA --> <Key - latin:keyLabel="श" + latin:keySpec="श" latin:keyLabelFlags="fontNormal" /> <!-- U+0939: "ह" DEVANAGARI LETTER HA --> <Key - latin:keyLabel="ह" + latin:keySpec="ह" latin:keyLabelFlags="fontNormal" /> <!-- U+0905: "अ" DEVANAGARI LETTER A --> <Key - latin:keyLabel="अ" + latin:keySpec="अ" latin:keyLabelFlags="fontNormal" /> <!-- U+0916: "ख" DEVANAGARI LETTER KHA --> <Key - latin:keyLabel="ख" + latin:keySpec="ख" latin:keyLabelFlags="fontNormal" /> <!-- U+0926: "द" DEVANAGARI LETTER DA --> <Key - latin:keyLabel="द" + latin:keySpec="द" latin:keyLabelFlags="fontNormal" /> <!-- U+0932: "ल" DEVANAGARI LETTER LA --> <Key - latin:keyLabel="ल" + latin:keySpec="ल" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_nepali_traditional3_right3.xml b/java/res/xml/rowkeys_nepali_traditional3_right3.xml index b2e01e481..3e6187d11 100644 --- a/java/res/xml/rowkeys_nepali_traditional3_right3.xml +++ b/java/res/xml/rowkeys_nepali_traditional3_right3.xml @@ -29,10 +29,12 @@ render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" /> + <Key + latin:keyStyle="baseKeyDevanagariSignAnusvara" /> <!-- U+0919: "ङ" DEVANAGARI LETTER NGA --> <Key - latin:keyLabel="ङ" + latin:keySpec="ङ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -52,12 +54,12 @@ latin:keyStyle="baseKeyDevanagariVowelSignE" /> <!-- U+0964: "।" DEVANAGARI DANDA --> <Key - latin:keyLabel="।" + latin:keySpec="।" latin:keyLabelFlags="fontNormal" /> - <!-- U+0930: "र" DEVANAGARI LETTER RA - U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U --> + <!-- U+0930: "र" DEVANAGARI LETTER RA + U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U --> <Key - latin:keyLabel="र" + latin:keySpec="र" latin:moreKeys="रु" latin:keyLabelFlags="fontNormal" /> </default> diff --git a/java/res/xml/rowkeys_nepali_traditional3_right5.xml b/java/res/xml/rowkeys_nepali_traditional3_right5.xml index 87f061610..89d5aa469 100644 --- a/java/res/xml/rowkeys_nepali_traditional3_right5.xml +++ b/java/res/xml/rowkeys_nepali_traditional3_right5.xml @@ -29,10 +29,12 @@ render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> <include - latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" /> + latin:keyboardLayout="@xml/keystyle_devanagari_sign_anusvara" /> + <Key + latin:keyStyle="baseKeyDevanagariSignAnusvara" /> <!-- U+0919: "ङ" DEVANAGARI LETTER NGA --> <Key - latin:keyLabel="ङ" + latin:keySpec="ङ" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different @@ -43,19 +45,19 @@ latin:keyStyle="baseKeyDevanagariVowelSignAi" /> <!-- U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U --> <Key - latin:keyLabel="रु" + latin:keySpec="रु" latin:moreKeys="!" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <Key - latin:keyLabel="\?" /> + latin:keySpec="\?" /> </case> <default> <!-- Because the font rendering system prior to API version 16 can't automatically render dotted circle for incomplete combining letter of some scripts, different set of Key definitions are needed based on the API version. --> - <!-- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA --> <include latin:keyboardLayout="@xml/keystyle_devanagari_sign_visarga" /> + <!-- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA --> <Key latin:keyStyle="baseKeyDevanagariSignVisarga" latin:moreKeys="ऽ" /> @@ -71,11 +73,11 @@ latin:keyStyle="baseKeyDevanagariVowelSignE" /> <!-- U+0964: "।" DEVANAGARI DANDA --> <Key - latin:keyLabel="।" + latin:keySpec="।" latin:keyLabelFlags="fontNormal" /> <!-- U+0930: "र" DEVANAGARI LETTER RA --> <Key - latin:keyLabel="र" + latin:keySpec="र" latin:moreKeys="!" latin:keyLabelFlags="fontNormal" /> <!-- Because the font rendering system prior to API version 16 can't automatically diff --git a/java/res/xml/rowkeys_nordic1.xml b/java/res/xml/rowkeys_nordic1.xml index 72ac86b2e..ff589cc4a 100644 --- a/java/res/xml/rowkeys_nordic1.xml +++ b/java/res/xml/rowkeys_nordic1.xml @@ -24,5 +24,5 @@ <include latin:keyboardLayout="@xml/rowkeys_qwerty1" /> <Key - latin:keyLabel="!text/keylabel_for_nordic_row1_11" /> + latin:keySpec="!text/keyspec_nordic_row1_11" /> </merge> diff --git a/java/res/xml/rowkeys_nordic2.xml b/java/res/xml/rowkeys_nordic2.xml index 836214abf..0330c0f67 100644 --- a/java/res/xml/rowkeys_nordic2.xml +++ b/java/res/xml/rowkeys_nordic2.xml @@ -24,9 +24,9 @@ <include latin:keyboardLayout="@xml/rowkeys_qwerty2" /> <Key - latin:keyLabel="!text/keylabel_for_nordic_row2_10" - latin:moreKeys="!text/more_keys_for_nordic_row2_10" /> + latin:keySpec="!text/keyspec_nordic_row2_10" + latin:moreKeys="!text/morekeys_nordic_row2_10" /> <Key - latin:keyLabel="!text/keylabel_for_nordic_row2_11" - latin:moreKeys="!text/more_keys_for_nordic_row2_11" /> + latin:keySpec="!text/keyspec_nordic_row2_11" + latin:moreKeys="!text/morekeys_nordic_row2_11" /> </merge> diff --git a/java/res/xml/rowkeys_pcqwerty1.xml b/java/res/xml/rowkeys_pcqwerty1.xml index de548d0ba..564468a9a 100644 --- a/java/res/xml/rowkeys_pcqwerty1.xml +++ b/java/res/xml/rowkeys_pcqwerty1.xml @@ -21,61 +21,72 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <Key - latin:keyLabel="`" - latin:additionalMoreKeys="~" /> - <Key - latin:keyLabel="1" - latin:additionalMoreKeys="!,!text/more_keys_for_symbols_exclamation" - latin:moreKeys="!text/more_keys_for_symbols_1" /> - <Key - latin:keyLabel="2" - latin:additionalMoreKeys="\@" - latin:moreKeys="!text/more_keys_for_symbols_2" /> - <Key - latin:keyLabel="3" - latin:additionalMoreKeys="\#" - latin:moreKeys="!text/more_keys_for_symbols_3" /> - <Key - latin:keyLabel="4" - latin:additionalMoreKeys="$" - latin:moreKeys="!text/more_keys_for_symbols_4" /> - <Key - latin:keyLabel="5" - latin:additionalMoreKeys="\\%" - latin:moreKeys="!text/more_keys_for_symbols_5" /> - <Key - latin:keyLabel="6" - latin:additionalMoreKeys="^" - latin:moreKeys="!text/more_keys_for_symbols_6" /> - <Key - latin:keyLabel="7" - latin:additionalMoreKeys="&" - latin:moreKeys="!text/more_keys_for_symbols_7" /> - <Key - latin:keyLabel="8" - latin:additionalMoreKeys="*" - latin:moreKeys="!text/more_keys_for_symbols_8" /> - <Key - latin:keyLabel="9" - latin:additionalMoreKeys="(" - latin:moreKeys="!text/more_keys_for_symbols_9" /> - <Key - latin:keyLabel="0" - latin:additionalMoreKeys=")" - latin:moreKeys="!text/more_keys_for_symbols_0" /> - <!-- U+2013: "–" EN DASH - U+2014: "—" EM DASH - U+00B7: "·" MIDDLE DOT --> - <Key - latin:keyLabel="-" - latin:additionalMoreKeys="_" - latin:moreKeys="–,—,·" /> - <!-- U+221E: "∞" INFINITY - U+2260: "≠" NOT EQUAL TO - U+2248: "≈" ALMOST EQUAL TO --> - <Key - latin:keyLabel="=" - latin:additionalMoreKeys="+" - latin:moreKeys="!fixedColumnOrder!4,∞,≠,≈,%" /> + <switch> + <case + latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked" + > + <Key + latin:keySpec="`" + latin:additionalMoreKeys="~" /> + <Key + latin:keySpec="1" + latin:additionalMoreKeys="!,!text/morekeys_exclamation" + latin:moreKeys="!text/morekeys_symbols_1" /> + <Key + latin:keySpec="2" + latin:additionalMoreKeys="\@" + latin:moreKeys="!text/morekeys_symbols_2" /> + <Key + latin:keySpec="3" + latin:additionalMoreKeys="\#" + latin:moreKeys="!text/morekeys_symbols_3" /> + <Key + latin:keySpec="4" + latin:additionalMoreKeys="$" + latin:moreKeys="!text/morekeys_symbols_4" /> + <Key + latin:keySpec="5" + latin:additionalMoreKeys="\\%" + latin:moreKeys="!text/morekeys_symbols_5" /> + <Key + latin:keySpec="6" + latin:additionalMoreKeys="^" + latin:moreKeys="!text/morekeys_symbols_6" /> + <Key + latin:keySpec="7" + latin:additionalMoreKeys="&" + latin:moreKeys="!text/morekeys_symbols_7" /> + <Key + latin:keySpec="8" + latin:additionalMoreKeys="*" + latin:moreKeys="!text/morekeys_symbols_8" /> + <Key + latin:keySpec="9" + latin:additionalMoreKeys="(" + latin:moreKeys="!text/morekeys_symbols_9" /> + <Key + latin:keySpec="0" + latin:additionalMoreKeys=")" + latin:moreKeys="!text/morekeys_symbols_0" /> + <!-- U+2013: "–" EN DASH + U+2014: "—" EM DASH + U+00B7: "·" MIDDLE DOT --> + <Key + latin:keySpec="-" + latin:additionalMoreKeys="_" + latin:moreKeys="–,—,·" /> + <!-- U+221E: "∞" INFINITY + U+2260: "≠" NOT EQUAL TO + U+2248: "≈" ALMOST EQUAL TO --> + <Key + latin:keySpec="=" + latin:additionalMoreKeys="+" + latin:moreKeys="!fixedColumnOrder!4,∞,≠,≈,%" /> + </case> + <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" --> + <default> + <include + latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" /> + </default> + </switch> </merge> diff --git a/java/res/xml/rowkeys_pcqwerty1_shift.xml b/java/res/xml/rowkeys_pcqwerty1_shift.xml index bc39f944e..c72040f8a 100644 --- a/java/res/xml/rowkeys_pcqwerty1_shift.xml +++ b/java/res/xml/rowkeys_pcqwerty1_shift.xml @@ -22,39 +22,38 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="~" /> + latin:keySpec="~" /> <Key - latin:keyLabel="!" - latin:additionalMoreKeys="!text/more_keys_for_symbols_exclamation" /> + latin:keySpec="!" + latin:additionalMoreKeys="!text/morekeys_exclamation" /> <Key - latin:keyLabel="\@" /> + latin:keySpec="\@" /> <Key - latin:keyLabel="\#" /> + latin:keySpec="\#" /> <Key - latin:keyLabel="$" - latin:additionalMoreKeys="!text/more_keys_for_currency_dollar" /> + latin:keySpec="$" + latin:additionalMoreKeys="!text/morekeys_currency_dollar" /> <Key - latin:keyLabel="%" - latin:additionalMoreKeys="!text/more_keys_for_symbols_percent" /> + latin:keySpec="%" + latin:additionalMoreKeys="!text/morekeys_symbols_percent" /> <Key - latin:keyLabel="^" /> + latin:keySpec="^" /> <Key - latin:keyLabel="&" /> + latin:keySpec="&" /> <Key - latin:keyLabel="*" - latin:additionalMoreKeys="!text/more_keys_for_star" /> + latin:keySpec="*" + latin:additionalMoreKeys="!text/morekeys_star" /> <Key - latin:keyLabel="(" /> + latin:keySpec="(" /> <Key - latin:keyLabel=")" /> + latin:keySpec=")" /> <Key - latin:keyLabel="_" /> - <!-- U+00B1: "±" PLUS-MINUS SIGN - U+00D7: "×" MULTIPLICATION SIGN + latin:keySpec="_" /> + <!-- U+00D7: "×" MULTIPLICATION SIGN U+00F7: "÷" DIVISION SIGN U+221A: "√" SQUARE ROOT --> <Key - latin:keyLabel="+" - latin:additionalMoreKeys="!text/more_keys_for_plus" - latin:moreKeys="±,×,÷,√" /> + latin:keySpec="+" + latin:additionalMoreKeys="!text/morekeys_plus" + latin:moreKeys="×,÷,√" /> </merge> diff --git a/java/res/xml/rowkeys_qwerty1.xml b/java/res/xml/rowkeys_qwerty1.xml index e7c9b590b..8f3b160fe 100644 --- a/java/res/xml/rowkeys_qwerty1.xml +++ b/java/res/xml/rowkeys_qwerty1.xml @@ -22,52 +22,52 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="!text/keylabel_for_q" + latin:keySpec="!text/keyspec_q" latin:keyHintLabel="1" latin:additionalMoreKeys="1" - latin:moreKeys="!text/more_keys_for_q" /> + latin:moreKeys="!text/morekeys_q" /> <Key - latin:keyLabel="!text/keylabel_for_w" + latin:keySpec="!text/keyspec_w" latin:keyHintLabel="2" latin:additionalMoreKeys="2" - latin:moreKeys="!text/more_keys_for_w" /> + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="e" + latin:keySpec="e" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_e" /> + latin:moreKeys="!text/morekeys_e" /> <Key - latin:keyLabel="r" + latin:keySpec="r" latin:keyHintLabel="4" latin:additionalMoreKeys="4" - latin:moreKeys="!text/more_keys_for_r" /> + latin:moreKeys="!text/morekeys_r" /> <Key - latin:keyLabel="t" + latin:keySpec="t" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_t" /> + latin:moreKeys="!text/morekeys_t" /> <Key - latin:keyLabel="!text/keylabel_for_y" + latin:keySpec="!text/keyspec_y" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_y" /> + latin:moreKeys="!text/morekeys_y" /> <Key - latin:keyLabel="u" + latin:keySpec="u" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_u" /> + latin:moreKeys="!text/morekeys_u" /> <Key - latin:keyLabel="i" + latin:keySpec="i" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_i" /> + latin:moreKeys="!text/morekeys_i" /> <Key - latin:keyLabel="o" + latin:keySpec="o" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="!text/more_keys_for_o" /> + latin:moreKeys="!text/morekeys_o" /> <Key - latin:keyLabel="p" + latin:keySpec="p" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </merge> diff --git a/java/res/xml/rowkeys_qwerty2.xml b/java/res/xml/rowkeys_qwerty2.xml index d9777d920..4077beaf6 100644 --- a/java/res/xml/rowkeys_qwerty2.xml +++ b/java/res/xml/rowkeys_qwerty2.xml @@ -22,29 +22,29 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="a" - latin:moreKeys="!text/more_keys_for_a" /> + latin:keySpec="a" + latin:moreKeys="!text/morekeys_a" /> <Key - latin:keyLabel="s" - latin:moreKeys="!text/more_keys_for_s" /> + latin:keySpec="s" + latin:moreKeys="!text/morekeys_s" /> <Key - latin:keyLabel="d" - latin:moreKeys="!text/more_keys_for_d" /> + latin:keySpec="d" + latin:moreKeys="!text/morekeys_d" /> <Key - latin:keyLabel="f" /> + latin:keySpec="f" /> <Key - latin:keyLabel="g" - latin:moreKeys="!text/more_keys_for_g" /> + latin:keySpec="g" + latin:moreKeys="!text/morekeys_g" /> <Key - latin:keyLabel="h" - latin:moreKeys="!text/more_keys_for_h" /> + latin:keySpec="h" + latin:moreKeys="!text/morekeys_h" /> <Key - latin:keyLabel="j" - latin:moreKeys="!text/more_keys_for_j" /> + latin:keySpec="j" + latin:moreKeys="!text/morekeys_j" /> <Key - latin:keyLabel="k" - latin:moreKeys="!text/more_keys_for_k" /> + latin:keySpec="k" + latin:moreKeys="!text/morekeys_k" /> <Key - latin:keyLabel="l" - latin:moreKeys="!text/more_keys_for_l" /> + latin:keySpec="l" + latin:moreKeys="!text/morekeys_l" /> </merge> diff --git a/java/res/xml/rowkeys_qwerty3.xml b/java/res/xml/rowkeys_qwerty3.xml index b70fd729f..8562003d2 100644 --- a/java/res/xml/rowkeys_qwerty3.xml +++ b/java/res/xml/rowkeys_qwerty3.xml @@ -22,22 +22,22 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="z" - latin:moreKeys="!text/more_keys_for_z" /> + latin:keySpec="z" + latin:moreKeys="!text/morekeys_z" /> <Key - latin:keyLabel="!text/keylabel_for_x" - latin:moreKeys="!text/more_keys_for_x" /> + latin:keySpec="!text/keyspec_x" + latin:moreKeys="!text/morekeys_x" /> <Key - latin:keyLabel="c" - latin:moreKeys="!text/more_keys_for_c" /> + latin:keySpec="c" + latin:moreKeys="!text/morekeys_c" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="n" - latin:moreKeys="!text/more_keys_for_n" /> + latin:keySpec="n" + latin:moreKeys="!text/morekeys_n" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> </merge> diff --git a/java/res/xml/rowkeys_qwertz1.xml b/java/res/xml/rowkeys_qwertz1.xml index d87f03ddc..c4edae339 100644 --- a/java/res/xml/rowkeys_qwertz1.xml +++ b/java/res/xml/rowkeys_qwertz1.xml @@ -22,51 +22,51 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="q" + latin:keySpec="q" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <Key - latin:keyLabel="w" + latin:keySpec="w" latin:keyHintLabel="2" latin:additionalMoreKeys="2" - latin:moreKeys="!text/more_keys_for_w" /> + latin:moreKeys="!text/morekeys_w" /> <Key - latin:keyLabel="e" + latin:keySpec="e" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_e" /> + latin:moreKeys="!text/morekeys_e" /> <Key - latin:keyLabel="r" + latin:keySpec="r" latin:keyHintLabel="4" latin:additionalMoreKeys="4" - latin:moreKeys="!text/more_keys_for_r" /> + latin:moreKeys="!text/morekeys_r" /> <Key - latin:keyLabel="t" + latin:keySpec="t" latin:keyHintLabel="5" latin:additionalMoreKeys="5" - latin:moreKeys="!text/more_keys_for_t" /> + latin:moreKeys="!text/morekeys_t" /> <Key - latin:keyLabel="z" + latin:keySpec="z" latin:keyHintLabel="6" latin:additionalMoreKeys="6" - latin:moreKeys="!text/more_keys_for_z" /> + latin:moreKeys="!text/morekeys_z" /> <Key - latin:keyLabel="u" + latin:keySpec="u" latin:keyHintLabel="7" latin:additionalMoreKeys="7" - latin:moreKeys="!text/more_keys_for_u" /> + latin:moreKeys="!text/morekeys_u" /> <Key - latin:keyLabel="i" + latin:keySpec="i" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_i" /> + latin:moreKeys="!text/morekeys_i" /> <Key - latin:keyLabel="o" + latin:keySpec="o" latin:keyHintLabel="9" latin:additionalMoreKeys="9" - latin:moreKeys="!text/more_keys_for_o" /> + latin:moreKeys="!text/morekeys_o" /> <Key - latin:keyLabel="p" + latin:keySpec="p" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> </merge> diff --git a/java/res/xml/rowkeys_qwertz3.xml b/java/res/xml/rowkeys_qwertz3.xml index 9e39fe08e..a66c34868 100644 --- a/java/res/xml/rowkeys_qwertz3.xml +++ b/java/res/xml/rowkeys_qwertz3.xml @@ -22,21 +22,21 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="y" - latin:moreKeys="!text/more_keys_for_y" /> + latin:keySpec="y" + latin:moreKeys="!text/morekeys_y" /> <Key - latin:keyLabel="x" /> + latin:keySpec="x" /> <Key - latin:keyLabel="c" - latin:moreKeys="!text/more_keys_for_c" /> + latin:keySpec="c" + latin:moreKeys="!text/morekeys_c" /> <Key - latin:keyLabel="v" - latin:moreKeys="!text/more_keys_for_v" /> + latin:keySpec="v" + latin:moreKeys="!text/morekeys_v" /> <Key - latin:keyLabel="b" /> + latin:keySpec="b" /> <Key - latin:keyLabel="n" - latin:moreKeys="!text/more_keys_for_n" /> + latin:keySpec="n" + latin:moreKeys="!text/morekeys_n" /> <Key - latin:keyLabel="m" /> + latin:keySpec="m" /> </merge> diff --git a/java/res/xml/rowkeys_south_slavic1.xml b/java/res/xml/rowkeys_south_slavic1.xml index 6117d46f1..064f164e8 100644 --- a/java/res/xml/rowkeys_south_slavic1.xml +++ b/java/res/xml/rowkeys_south_slavic1.xml @@ -23,56 +23,56 @@ > <!-- U+0459: "љ" CYRILLIC SMALL LETTER LJE --> <Key - latin:keyLabel="љ" + latin:keySpec="љ" latin:keyHintLabel="1" latin:additionalMoreKeys="1" /> <!-- U+045A: "њ" CYRILLIC SMALL LETTER NJE --> <Key - latin:keyLabel="њ" + latin:keySpec="њ" latin:keyHintLabel="2" latin:additionalMoreKeys="2" /> <!-- U+0435: "е" CYRILLIC SMALL LETTER IE --> <Key - latin:keyLabel="е" + latin:keySpec="е" latin:keyHintLabel="3" latin:additionalMoreKeys="3" - latin:moreKeys="!text/more_keys_for_cyrillic_ie" /> + latin:moreKeys="!text/morekeys_cyrillic_ie" /> <!-- U+0440: "р" CYRILLIC SMALL LETTER ER --> <Key - latin:keyLabel="р" + latin:keySpec="р" latin:keyHintLabel="4" latin:additionalMoreKeys="4" /> <!-- U+0442: "т" CYRILLIC SMALL LETTER TE --> <Key - latin:keyLabel="т" + latin:keySpec="т" latin:keyHintLabel="5" latin:additionalMoreKeys="5" /> <Key - latin:keyLabel="!text/keylabel_for_south_slavic_row1_6" + latin:keySpec="!text/keyspec_south_slavic_row1_6" latin:keyHintLabel="6" latin:additionalMoreKeys="6" /> <!-- U+0443: "у" CYRILLIC SMALL LETTER U --> <Key - latin:keyLabel="у" + latin:keySpec="у" latin:keyHintLabel="7" latin:additionalMoreKeys="7" /> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> <Key - latin:keyLabel="и" + latin:keySpec="и" latin:keyHintLabel="8" latin:additionalMoreKeys="8" - latin:moreKeys="!text/more_keys_for_cyrillic_i" /> + latin:moreKeys="!text/morekeys_cyrillic_i" /> <!-- U+043E: "о" CYRILLIC SMALL LETTER O --> <Key - latin:keyLabel="о" + latin:keySpec="о" latin:keyHintLabel="9" latin:additionalMoreKeys="9" /> <!-- U+043F: "п" CYRILLIC SMALL LETTER PE --> <Key - latin:keyLabel="п" + latin:keySpec="п" latin:keyHintLabel="0" latin:additionalMoreKeys="0" /> <!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA --> <Key - latin:keyLabel="ш" /> + latin:keySpec="ш" /> </merge> diff --git a/java/res/xml/rowkeys_south_slavic2.xml b/java/res/xml/rowkeys_south_slavic2.xml index 88e894053..3b98001b2 100644 --- a/java/res/xml/rowkeys_south_slavic2.xml +++ b/java/res/xml/rowkeys_south_slavic2.xml @@ -23,34 +23,34 @@ > <!-- U+0430: "а" CYRILLIC SMALL LETTER A --> <Key - latin:keyLabel="а" /> + latin:keySpec="а" /> <!-- U+0441: "с" CYRILLIC SMALL LETTER ES --> <Key - latin:keyLabel="с" /> + latin:keySpec="с" /> <!-- U+0434: "д" CYRILLIC SMALL LETTER DE --> <Key - latin:keyLabel="д" /> + latin:keySpec="д" /> <!-- U+0444: "ф" CYRILLIC SMALL LETTER EF --> <Key - latin:keyLabel="ф" /> + latin:keySpec="ф" /> <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE --> <Key - latin:keyLabel="г" /> + latin:keySpec="г" /> <!-- U+0445: "х" CYRILLIC SMALL LETTER HA --> <Key - latin:keyLabel="х" /> + latin:keySpec="х" /> <!-- U+0458: "ј" CYRILLIC SMALL LETTER JE --> <Key - latin:keyLabel="ј" /> + latin:keySpec="ј" /> <!-- U+043A: "к" CYRILLIC SMALL LETTER KA --> <Key - latin:keyLabel="к" /> + latin:keySpec="к" /> <!-- U+043B: "л" CYRILLIC SMALL LETTER EL --> <Key - latin:keyLabel="л" /> + latin:keySpec="л" /> <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE --> <Key - latin:keyLabel="ч" /> + latin:keySpec="ч" /> <Key - latin:keyLabel="!text/keylabel_for_south_slavic_row2_11" /> + latin:keySpec="!text/keyspec_south_slavic_row2_11" /> </merge> diff --git a/java/res/xml/rowkeys_south_slavic3.xml b/java/res/xml/rowkeys_south_slavic3.xml index b01550911..31df9b96e 100644 --- a/java/res/xml/rowkeys_south_slavic3.xml +++ b/java/res/xml/rowkeys_south_slavic3.xml @@ -22,28 +22,28 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="!text/keylabel_for_south_slavic_row3_1" /> + latin:keySpec="!text/keyspec_south_slavic_row3_1" /> <!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE --> <Key - latin:keyLabel="џ" /> + latin:keySpec="џ" /> <!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE --> <Key - latin:keyLabel="ц" /> + latin:keySpec="ц" /> <!-- U+0432: "в" CYRILLIC SMALL LETTER VE --> <Key - latin:keyLabel="в" /> + latin:keySpec="в" /> <!-- U+0431: "б" CYRILLIC SMALL LETTER BE --> <Key - latin:keyLabel="б" /> + latin:keySpec="б" /> <!-- U+043D: "н" CYRILLIC SMALL LETTER EN --> <Key - latin:keyLabel="н" /> + latin:keySpec="н" /> <!-- U+043C: "м" CYRILLIC SMALL LETTER EM --> <Key - latin:keyLabel="м" /> + latin:keySpec="м" /> <Key - latin:keyLabel="!text/keylabel_for_south_slavic_row3_8" /> + latin:keySpec="!text/keyspec_south_slavic_row3_8" /> <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE --> <Key - latin:keyLabel="ж" /> + latin:keySpec="ж" /> </merge> diff --git a/java/res/xml/rowkeys_spanish2.xml b/java/res/xml/rowkeys_spanish2.xml index 335dff33c..5c7f67cdd 100644 --- a/java/res/xml/rowkeys_spanish2.xml +++ b/java/res/xml/rowkeys_spanish2.xml @@ -25,5 +25,5 @@ latin:keyboardLayout="@xml/rowkeys_qwerty2" /> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> <Key - latin:keyLabel="!text/keylabel_for_spanish_row2_10" /> + latin:keySpec="!text/keyspec_spanish_row2_10" /> </merge> diff --git a/java/res/xml/rowkeys_swiss1.xml b/java/res/xml/rowkeys_swiss1.xml new file mode 100644 index 000000000..2b82c81bd --- /dev/null +++ b/java/res/xml/rowkeys_swiss1.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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/rowkeys_qwertz1" /> + <Key + latin:keySpec="!text/keyspec_swiss_row1_11" + latin:moreKeys="!text/morekeys_swiss_row1_11" /> +</merge> diff --git a/java/res/xml/key_azerty3_right.xml b/java/res/xml/rowkeys_swiss2.xml index 65789ea69..770911179 100644 --- a/java/res/xml/key_azerty3_right.xml +++ b/java/res/xml/rowkeys_swiss2.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2012, The Android Open Source Project +** Copyright 2013, 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. @@ -21,17 +21,12 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <switch> - <case - latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted" - > - <Key - latin:keyLabel="\?" /> - </case> - <default> - <Key - latin:keyLabel="\'" - latin:moreKeys="!text/more_keys_for_single_quote" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/rowkeys_qwerty2" /> + <Key + latin:keySpec="!text/keyspec_swiss_row2_10" + latin:moreKeys="!text/morekeys_swiss_row2_10" /> + <Key + latin:keySpec="!text/keyspec_swiss_row2_11" + latin:moreKeys="!text/morekeys_swiss_row2_11" /> </merge> diff --git a/java/res/xml/rowkeys_symbols1.xml b/java/res/xml/rowkeys_symbols1.xml index 6e2f92dd9..daf9087b2 100644 --- a/java/res/xml/rowkeys_symbols1.xml +++ b/java/res/xml/rowkeys_symbols1.xml @@ -22,43 +22,43 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="!text/keylabel_for_symbols_1" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_1" - latin:moreKeys="!text/more_keys_for_symbols_1" /> + latin:keySpec="!text/keyspec_symbols_1" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_1" + latin:moreKeys="!text/morekeys_symbols_1" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_2" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_2" - latin:moreKeys="!text/more_keys_for_symbols_2" /> + latin:keySpec="!text/keyspec_symbols_2" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_2" + latin:moreKeys="!text/morekeys_symbols_2" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_3" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_3" - latin:moreKeys="!text/more_keys_for_symbols_3" /> + latin:keySpec="!text/keyspec_symbols_3" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_3" + latin:moreKeys="!text/morekeys_symbols_3" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_4" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_4" - latin:moreKeys="!text/more_keys_for_symbols_4" /> + latin:keySpec="!text/keyspec_symbols_4" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_4" + latin:moreKeys="!text/morekeys_symbols_4" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_5" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_5" - latin:moreKeys="!text/more_keys_for_symbols_5" /> + latin:keySpec="!text/keyspec_symbols_5" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_5" + latin:moreKeys="!text/morekeys_symbols_5" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_6" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_6" - latin:moreKeys="!text/more_keys_for_symbols_6" /> + latin:keySpec="!text/keyspec_symbols_6" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_6" + latin:moreKeys="!text/morekeys_symbols_6" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_7" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_7" - latin:moreKeys="!text/more_keys_for_symbols_7" /> + latin:keySpec="!text/keyspec_symbols_7" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_7" + latin:moreKeys="!text/morekeys_symbols_7" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_8" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_8" - latin:moreKeys="!text/more_keys_for_symbols_8" /> + latin:keySpec="!text/keyspec_symbols_8" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_8" + latin:moreKeys="!text/morekeys_symbols_8" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_9" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_9" - latin:moreKeys="!text/more_keys_for_symbols_9" /> + latin:keySpec="!text/keyspec_symbols_9" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_9" + latin:moreKeys="!text/morekeys_symbols_9" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_0" - latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_0" - latin:moreKeys="!text/more_keys_for_symbols_0" /> + latin:keySpec="!text/keyspec_symbols_0" + latin:additionalMoreKeys="!text/additional_morekeys_symbols_0" + latin:moreKeys="!text/morekeys_symbols_0" /> </merge> diff --git a/java/res/xml/rowkeys_symbols2.xml b/java/res/xml/rowkeys_symbols2.xml index 76cbf6259..811915825 100644 --- a/java/res/xml/rowkeys_symbols2.xml +++ b/java/res/xml/rowkeys_symbols2.xml @@ -28,37 +28,37 @@ <!-- U+066C: "٬" ARABIC THOUSANDS SEPARATOR U+066B: "٫" ARABIC DECIMAL SEPARATOR --> <Key - latin:keyLabel="٬" + latin:keySpec="٬" latin:keyHintLabel="\@" latin:moreKeys="\@" /> <Key - latin:keyLabel="٫" + latin:keySpec="٫" latin:keyHintLabel="\#" latin:moreKeys="\#" /> </case> <default> <Key - latin:keyLabel="\@" /> + latin:keySpec="\@" /> <Key - latin:keyLabel="\#" /> + latin:keySpec="\#" /> </default> </switch> <Key latin:keyStyle="currencyKeyStyle" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_percent" - latin:moreKeys="!text/more_keys_for_symbols_percent" /> + latin:keySpec="!text/keyspec_symbols_percent" + latin:moreKeys="!text/morekeys_symbols_percent" /> <Key - latin:keyLabel="&" /> + latin:keySpec="&" /> <!-- U+2013: "–" EN DASH U+2014: "—" EM DASH U+00B7: "·" MIDDLE DOT --> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:moreKeys="_,–,—,·" /> <Key - latin:keyLabel="+" - latin:moreKeys="!text/more_keys_for_plus" /> + latin:keySpec="+" + latin:moreKeys="!text/morekeys_plus" /> <include latin:keyboardLayout="@xml/keys_parentheses" /> </merge> diff --git a/java/res/xml/rowkeys_symbols3.xml b/java/res/xml/rowkeys_symbols3.xml index 074078cb6..8093081f8 100644 --- a/java/res/xml/rowkeys_symbols3.xml +++ b/java/res/xml/rowkeys_symbols3.xml @@ -22,41 +22,37 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="*" - latin:moreKeys="!text/more_keys_for_star" /> + latin:keySpec="*" + latin:moreKeys="!text/morekeys_star" /> <switch> <case latin:languageCode="fa" > - <!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> <Key - latin:keyLabel="«" - latin:code="0x00BB" - latin:moreKeys="!text/more_keys_for_double_quote" /> + latin:keySpec="!text/keyspec_left_double_angle_quote" + latin:moreKeys="!text/morekeys_double_quote" /> <Key - latin:keyLabel="»" - latin:code="0x00AB" - latin:moreKeys="!text/more_keys_for_single_quote" /> + latin:keySpec="!text/keyspec_right_double_angle_quote" + latin:moreKeys="!text/morekeys_single_quote" /> </case> <default> <Key - latin:keyLabel=""" - latin:moreKeys="!text/more_keys_for_double_quote" /> + latin:keySpec=""" + latin:moreKeys="!text/morekeys_double_quote" /> <Key - latin:keyLabel="\'" - latin:moreKeys="!text/more_keys_for_single_quote" /> + latin:keySpec="\'" + latin:moreKeys="!text/morekeys_single_quote" /> </default> </switch> <Key - latin:keyLabel=":" /> + latin:keySpec=":" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_semicolon" - latin:moreKeys="!text/more_keys_for_symbols_semicolon" /> + latin:keySpec="!text/keyspec_symbols_semicolon" + latin:moreKeys="!text/morekeys_symbols_semicolon" /> <Key - latin:keyLabel="!" - latin:moreKeys="!text/more_keys_for_symbols_exclamation" /> + latin:keySpec="!" + latin:moreKeys="!text/morekeys_exclamation" /> <Key - latin:keyLabel="!text/keylabel_for_symbols_question" - latin:moreKeys="!text/more_keys_for_symbols_question" /> + latin:keySpec="!text/keyspec_symbols_question" + latin:moreKeys="!text/morekeys_question" /> </merge> diff --git a/java/res/xml/rowkeys_symbols_shift1.xml b/java/res/xml/rowkeys_symbols_shift1.xml index 6013493e5..f232a7de2 100644 --- a/java/res/xml/rowkeys_symbols_shift1.xml +++ b/java/res/xml/rowkeys_symbols_shift1.xml @@ -22,35 +22,35 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="~" /> + latin:keySpec="~" /> <Key - latin:keyLabel="`" /> + latin:keySpec="`" /> <Key - latin:keyLabel="|" /> + latin:keySpec="|" /> <!-- U+2022: "•" BULLET --> <Key - latin:keyLabel="•" - latin:moreKeys="!text/more_keys_for_bullet" /> + latin:keySpec="•" + latin:moreKeys="!text/morekeys_bullet" /> <!-- U+221A: "√" SQUARE ROOT --> <Key - latin:keyLabel="√" /> - <!-- U+03A0: "Π" GREEK CAPITAL LETTER PI - U+03C0: "π" GREEK SMALL LETTER PI --> + latin:keySpec="√" /> + <!-- U+03C0: "π" GREEK SMALL LETTER PI + U+03A0: "Π" GREEK CAPITAL LETTER PI --> <Key - latin:keyLabel="Π" - latin:moreKeys="π" /> + latin:keySpec="π" + latin:moreKeys="Π" /> <!-- U+00F7: "÷" DIVISION SIGN --> <Key - latin:keyLabel="÷" /> + latin:keySpec="÷" /> <!-- U+00D7: "×" MULTIPLICATION SIGN --> <Key - latin:keyLabel="×" /> + latin:keySpec="×" /> <!-- U+00B6: "¶" PILCROW SIGN U+00A7: "§" SECTION SIGN --> <Key - latin:keyLabel="¶" + latin:keySpec="¶" latin:moreKeys="§" /> <!-- U+2206: "∆" INCREMENT --> <Key - latin:keyLabel="∆" /> + latin:keySpec="∆" /> </merge> diff --git a/java/res/xml/rowkeys_symbols_shift2.xml b/java/res/xml/rowkeys_symbols_shift2.xml index 36f92143f..39a58030b 100644 --- a/java/res/xml/rowkeys_symbols_shift2.xml +++ b/java/res/xml/rowkeys_symbols_shift2.xml @@ -34,19 +34,19 @@ U+2190: "←" LEFTWARDS ARROW U+2192: "→" RIGHTWARDS ARROW --> <Key - latin:keyLabel="^" + latin:keySpec="^" latin:moreKeys="↑,↓,←,→" /> <!-- U+00B0: "°" DEGREE SIGN U+2032: "′" PRIME U+2033: "″" DOUBLE PRIME --> <Key - latin:keyLabel="°" + latin:keySpec="°" latin:moreKeys="′,″" /> <!-- U+2260: "≠" NOT EQUAL TO U+2248: "≈" ALMOST EQUAL TO U+221E: "∞" INFINITY --> <Key - latin:keyLabel="=" + latin:keySpec="=" latin:moreKeys="≠,≈,∞" /> <include latin:keyboardLayout="@xml/keys_curly_brackets" /> diff --git a/java/res/xml/rowkeys_symbols_shift3.xml b/java/res/xml/rowkeys_symbols_shift3.xml index 5fe1c7450..92ff97bb0 100644 --- a/java/res/xml/rowkeys_symbols_shift3.xml +++ b/java/res/xml/rowkeys_symbols_shift3.xml @@ -22,19 +22,19 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="\\" /> + latin:keySpec="\\" /> <!-- U+00A9: "©" COPYRIGHT SIGN --> <Key - latin:keyLabel="©" /> + latin:keySpec="©" /> <!-- U+00AE: "®" REGISTERED SIGN --> <Key - latin:keyLabel="®" /> + latin:keySpec="®" /> <!-- U+2122: "™" TRADE MARK SIGN --> <Key - latin:keyLabel="™" /> + latin:keySpec="™" /> <!-- U+2105: "℅" CARE OF --> <Key - latin:keyLabel="℅" /> + latin:keySpec="℅" /> <include latin:keyboardLayout="@xml/keys_square_brackets" /> </merge> diff --git a/java/res/xml/rowkeys_thai1.xml b/java/res/xml/rowkeys_thai1.xml index cd536656f..e42bda391 100644 --- a/java/res/xml/rowkeys_thai1.xml +++ b/java/res/xml/rowkeys_thai1.xml @@ -26,77 +26,76 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel="+" /> + latin:keySpec="+" /> <!-- U+0E51: "๑" THAI DIGIT ONE --> <Key - latin:keyLabel="๑" + latin:keySpec="๑" latin:keyLabelFlags="fontNormal" /> <!-- U+0E52: "๒" THAI DIGIT TWO --> <Key - latin:keyLabel="๒" + latin:keySpec="๒" latin:keyLabelFlags="fontNormal" /> <!-- U+0E53: "๓" THAI DIGIT THREE --> <Key - latin:keyLabel="๓" + latin:keySpec="๓" latin:keyLabelFlags="fontNormal" /> <!-- U+0E54: "๔" THAI DIGIT FOUR --> <Key - latin:keyLabel="๔" + latin:keySpec="๔" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E39: " ู" THAI CHARACTER SARA UU --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ู" - latin:code="0x0E39" + latin:keySpec=" ู|ู" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT --> <Key - latin:keyLabel="฿" + latin:keySpec="฿" latin:keyLabelFlags="fontNormal" /> <!-- U+0E55: "๕" THAI DIGIT FIVE --> <Key - latin:keyLabel="๕" + latin:keySpec="๕" latin:keyLabelFlags="fontNormal" /> <!-- U+0E56: "๖" THAI DIGIT SIX --> <Key - latin:keyLabel="๖" + latin:keySpec="๖" latin:keyLabelFlags="fontNormal" /> <!-- U+0E57: "๗" THAI DIGIT SEVEN --> <Key - latin:keyLabel="๗" + latin:keySpec="๗" latin:keyLabelFlags="fontNormal" /> <!-- U+0E58: "๘" THAI DIGIT EIGHT --> <Key - latin:keyLabel="๘" + latin:keySpec="๘" latin:keyLabelFlags="fontNormal" /> <!-- U+0E59: "๙" THAI DIGIT NINE --> <Key - latin:keyLabel="๙" + latin:keySpec="๙" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+0E45: "ๅ" THAI CHARACTER LAKKHANGYAO --> <Key - latin:keyLabel="ๅ" + latin:keySpec="ๅ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E51: "๑" THAI DIGIT ONE --> <Key latin:keyHintLabel="1" latin:additionalMoreKeys="1" latin:moreKeys="๑" - latin:keyLabel="/" /> + latin:keySpec="/" /> <!-- U+0E52: "๒" THAI DIGIT TWO --> <Key latin:keyHintLabel="2" latin:additionalMoreKeys="2" latin:moreKeys="๒" - latin:keyLabel="_" /> + latin:keySpec="_" /> <!-- U+0E20: "ภ" THAI CHARACTER PHO SAMPHAO U+0E53: "๓" THAI DIGIT THREE --> <Key - latin:keyLabel="ภ" + latin:keySpec="ภ" latin:keyHintLabel="3" latin:additionalMoreKeys="3" latin:moreKeys="๓" @@ -104,7 +103,7 @@ <!-- U+0E16: "ถ" THAI CHARACTER THO THUNG U+0E54: "๔" THAI DIGIT FOUR --> <Key - latin:keyLabel="ถ" + latin:keySpec="ถ" latin:keyHintLabel="4" latin:additionalMoreKeys="4" latin:moreKeys="๔" @@ -114,21 +113,19 @@ <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ุ" - latin:code="0x0E38" + latin:keySpec=" ุ|ุ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E36: " ึ" THAI CHARACTER SARA UE --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ึ" - latin:code="0x0E36" + latin:keySpec=" ึ|ึ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E04: "ค" THAI CHARACTER KHO KHWAI U+0E55: "๕" THAI DIGIT FIVE --> <Key - latin:keyLabel="ค" + latin:keySpec="ค" latin:keyHintLabel="5" latin:additionalMoreKeys="5" latin:moreKeys="๕" @@ -136,7 +133,7 @@ <!-- U+0E15: "ต" THAI CHARACTER TO TAO U+0E56: "๖" THAI DIGIT SIX --> <Key - latin:keyLabel="ต" + latin:keySpec="ต" latin:keyHintLabel="6" latin:additionalMoreKeys="6" latin:moreKeys="๖" @@ -144,7 +141,7 @@ <!-- U+0E08: "จ" THAI CHARACTER CHO CHAN U+0E57: "๗" THAI DIGIT SEVEN --> <Key - latin:keyLabel="จ" + latin:keySpec="จ" latin:keyHintLabel="7" latin:additionalMoreKeys="7" latin:moreKeys="๗" @@ -152,7 +149,7 @@ <!-- U+0E02: "ข" THAI CHARACTER KHO KHAI U+0E58: "๘" THAI DIGIT EIGHT --> <Key - latin:keyLabel="ข" + latin:keySpec="ข" latin:keyHintLabel="8" latin:additionalMoreKeys="8" latin:moreKeys="๘" @@ -160,7 +157,7 @@ <!-- U+0E0A: "ช" THAI CHARACTER CHO CHANG U+0E59: "๙" THAI DIGIT NINE --> <Key - latin:keyLabel="ช" + latin:keySpec="ช" latin:keyHintLabel="9" latin:additionalMoreKeys="9" latin:moreKeys="๙" diff --git a/java/res/xml/rowkeys_thai2.xml b/java/res/xml/rowkeys_thai2.xml index 4bcbbbf8d..7ab036a05 100644 --- a/java/res/xml/rowkeys_thai2.xml +++ b/java/res/xml/rowkeys_thai2.xml @@ -27,117 +27,113 @@ > <!-- U+0E50: "๐" THAI DIGIT ZERO --> <Key - latin:keyLabel="๐" + latin:keySpec="๐" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel=""" /> + latin:keySpec=""" /> <!-- U+0E0E: "ฎ" THAI CHARACTER DO CHADA --> <Key - latin:keyLabel="ฎ" + latin:keySpec="ฎ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E11: "ฑ" THAI CHARACTER THO NANGMONTHO --> <Key - latin:keyLabel="ฑ" + latin:keySpec="ฑ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E18: "ธ" THAI CHARACTER THO THONG --> <Key - latin:keyLabel="ธ" + latin:keySpec="ธ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E4D: " ํ" THAI CHARACTER THANTHAKHAT --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ํ" - latin:code="0x0E4D" + latin:keySpec=" ํ|ํ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E4A: " ๊" THAI CHARACTER MAI TRI --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ๊" - latin:code="0x0E4A" + latin:keySpec=" ๊|๊" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E13: "ณ" THAI CHARACTER NO NEN --> <Key - latin:keyLabel="ณ" + latin:keySpec="ณ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2F: "ฯ" THAI CHARACTER PAIYANNOI --> <Key - latin:keyLabel="ฯ" + latin:keySpec="ฯ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E0D: "ญ" THAI CHARACTER YO YING --> <Key - latin:keyLabel="ญ" + latin:keySpec="ญ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E10: "ฐ" THAI CHARACTER THO THAN --> <Key - latin:keyLabel="ฐ" + latin:keySpec="ฐ" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="," /> + latin:keySpec="," /> </case> <default> <!-- U+0E46: "ๆ" THAI CHARACTER MAIYAMOK U+0E50: "๐" THAI DIGIT ZERO --> <Key - latin:keyLabel="ๆ" + latin:keySpec="ๆ" latin:keyHintLabel="0" latin:additionalMoreKeys="0" latin:moreKeys="๐" latin:keyLabelFlags="fontNormal" /> <!-- U+0E44: "ไ" THAI CHARACTER SARA AI MAIMALAI --> <Key - latin:keyLabel="ไ" + latin:keySpec="ไ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E33: "ำ" THAI CHARACTER SARA AM --> <Key - latin:keyLabel="ำ" + latin:keySpec="ำ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E1E: "พ" THAI CHARACTER PHO PHAN --> <Key - latin:keyLabel="พ" + latin:keySpec="พ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E30: "ะ" THAI CHARACTER SARA A --> <Key - latin:keyLabel="ะ" + latin:keySpec="ะ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E31: " ั" THAI CHARACTER MAI HAN-AKAT --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ั" - latin:code="0x0E31" + latin:keySpec=" ั|ั" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E35: " ี" HAI CHARACTER SARA II --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ี" - latin:code="0x0E35" + latin:keySpec=" ี|ี" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E23: "ร" THAI CHARACTER RO RUA --> <Key - latin:keyLabel="ร" + latin:keySpec="ร" latin:keyLabelFlags="fontNormal" /> <!-- U+0E19: "น" THAI CHARACTER NO NU --> <Key - latin:keyLabel="น" + latin:keySpec="น" latin:keyLabelFlags="fontNormal" /> <!-- U+0E22: "ย" THAI CHARACTER YO YAK --> <Key - latin:keyLabel="ย" + latin:keySpec="ย" latin:keyLabelFlags="fontNormal" /> <!-- U+0E1A: "บ" THAI CHARACTER BO BAIMAI --> <Key - latin:keyLabel="บ" + latin:keySpec="บ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E25: "ล" THAI CHARACTER LO LING --> <Key - latin:keyLabel="ล" + latin:keySpec="ล" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_thai3.xml b/java/res/xml/rowkeys_thai3.xml index 7b6e6372e..098d8a780 100644 --- a/java/res/xml/rowkeys_thai3.xml +++ b/java/res/xml/rowkeys_thai3.xml @@ -27,107 +27,103 @@ > <!-- U+0E24: "ฤ" THAI CHARACTER RU --> <Key - latin:keyLabel="ฤ" + latin:keySpec="ฤ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E06: "ฆ" THAI CHARACTER KHO RAKHANG --> <Key - latin:keyLabel="ฆ" + latin:keySpec="ฆ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E0F: "ฏ" THAI CHARACTER TO PATAK --> <Key - latin:keyLabel="ฏ" + latin:keySpec="ฏ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E42: "โ" THAI CHARACTER SARA O --> <Key - latin:keyLabel="โ" + latin:keySpec="โ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E0C: "ฌ" THAI CHARACTER CHO CHOE --> <Key - latin:keyLabel="ฌ" + latin:keySpec="ฌ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E47: " ็" THAI CHARACTER MAITAIKHU --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ็" - latin:code="0x0E47" + latin:keySpec=" ็|็" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E4B: " ๋" THAI CHARACTER MAI CHATTAWA --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ๋" - latin:code="0x0E4B" + latin:keySpec=" ๋|๋" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E29: "ษ" THAI CHARACTER SO RUSI --> <Key - latin:keyLabel="ษ" + latin:keySpec="ษ" latin:keyLabelFlags="fontNormal" /> - <!-- U+0E28: "ศ" THAI CHARACTER SO SALA --> + <!-- U+0E28: "ศ" THAI CHARACTER SO SALA --> <Key - latin:keyLabel="ศ" + latin:keySpec="ศ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E0B: "ซ" THAI CHARACTER SO SO --> <Key - latin:keyLabel="ซ" + latin:keySpec="ซ" latin:keyLabelFlags="fontNormal" /> <Key - latin:keyLabel="." /> + latin:keySpec="." /> </case> <default> <!-- U+0E1F: "ฟ" THAI CHARACTER FO FAN --> <Key - latin:keyLabel="ฟ" + latin:keySpec="ฟ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2B: "ห" THAI CHARACTER HO HIP --> <Key - latin:keyLabel="ห" + latin:keySpec="ห" latin:keyLabelFlags="fontNormal" /> <!-- U+0E01: "ก" THAI CHARACTER KO KAI --> <Key - latin:keyLabel="ก" + latin:keySpec="ก" latin:keyLabelFlags="fontNormal" /> <!-- U+0E14: "ด" THAI CHARACTER DO DEK --> <Key - latin:keyLabel="ด" + latin:keySpec="ด" latin:keyLabelFlags="fontNormal" /> <!-- U+0E40: "เ" THAI CHARACTER SARA E --> <Key - latin:keyLabel="เ" + latin:keySpec="เ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E49: " ้" THAI CHARACTER MAI THO --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ้" - latin:code="0x0E49" + latin:keySpec=" ้|้" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E48: " ่" THAI CHARACTER MAI EK --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ่" - latin:code="0x0E48" + latin:keySpec=" ่|่" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E32: "า" THAI CHARACTER SARA AA --> <Key - latin:keyLabel="า" + latin:keySpec="า" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2A: "ส" THAI CHARACTER SO SUA --> <Key - latin:keyLabel="ส" + latin:keySpec="ส" latin:keyLabelFlags="fontNormal" /> <!-- U+0E27: "ว" THAI CHARACTER WO WAEN --> <Key - latin:keyLabel="ว" + latin:keySpec="ว" latin:keyLabelFlags="fontNormal" /> <!-- U+0E07: "ง" THAI CHARACTER NGO NGU --> <Key - latin:keyLabel="ง" + latin:keySpec="ง" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rowkeys_thai4.xml b/java/res/xml/rowkeys_thai4.xml index 8a784242c..332d09d7e 100644 --- a/java/res/xml/rowkeys_thai4.xml +++ b/java/res/xml/rowkeys_thai4.xml @@ -26,96 +26,92 @@ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" > <Key - latin:keyLabel="(" /> + latin:keySpec="(" /> <Key - latin:keyLabel=")" /> + latin:keySpec=")" /> <!-- U+0E09: "ฉ" THAI CHARACTER CHO CHING --> <Key - latin:keyLabel="ฉ" + latin:keySpec="ฉ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2E: "ฮ" THAI CHARACTER HO NOKHUK --> <Key - latin:keyLabel="ฮ" + latin:keySpec="ฮ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E3A: " ฺ" THAI CHARACTER PHINTHU --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ฺ" - latin:code="0x0E3A" + latin:keySpec=" ฺ|ฺ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E4C: " ์" THAI CHARACTER THANTHAKHAT --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ์" - latin:code="0x0E4C" + latin:keySpec=" ์|์" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <Key - latin:keyLabel="\?" /> + latin:keySpec="\?" /> <!-- U+0E12: "ฒ" THAI CHARACTER THO PHUTHAO --> <Key - latin:keyLabel="ฒ" + latin:keySpec="ฒ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2C: "ฬ" THAI CHARACTER LO CHULA --> <Key - latin:keyLabel="ฬ" + latin:keySpec="ฬ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E26: "ฦ" THAI CHARACTER LU --> <Key - latin:keyLabel="ฦ" + latin:keySpec="ฦ" latin:keyLabelFlags="fontNormal" /> </case> <default> <!-- U+0E1C: "ผ" THAI CHARACTER PHO PHUNG --> <Key - latin:keyLabel="ผ" + latin:keySpec="ผ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E1B: "ป" THAI CHARACTER PO PLA --> <Key - latin:keyLabel="ป" + latin:keySpec="ป" latin:keyLabelFlags="fontNormal" /> <!-- U+0E41: "แ" THAI CHARACTER SARA AE --> <Key - latin:keyLabel="แ" + latin:keySpec="แ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E2D: "อ" THAI CHARACTER O ANG --> <Key - latin:keyLabel="อ" + latin:keySpec="อ" latin:keyLabelFlags="fontNormal" /> <!-- U+0020: " " SPACE U+0E34: " ิ" THAI CHARACTER SARA I --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ิ" - latin:code="0x0E34" + latin:keySpec=" ิ|ิ" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0020: " " SPACE U+0E37: " ื" THAI CHARACTER SARA UEE --> <!-- Note: The space character is needed as a preceding letter to draw some Thai composing characters correctly. --> <Key - latin:keyLabel=" ื" - latin:code="0x0E37" + latin:keySpec=" ื|ื" latin:keyLabelFlags="fontNormal|followKeyLetterRatio" /> <!-- U+0E17: "ท" THAI CHARACTER THO THAHAN --> <Key - latin:keyLabel="ท" + latin:keySpec="ท" latin:keyLabelFlags="fontNormal" /> <!-- U+0E21: "ม" THAI CHARACTER MO MA --> <Key - latin:keyLabel="ม" + latin:keySpec="ม" latin:keyLabelFlags="fontNormal" /> <!-- U+0E43: "ใ" THAI CHARACTER SARA AI MAIMUAN --> <Key - latin:keyLabel="ใ" + latin:keySpec="ใ" latin:keyLabelFlags="fontNormal" /> <!-- U+0E1D: "ฝ" THAI CHARACTER FO FA --> <Key - latin:keyLabel="ฝ" + latin:keySpec="ฝ" latin:keyLabelFlags="fontNormal" /> </default> </switch> diff --git a/java/res/xml/rows_colemak.xml b/java/res/xml/rows_colemak.xml index d74c2c9ec..ec553c244 100644 --- a/java/res/xml/rows_colemak.xml +++ b/java/res/xml/rows_colemak.xml @@ -28,8 +28,6 @@ > <include latin:keyboardLayout="@xml/rowkeys_colemak1" /> - <include - latin:keyboardLayout="@xml/key_colemak_colon" /> </Row> <Row latin:keyWidth="10%p" diff --git a/java/res/xml/rows_greek.xml b/java/res/xml/rows_greek.xml index ca6d24005..e00b927a0 100644 --- a/java/res/xml/rows_greek.xml +++ b/java/res/xml/rows_greek.xml @@ -27,8 +27,6 @@ latin:keyWidth="10%p" > <include - latin:keyboardLayout="@xml/key_greek_semicolon" /> - <include latin:keyboardLayout="@xml/rowkeys_greek1" /> </Row> <Row diff --git a/java/res/xml/rows_hindi_compact.xml b/java/res/xml/rows_hindi_compact.xml new file mode 100644 index 000000000..a60cf2b02 --- /dev/null +++ b/java/res/xml/rows_hindi_compact.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact1" /> + </Row> + <Row + latin:keyWidth="9.091%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact2" /> + </Row> + <Row + latin:keyWidth="9.091%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_hindi_compact3" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml/rows_myanmar.xml b/java/res/xml/rows_myanmar.xml new file mode 100644 index 000000000..5de47f7b8 --- /dev/null +++ b/java/res/xml/rows_myanmar.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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="10.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar1" /> + </Row> + <Row + latin:keyWidth="10.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar2" /> + </Row> + <Row + latin:keyWidth="10.0%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_myanmar3" /> + </Row> + <Row + latin:keyWidth="10.0%p" + > + <Key + latin:keyStyle="shiftKeyStyle" /> + <include + latin:keyboardLayout="@xml/rowkeys_myanmar4" /> + <Key + latin:keyStyle="deleteKeyStyle" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml index 291018a14..859a1624a 100644 --- a/java/res/xml/rows_number_normal.xml +++ b/java/res/xml/rows_number_normal.xml @@ -23,16 +23,16 @@ > <Row> <Key - latin:keyLabel="1" + latin:keySpec="1" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="2" + latin:keySpec="2" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="3" + latin:keySpec="3" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:moreKeys="+" latin:keyLabelFlags="hasPopupHint" latin:keyStyle="numFunctionalKeyStyle" @@ -40,20 +40,20 @@ </Row> <Row> <Key - latin:keyLabel="4" + latin:keySpec="4" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="5" + latin:keySpec="5" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="6" + latin:keySpec="6" latin:keyStyle="numKeyStyle" /> <switch> <case latin:mode="date" > <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numFunctionalKeyStyle" latin:keyWidth="fillRight" /> </case> @@ -61,15 +61,15 @@ latin:mode="time|datetime" > <Key - latin:keyLabel="." + latin:keySpec="." latin:keyLabelFlags="hasPopupHint" - latin:moreKeys="!text/more_keys_for_am_pm" + latin:moreKeys="!text/morekeys_am_pm" latin:keyStyle="numFunctionalKeyStyle" latin:keyWidth="fillRight" /> </case> <default> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyStyle="numFunctionalKeyStyle" latin:keyWidth="fillRight" /> </default> @@ -77,13 +77,13 @@ </Row> <Row> <Key - latin:keyLabel="7" + latin:keySpec="7" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="8" + latin:keySpec="8" latin:keyStyle="numKeyStyle"/> <Key - latin:keyLabel="9" + latin:keySpec="9" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="deleteKeyStyle" @@ -93,36 +93,34 @@ <Key latin:keyStyle="numSpaceKeyStyle" /> <Key - latin:keyLabel="0" + latin:keySpec="0" latin:keyStyle="numKeyStyle" /> <switch> <case latin:mode="date" > <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyStyle="numKeyStyle" /> </case> <case latin:mode="time" > <Key - latin:keyLabel=":" + latin:keySpec=":" latin:keyStyle="numKeyStyle" /> </case> <case latin:mode="datetime" > - <!-- U+002F: "/" SOLIDUS --> <Key - latin:code="0x002F" - latin:keyLabel="/ :" + latin:keySpec="/ :|/" latin:moreKeys="!noPanelAutoMoreKey!,:" latin:keyStyle="numKeyStyle" /> </case> <default> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numKeyStyle" /> </default> </switch> diff --git a/java/res/xml/rows_pcqwerty.xml b/java/res/xml/rows_pcqwerty.xml index 884698963..a5ed74518 100644 --- a/java/res/xml/rows_pcqwerty.xml +++ b/java/res/xml/rows_pcqwerty.xml @@ -26,19 +26,8 @@ <Row latin:keyWidth="7.692%p" > - <switch> - <case - latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted" - > - <include - latin:keyboardLayout="@xml/rowkeys_pcqwerty1" /> - </case> - <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" --> - <default> - <include - latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/rowkeys_pcqwerty1" /> </Row> <Row latin:keyWidth="7.692%p" diff --git a/java/res/xml/rows_phone.xml b/java/res/xml/rows_phone.xml index d8dcfbd62..03e45419a 100644 --- a/java/res/xml/rows_phone.xml +++ b/java/res/xml/rows_phone.xml @@ -33,7 +33,7 @@ <Key latin:keyStyle="num3KeyStyle" /> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:moreKeys="+" latin:keyLabelFlags="hasPopupHint" latin:keyStyle="numFunctionalKeyStyle" @@ -47,7 +47,7 @@ <Key latin:keyStyle="num6KeyStyle" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numFunctionalKeyStyle" latin:keyWidth="fillRight" /> </Row> @@ -68,8 +68,7 @@ <!-- U+0030: "0" DIGIT ZERO --> <Key latin:keyStyle="num0KeyStyle" - latin:code="0x0030" - latin:keyLabel="0 +" + latin:keySpec="0 +|0" latin:moreKeys="!noPanelAutoMoreKey!,+" /> <Key latin:keyStyle="numSpaceKeyStyle" /> diff --git a/java/res/xml/rows_phone_symbols.xml b/java/res/xml/rows_phone_symbols.xml index 8c10a2d71..983bfb5c8 100644 --- a/java/res/xml/rows_phone_symbols.xml +++ b/java/res/xml/rows_phone_symbols.xml @@ -27,16 +27,16 @@ latin:keyboardLayout="@xml/key_styles_number" /> <Row> <Key - latin:keyLabel="(" + latin:keySpec="(" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="/" + latin:keySpec="/" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel=")" + latin:keySpec=")" latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="-" + latin:keySpec="-" latin:moreKeys="+" latin:keyLabelFlags="hasPopupHint" latin:keyStyle="numFunctionalKeyStyle" @@ -44,17 +44,17 @@ </Row> <Row> <Key - latin:keyLabel="N" + latin:keySpec="N" latin:keyStyle="numKeyBaseStyle" /> <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this has changed. --> <Key latin:keyStyle="numPauseKeyStyle" /> <Key - latin:keyLabel="," + latin:keySpec="," latin:keyStyle="numKeyStyle" /> <Key - latin:keyLabel="." + latin:keySpec="." latin:keyStyle="numFunctionalKeyStyle" latin:keyWidth="fillRight" /> </Row> @@ -65,7 +65,7 @@ <Key latin:keyStyle="numWaitKeyStyle" /> <Key - latin:keyLabel="\#" + latin:keySpec="\#" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="deleteKeyStyle" @@ -75,7 +75,7 @@ <Key latin:keyStyle="numPhoneToNumericKeyStyle" /> <Key - latin:keyLabel="+" + latin:keySpec="+" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="numSpaceKeyStyle" /> diff --git a/java/res/xml/rows_swiss.xml b/java/res/xml/rows_swiss.xml new file mode 100644 index 000000000..03e412940 --- /dev/null +++ b/java/res/xml/rows_swiss.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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" + > + <include + latin:keyboardLayout="@xml/rowkeys_swiss1" /> + </Row> + <Row + latin:keyWidth="9.091%p" + > + <include + latin:keyboardLayout="@xml/rowkeys_swiss2" /> + </Row> + <Row + latin:keyWidth="9.2%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="15%p" + latin:visualInsetsRight="1%p" /> + <Spacer + latin:keyWidth="2.8%p" /> + <include + latin:keyboardLayout="@xml/rowkeys_qwertz3" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-15%p" + latin:keyWidth="fillRight" + latin:visualInsetsLeft="1%p" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml/rows_symbols.xml b/java/res/xml/rows_symbols.xml index d0606c63b..6fd876f4e 100644 --- a/java/res/xml/rows_symbols.xml +++ b/java/res/xml/rows_symbols.xml @@ -54,6 +54,7 @@ </Row> <Row latin:keyWidth="10%p" + latin:backgroundType="functional" > <Key latin:keyStyle="toAlphaKeyStyle" diff --git a/java/res/xml/rows_symbols_shift.xml b/java/res/xml/rows_symbols_shift.xml index c4bdb9f38..64f6e6114 100644 --- a/java/res/xml/rows_symbols_shift.xml +++ b/java/res/xml/rows_symbols_shift.xml @@ -54,6 +54,7 @@ </Row> <Row latin:keyWidth="10%p" + latin:backgroundType="functional" > <Key latin:keyStyle="toAlphaKeyStyle" diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java index c628c5b09..ec1ab3565 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java @@ -17,17 +17,13 @@ package com.android.inputmethod.accessibility; import android.graphics.Rect; -import android.inputmethodservice.InputMethodService; import android.os.Bundle; -import android.os.SystemClock; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; import android.support.v4.view.accessibility.AccessibilityRecordCompat; import android.util.Log; -import android.util.SparseArray; -import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.EditorInfo; @@ -37,9 +33,10 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; -import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; +import java.util.List; + /** * Exposes a virtual view sub-tree for {@link KeyboardView} and generates * {@link AccessibilityEvent}s for individual {@link Key}s. @@ -54,13 +51,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider private static final String TAG = AccessibilityEntityProvider.class.getSimpleName(); private static final int UNDEFINED = Integer.MIN_VALUE; - private final InputMethodService mInputMethodService; private final KeyCodeDescriptionMapper mKeyCodeDescriptionMapper; private final AccessibilityUtils mAccessibilityUtils; - /** A map of integer IDs to {@link Key}s. */ - private final SparseArray<Key> mVirtualViewIdToKey = CollectionUtils.newSparseArray(); - /** Temporary rect used to calculate in-screen bounds. */ private final Rect mTempBoundsInScreen = new Rect(); @@ -73,9 +66,10 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider /** The current keyboard view. */ private KeyboardView mKeyboardView; - public AccessibilityEntityProvider(final KeyboardView keyboardView, - final InputMethodService inputMethod) { - mInputMethodService = inputMethod; + /** The current keyboard. */ + private Keyboard mKeyboard; + + public AccessibilityEntityProvider(final KeyboardView keyboardView) { mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance(); setView(keyboardView); @@ -92,14 +86,43 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider // Since this class is constructed lazily, we might not get a subsequent // call to setKeyboard() and therefore need to call it now. - setKeyboard(); + setKeyboard(keyboardView.getKeyboard()); } /** * Sets the keyboard represented by this node provider. + * + * @param keyboard The keyboard that is being set to the keyboard view. */ - public void setKeyboard() { - assignVirtualViewIds(); + public void setKeyboard(final Keyboard keyboard) { + mKeyboard = keyboard; + } + + private Key getKeyOf(final int virtualViewId) { + if (mKeyboard == null) { + return null; + } + final List<Key> sortedKeys = mKeyboard.getSortedKeys(); + // Use a virtual view id as an index of the sorted keys list. + if (virtualViewId >= 0 && virtualViewId < sortedKeys.size()) { + return sortedKeys.get(virtualViewId); + } + return null; + } + + private int getVirtualViewIdOf(final Key key) { + if (mKeyboard == null) { + return View.NO_ID; + } + final List<Key> sortedKeys = mKeyboard.getSortedKeys(); + final int size = sortedKeys.size(); + for (int index = 0; index < size; index++) { + if (sortedKeys.get(index) == key) { + // Use an index of the sorted keys list as a virtual view id. + return index; + } + } + return View.NO_ID; } /** @@ -112,7 +135,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @see AccessibilityEvent */ public AccessibilityEvent createAccessibilityEvent(final Key key, final int eventType) { - final int virtualViewId = generateVirtualViewIdForKey(key); + final int virtualViewId = getVirtualViewIdOf(key); final String keyDescription = getKeyDescription(key); final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setPackageName(mKeyboardView.getContext().getPackageName()); @@ -158,17 +181,21 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider ViewCompat.onInitializeAccessibilityNodeInfo(mKeyboardView, rootInfo); // Add the virtual children of the root View. - final Keyboard keyboard = mKeyboardView.getKeyboard(); - final Key[] keys = keyboard.getKeys(); - for (Key key : keys) { - final int childVirtualViewId = generateVirtualViewIdForKey(key); - rootInfo.addChild(mKeyboardView, childVirtualViewId); + final List<Key> sortedKeys = mKeyboard.getSortedKeys(); + final int size = sortedKeys.size(); + for (int index = 0; index < size; index++) { + final Key key = sortedKeys.get(index); + if (key.isSpacer()) { + continue; + } + // Use an index of the sorted keys list as a virtual view id. + rootInfo.addChild(mKeyboardView, index); } return rootInfo; } - // Find the view that corresponds to the given id. - final Key key = mVirtualViewIdToKey.get(virtualViewId); + // Find the key that corresponds to the given virtual view id. + final Key key = getKeyOf(virtualViewId); if (key == null) { Log.e(TAG, "Invalid virtual view ID: " + virtualViewId); return null; @@ -203,31 +230,10 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider return info; } - /** - * Simulates a key press by injecting touch events into the keyboard view. - * This avoids the complexity of trackers and listeners within the keyboard. - * - * @param key The key to press. - */ - void simulateKeyPress(final Key key) { - final int x = key.getHitBox().centerX(); - final int y = key.getHitBox().centerY(); - final long downTime = SystemClock.uptimeMillis(); - final MotionEvent downEvent = MotionEvent.obtain( - downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0); - final MotionEvent upEvent = MotionEvent.obtain( - downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0); - - mKeyboardView.onTouchEvent(downEvent); - mKeyboardView.onTouchEvent(upEvent); - downEvent.recycle(); - upEvent.recycle(); - } - @Override public boolean performAction(final int virtualViewId, final int action, final Bundle arguments) { - final Key key = mVirtualViewIdToKey.get(virtualViewId); + final Key key = getKeyOf(virtualViewId); if (key == null) { return false; } @@ -243,7 +249,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @return The result of performing the action, or false if the action is not supported. */ boolean performActionForKey(final Key key, final int action, final Bundle arguments) { - final int virtualViewId = generateVirtualViewIdForKey(key); + final int virtualViewId = getVirtualViewIdOf(key); switch (action) { case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS: @@ -285,11 +291,11 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider * @return The context-specific description of the key. */ private String getKeyDescription(final Key key) { - final EditorInfo editorInfo = mInputMethodService.getCurrentInputEditorInfo(); + final EditorInfo editorInfo = mKeyboard.mId.mEditorInfo; final boolean shouldObscure = mAccessibilityUtils.shouldObscureInput(editorInfo); final SettingsValues currentSettings = Settings.getInstance().getCurrent(); final String keyCodeDescription = mKeyCodeDescriptionMapper.getDescriptionForKey( - mKeyboardView.getContext(), mKeyboardView.getKeyboard(), key, shouldObscure); + mKeyboardView.getContext(), mKeyboard, key, shouldObscure); if (currentSettings.isWordSeparator(key.getCode())) { return mAccessibilityUtils.getAutoCorrectionDescription( keyCodeDescription, shouldObscure); @@ -299,40 +305,9 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider } /** - * Assigns virtual view IDs to keyboard keys and populates the related maps. - */ - private void assignVirtualViewIds() { - final Keyboard keyboard = mKeyboardView.getKeyboard(); - if (keyboard == null) { - return; - } - mVirtualViewIdToKey.clear(); - - final Key[] keys = keyboard.getKeys(); - for (Key key : keys) { - final int virtualViewId = generateVirtualViewIdForKey(key); - mVirtualViewIdToKey.put(virtualViewId, key); - } - } - - /** * Updates the parent's on-screen location. */ private void updateParentLocation() { mKeyboardView.getLocationOnScreen(mParentLocation); } - - /** - * Generates a virtual view identifier for the given key. Returned - * identifiers are valid until the next global layout state change. - * - * @param key The key to identify. - * @return A virtual view identifier. - */ - private static int generateVirtualViewIdForKey(final Key key) { - // The key x- and y-coordinates are stable between layout changes. - // Generate an identifier by bit-shifting the x-coordinate to the - // left-half of the integer and OR'ing with the y-coordinate. - return ((0xFFFF & key.getX()) << (Integer.SIZE / 2)) | (0xFFFF & key.getY()); - } } diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java index 10fb9fef4..bc094b117 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.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.Build; import android.os.SystemClock; @@ -63,13 +62,13 @@ public final class AccessibilityUtils { */ private static final boolean ENABLE_ACCESSIBILITY = true; - public static void init(final InputMethodService inputMethod) { + public static void init(final Context context) { if (!ENABLE_ACCESSIBILITY) return; // These only need to be initialized if the kill switch is off. - sInstance.initInternal(inputMethod); + sInstance.initInternal(context); KeyCodeDescriptionMapper.init(); - AccessibleKeyboardViewProxy.init(inputMethod); + AccessibleKeyboardViewProxy.init(context); } public static AccessibilityUtils getInstance() { @@ -158,7 +157,7 @@ public final class AccessibilityUtils { * @param typedWord the currently typed word */ public void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) { - if (suggestedWords != null && suggestedWords.mWillAutoCorrect) { + if (suggestedWords.mWillAutoCorrect) { mAutoCorrectionWord = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); mTypedWord = typedWord; } else { diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index 73896dfd3..15f79f3de 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -17,7 +17,7 @@ package com.android.inputmethod.accessibility; import android.content.Context; -import android.inputmethodservice.InputMethodService; +import android.os.SystemClock; import android.support.v4.view.AccessibilityDelegateCompat; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityEventCompat; @@ -29,11 +29,12 @@ import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; 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.MainKeyboardView; -import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat { private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy(); @@ -53,8 +54,8 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp KEYBOARD_MODE_RES_IDS.put(KeyboardId.MODE_URL, R.string.keyboard_mode_url); } - private InputMethodService mInputMethod; private MainKeyboardView mView; + private Keyboard mKeyboard; private AccessibilityEntityProvider mAccessibilityNodeProvider; private Key mLastHoverKey = null; @@ -65,10 +66,11 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp private int mEdgeSlop; /** The most recently set keyboard mode. */ - private int mLastKeyboardMode; + private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN; + private static final int KEYBOARD_IS_HIDDEN = -1; - public static void init(final InputMethodService inputMethod) { - sInstance.initInternal(inputMethod); + public static void init(final Context context) { + sInstance.initInternal(context); } public static AccessibleKeyboardViewProxy getInstance() { @@ -79,10 +81,9 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp // Not publicly instantiable. } - private void initInternal(final InputMethodService inputMethod) { - mInputMethod = inputMethod; - mEdgeSlop = inputMethod.getResources().getDimensionPixelSize( - R.dimen.accessibility_edge_slop); + private void initInternal(final Context context) { + mEdgeSlop = context.getResources().getDimensionPixelSize( + R.dimen.config_accessibility_edge_slop); } /** @@ -104,6 +105,10 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp return; } mAccessibilityNodeProvider.setView(view); + + // Since this class is constructed lazily, we might not get a subsequent + // call to setKeyboard() and therefore need to call it now. + setKeyboard(view.getKeyboard()); } /** @@ -111,24 +116,40 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp * <p> * <b>Note:</b> This method will be called even if accessibility is not * enabled. + * @param keyboard The keyboard that is being set to the wrapping view. */ - public void setKeyboard() { - if (mView == null) { + public void setKeyboard(final Keyboard keyboard) { + if (keyboard == null) { return; } if (mAccessibilityNodeProvider != null) { - mAccessibilityNodeProvider.setKeyboard(); + mAccessibilityNodeProvider.setKeyboard(keyboard); } - final int keyboardMode = mView.getKeyboard().mId.mMode; + final Keyboard lastKeyboard = mKeyboard; + final int lastKeyboardMode = mLastKeyboardMode; + mKeyboard = keyboard; + mLastKeyboardMode = keyboard.mId.mMode; // Since this method is called even when accessibility is off, make sure - // to check the state before announcing anything. Also, don't announce - // changes within the same mode. - if (AccessibilityUtils.getInstance().isAccessibilityEnabled() - && (mLastKeyboardMode != keyboardMode)) { - announceKeyboardMode(keyboardMode); + // to check the state before announcing anything. + if (!AccessibilityUtils.getInstance().isAccessibilityEnabled()) { + return; + } + // Announce the language name only when the language is changed. + if (lastKeyboard == null || !keyboard.mId.mSubtype.equals(lastKeyboard.mId.mSubtype)) { + announceKeyboardLanguage(keyboard); + return; + } + // Announce the mode only when the mode is changed. + if (keyboard.mId.mMode != lastKeyboardMode) { + announceKeyboardMode(keyboard); + return; + } + // Announce the keyboard type only when the type is changed. + if (keyboard.mId.mElementId != lastKeyboard.mId.mElementId) { + announceKeyboardType(keyboard, lastKeyboard); + return; } - mLastKeyboardMode = keyboardMode; } /** @@ -139,23 +160,78 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp return; } announceKeyboardHidden(); - mLastKeyboardMode = -1; + mLastKeyboardMode = KEYBOARD_IS_HIDDEN; } /** - * Announces which type of keyboard is being displayed. If the keyboard type - * is unknown, no announcement is made. + * Announces which language of keyboard is being displayed. * - * @param mode The new keyboard mode. + * @param keyboard The new keyboard. */ - private void announceKeyboardMode(int mode) { - final int resId = KEYBOARD_MODE_RES_IDS.get(mode); - if (resId == 0) { + private void announceKeyboardLanguage(final Keyboard keyboard) { + final String languageText = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale( + keyboard.mId.mSubtype); + sendWindowStateChanged(languageText); + } + + /** + * Announces which type of keyboard is being displayed. + * If the keyboard type is unknown, no announcement is made. + * + * @param keyboard The new keyboard. + */ + private void announceKeyboardMode(final Keyboard keyboard) { + final Context context = mView.getContext(); + final int modeTextResId = KEYBOARD_MODE_RES_IDS.get(keyboard.mId.mMode); + if (modeTextResId == 0) { return; } - final Context context = mView.getContext(); - final String keyboardMode = context.getString(resId); - final String text = context.getString(R.string.announce_keyboard_mode, keyboardMode); + final String modeText = context.getString(modeTextResId); + final String text = context.getString(R.string.announce_keyboard_mode, modeText); + sendWindowStateChanged(text); + } + + /** + * Announces which type of keyboard is being displayed. + * + * @param keyboard The new keyboard. + * @param lastKeyboard The last keyboard. + */ + private void announceKeyboardType(final Keyboard keyboard, final Keyboard lastKeyboard) { + final int lastElementId = lastKeyboard.mId.mElementId; + final int resId; + switch (keyboard.mId.mElementId) { + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET: + if (lastElementId == KeyboardId.ELEMENT_ALPHABET + || lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return; + } + resId = R.string.spoken_description_mode_alpha; + break; + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + resId = R.string.spoken_description_shiftmode_on; + break; + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + resId = R.string.spoken_description_shiftmode_locked; + break; + case KeyboardId.ELEMENT_SYMBOLS: + resId = R.string.spoken_description_mode_symbol; + break; + case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: + resId = R.string.spoken_description_mode_symbol_shift; + 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: + return; + } + final String text = mView.getContext().getString(resId); sendWindowStateChanged(text); } @@ -204,25 +280,14 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } /** - * Intercepts touch events before dispatch when touch exploration is turned on in ICS and - * higher. - * - * @param event The motion event being dispatched. - * @return {@code true} if the event is handled - */ - public boolean dispatchTouchEvent(final MotionEvent event) { - // To avoid accidental key presses during touch exploration, always drop - // touch events generated by the user. - return false; - } - - /** * Receives hover events when touch exploration is turned on in SDK versions ICS and higher. * * @param event The hover event. + * @param keyDetector The {@link KeyDetector} to determine on which key the <code>event</code> + * is hovering. * @return {@code true} if the event is handled */ - public boolean dispatchHoverEvent(final MotionEvent event, final PointerTracker tracker) { + public boolean dispatchHoverEvent(final MotionEvent event, final KeyDetector keyDetector) { if (mView == null) { return false; } @@ -233,7 +298,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp final Key key; if (pointInView(x, y)) { - key = tracker.getKeyOn(x, y); + key = keyDetector.detectHitKey(x, y); } else { key = null; } @@ -244,7 +309,8 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp // Make sure we're not getting an EXIT event because the user slid // off the keyboard area, then force a key press. if (key != null) { - getAccessibilityNodeProvider().simulateKeyPress(key); + final long downTime = simulateKeyPress(key); + simulateKeyRelease(key, downTime); } //$FALL-THROUGH$ case MotionEvent.ACTION_HOVER_ENTER: @@ -266,7 +332,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp // will call this method multiple times it is a good practice to // cache the provider instance. if (mAccessibilityNodeProvider == null) { - mAccessibilityNodeProvider = new AccessibilityEntityProvider(mView, mInputMethod); + mAccessibilityNodeProvider = new AccessibilityEntityProvider(mView); } return mAccessibilityNodeProvider; } @@ -285,6 +351,38 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } /** + * Simulates a key press by injecting touch an event into the keyboard view. + * This avoids the complexity of trackers and listeners within the keyboard. + * + * @param key The key to press. + */ + private long simulateKeyPress(final Key key) { + final int x = key.getHitBox().centerX(); + final int y = key.getHitBox().centerY(); + final long downTime = SystemClock.uptimeMillis(); + final MotionEvent downEvent = MotionEvent.obtain( + downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0); + mView.onTouchEvent(downEvent); + downEvent.recycle(); + return downTime; + } + + /** + * Simulates a key release by injecting touch an event into the keyboard view. + * This avoids the complexity of trackers and listeners within the keyboard. + * + * @param key The key to release. + */ + private void simulateKeyRelease(final Key key, final long downTime) { + final int x = key.getHitBox().centerX(); + final int y = key.getHitBox().centerY(); + final MotionEvent upEvent = MotionEvent.obtain( + downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0); + mView.onTouchEvent(upEvent); + upEvent.recycle(); + } + + /** * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT on the previous key, * a HOVER_ENTER on the current key, and a HOVER_MOVE on the current key. * @@ -335,77 +433,4 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp } return true; } - - /** - * Notifies the user of changes in the keyboard shift state. - */ - public void notifyShiftState() { - if (mView == null) { - return; - } - - 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().announceForAccessibility(mView, text); - } - - /** - * Notifies the user of changes in the keyboard symbols state. - */ - public void notifySymbolsState() { - if (mView == null) { - return; - } - - 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().announceForAccessibility(mView, text); - } } diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 58624a2e6..2e6649bf2 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -58,9 +58,6 @@ public final class KeyCodeDescriptionMapper { } private void initInternal() { - // Manual label substitutions for key labels with no string resource - mKeyLabelMap.put(":-)", R.string.spoken_description_smiley); - // Special non-character codes defined in Keyboard mKeyCodeMap.put(Constants.CODE_SPACE, R.string.spoken_description_space); mKeyCodeMap.put(Constants.CODE_DELETE, R.string.spoken_description_delete); @@ -75,6 +72,7 @@ public final class KeyCodeDescriptionMapper { mKeyCodeMap.put(Constants.CODE_ACTION_NEXT, R.string.spoken_description_action_next); mKeyCodeMap.put(Constants.CODE_ACTION_PREVIOUS, R.string.spoken_description_action_previous); + mKeyCodeMap.put(Constants.CODE_EMOJI, R.string.spoken_description_emoji); } /** diff --git a/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java b/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java index 7e9e2e37b..6e43cc9a7 100644 --- a/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java +++ b/java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java @@ -23,10 +23,10 @@ import android.os.Build.VERSION_CODES; * A class to encapsulate work-arounds specific to particular apps. */ public class AppWorkaroundsUtils { - private PackageInfo mPackageInfo; // May be null - private boolean mIsBrokenByRecorrection = false; + private final PackageInfo mPackageInfo; // May be null + private final boolean mIsBrokenByRecorrection; - public void setPackageInfo(final PackageInfo packageInfo) { + public AppWorkaroundsUtils(final PackageInfo packageInfo) { mPackageInfo = packageInfo; mIsBrokenByRecorrection = AppWorkaroundsHelper.evaluateIsBrokenByRecorrection( packageInfo); diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index a80c3fefe..18b3a6060 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -28,6 +28,12 @@ public final class InputMethodManagerCompatWrapper { private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod( InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE); + // Note that InputMethodManager.shouldOfferSwitchingToNextInputMethod() has been introduced + // in API level 19 (Build.VERSION_CODES.KITKAT). + private static final Method METHOD_shouldOfferSwitchingToNextInputMethod = + CompatUtils.getMethod(InputMethodManager.class, + "shouldOfferSwitchingToNextInputMethod", IBinder.class); + public final InputMethodManager mImm; public InputMethodManagerCompatWrapper(final Context context) { @@ -38,4 +44,9 @@ public final class InputMethodManagerCompatWrapper { return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */, METHOD_switchToNextInputMethod, token, onlyCurrentIme); } + + public boolean shouldOfferSwitchingToNextInputMethod(final IBinder token) { + return (Boolean)CompatUtils.invoke(mImm, false /* defaultValue */, + METHOD_shouldOfferSwitchingToNextInputMethod, token); + } } diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java index 14ee654f3..81df17127 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatUtils.java @@ -17,11 +17,12 @@ package com.android.inputmethod.compat; import android.inputmethodservice.InputMethodService; +import com.android.inputmethod.latin.define.ProductionFlag; import java.lang.reflect.Method; public final class InputMethodServiceCompatUtils { - // Note that InputMethodService.enableHardwareAcceleration() has been introduced + // Note that {@link InputMethodService#enableHardwareAcceleration} has been introduced // in API level 17 (Build.VERSION_CODES.JELLY_BEAN_MR1). private static final Method METHOD_enableHardwareAcceleration = CompatUtils.getMethod(InputMethodService.class, "enableHardwareAcceleration"); @@ -34,4 +35,30 @@ public final class InputMethodServiceCompatUtils { return (Boolean)CompatUtils.invoke(ims, false /* defaultValue */, METHOD_enableHardwareAcceleration); } + + public static void setCursorAnchorMonitorMode(final InputMethodService ims, final int mode) { + if (ProductionFlag.USES_CURSOR_ANCHOR_MONITOR) { + ExperimentalAPIUtils.setCursorAnchorMonitorMode(ims, mode); + } + } + + /* + * For unreleased APIs. ProGuard will strip this class entirely, unless used explicitly. + */ + private static final class ExperimentalAPIUtils { + // Note that {@link InputMethodManager#setCursorAnchorMonitorMode} is not yet available as + // an official API as of API level 19 (Build.VERSION_CODES.KITKAT). + private static final Method METHOD_setCursorAnchorMonitorMode = CompatUtils.getMethod( + InputMethodService.class, "setCursorAnchorMonitorMode", int.class); + + private ExperimentalAPIUtils() { + // This utility class is not publicly instantiable. + } + + public static void setCursorAnchorMonitorMode(final InputMethodService ims, + final int mode) { + CompatUtils.invoke(ims, null /* defaultValue */, + METHOD_setCursorAnchorMonitorMode, mode); + } + } } diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java index b119d6c82..4ea7fb888 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java @@ -19,7 +19,10 @@ package com.android.inputmethod.compat; import android.os.Build; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.Constants; + import java.lang.reflect.Constructor; +import java.lang.reflect.Method; public final class InputMethodSubtypeCompatUtils { private static final String TAG = InputMethodSubtypeCompatUtils.class.getSimpleName(); @@ -37,6 +40,12 @@ public final class InputMethodSubtypeCompatUtils { } } } + + // Note that {@link InputMethodSubtype#isAsciiCapable()} has been introduced in API level 19 + // (Build.VERSION_CODE.KITKAT). + private static final Method METHOD_isAsciiCapable = CompatUtils.getMethod( + InputMethodSubtype.class, "isAsciiCapable"); + private InputMethodSubtypeCompatUtils() { // This utility class is not publicly instantiable. } @@ -53,4 +62,9 @@ public final class InputMethodSubtypeCompatUtils { nameId, iconId, locale, mode, extraValue, isAuxiliary, overridesImplicitlyEnabledSubtype, id); } + + public static boolean isAsciiCapable(final InputMethodSubtype subtype) { + return (Boolean)CompatUtils.invoke(subtype, false, METHOD_isAsciiCapable) + || subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE); + } } diff --git a/java/src/com/android/inputmethod/compat/LooperCompatUtils.java b/java/src/com/android/inputmethod/compat/LooperCompatUtils.java new file mode 100644 index 000000000..d647dbbd3 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/LooperCompatUtils.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 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.os.Looper; + +import java.lang.reflect.Method; + +/** + * Helper to call Looper#quitSafely, which was introduced in API + * level 18 (Build.VERSION_CODES.JELLY_BEAN_MR2). + * + * In unit tests, we create lots of instances of LatinIME, which means we need to clean up + * some Loopers lest we leak file descriptors. In normal use on a device though, this is never + * necessary (although it does not hurt). + */ +public final class LooperCompatUtils { + private static final Method METHOD_quitSafely = CompatUtils.getMethod( + Looper.class, "quitSafely"); + + public static void quitSafely(final Looper looper) { + if (null != METHOD_quitSafely) { + CompatUtils.invoke(looper, null /* default return value */, METHOD_quitSafely); + } else { + looper.quit(); + } + } +} diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index 55282c583..60f7e2def 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -25,6 +25,7 @@ import android.text.style.SuggestionSpan; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestionSpanPickedNotificationReceiver; import com.android.inputmethod.latin.utils.CollectionUtils; @@ -66,30 +67,30 @@ public final class SuggestionSpanUtils { } public static CharSequence getTextWithSuggestionSpan(final Context context, - final String pickedWord, final SuggestedWords suggestedWords, - final boolean dictionaryAvailable) { - if (!dictionaryAvailable || TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty() - || suggestedWords.mIsPrediction || suggestedWords.mIsPunctuationSuggestions) { + final String pickedWord, final SuggestedWords suggestedWords) { + if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty() + || suggestedWords.mIsPrediction || suggestedWords.isPunctuationSuggestions()) { return pickedWord; } - final Spannable spannable = new SpannableString(pickedWord); final ArrayList<String> suggestionsList = CollectionUtils.newArrayList(); for (int i = 0; i < suggestedWords.size(); ++i) { if (suggestionsList.size() >= SuggestionSpan.SUGGESTIONS_MAX_SIZE) { break; } + final SuggestedWordInfo info = suggestedWords.getInfo(i); + if (info.mKind == SuggestedWordInfo.KIND_PREDICTION) { + continue; + } final String word = suggestedWords.getWord(i); if (!TextUtils.equals(pickedWord, word)) { suggestionsList.add(word.toString()); } } - - // TODO: We should avoid adding suggestion span candidates that came from the bigram - // prediction. final SuggestionSpan suggestionSpan = new SuggestionSpan(context, null /* locale */, suggestionsList.toArray(new String[suggestionsList.size()]), 0 /* flags */, SuggestionSpanPickedNotificationReceiver.class); + final Spannable spannable = new SpannableString(pickedWord); spannable.setSpan(suggestionSpan, 0, pickedWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannable; } diff --git a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java index a0d76415c..6e32e74ab 100644 --- a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java @@ -29,8 +29,8 @@ public final class UserDictionaryCompatUtils { Context.class, String.class, Integer.TYPE, String.class, Locale.class); @SuppressWarnings("deprecation") - public static void addWord(final Context context, final String word, final int freq, - final String shortcut, final Locale locale) { + public static void addWord(final Context context, final String word, + final int freq, final String shortcut, final Locale locale) { if (hasNewerAddWord()) { CompatUtils.invoke(Words.class, null, METHOD_addWord, context, word, freq, shortcut, locale); diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java index a8fab8855..dec739d39 100644 --- a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java @@ -20,6 +20,9 @@ import android.view.View; import java.lang.reflect.Method; +// TODO: Use {@link android.support.v4.view.ViewCompat} instead of this utility class. +// Currently {@link #getPaddingEnd(View)} and {@link #setPaddingRelative(View,int,int,int,int)} +// are missing from android-support-v4 static library in KitKat SDK. public final class ViewCompatUtils { // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1). diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java index d5e638e7e..706bdea8e 100644 --- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java +++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java @@ -117,16 +117,11 @@ public final class ActionBatch { final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db, mWordList.mId, mWordList.mVersion); final int status = values.getAsInteger(MetadataDbHelper.STATUS_COLUMN); - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); if (MetadataDbHelper.STATUS_DOWNLOADING == status) { // The word list is still downloading. Cancel the download and revert the // word list status to "available". - if (null != manager) { - // DownloadManager is disabled (or not installed?). We can't cancel - there - // is nothing we can do. We still need to mark the entry as available. - manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); - } + manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion); } else if (MetadataDbHelper.STATUS_AVAILABLE != status) { // Should never happen @@ -136,9 +131,6 @@ public final class ActionBatch { // Download it. DebugLogUtils.l("Upgrade word list, downloading", mWordList.mRemoteFilename); - // TODO: if DownloadManager is disabled or not installed, download by ourselves - if (null == manager) return; - // This is an upgraded word list: we should download it. // Adding a disambiguator to circumvent a bug in older versions of DownloadManager. // DownloadManager also stupidly cuts the extension to replace with its own that it @@ -293,13 +285,8 @@ public final class ActionBatch { } // The word list is still downloading. Cancel the download and revert the // word list status to "available". - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - if (null != manager) { - // If we can't cancel the download because DownloadManager is not available, - // we still need to mark the entry as available. - manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); - } + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); + manager.remove(values.getAsLong(MetadataDbHelper.PENDINGID_COLUMN)); MetadataDbHelper.markEntryAsAvailable(db, mWordList.mId, mWordList.mVersion); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java index 7c27e6d51..3d0e29ed0 100644 --- a/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java +++ b/java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java @@ -23,7 +23,7 @@ public final class CommonPreferences { private static final String COMMON_PREFERENCES_NAME = "LatinImeDictPrefs"; public static SharedPreferences getCommonPreferences(final Context context) { - return context.getSharedPreferences(COMMON_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); + return context.getSharedPreferences(COMMON_PREFERENCES_NAME, 0); } public static void enable(final SharedPreferences pref, final String id) { diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java index 88b5032e3..2623eff56 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java @@ -100,32 +100,29 @@ public class DictionaryDownloadProgressBar extends ProgressBar { @Override protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); mIsCurrentlyAttachedToWindow = false; updateReporterThreadRunningStatusAccordingToVisibility(); } private class UpdaterThread extends Thread { private final static int REPORT_PERIOD = 150; // how often to report progress, in ms - final DownloadManager mDownloadManager; + final DownloadManagerWrapper mDownloadManagerWrapper; final int mId; public UpdaterThread(final Context context, final int id) { super(); - mDownloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + mDownloadManagerWrapper = new DownloadManagerWrapper(context); mId = id; } @Override public void run() { try { - // It's almost impossible that mDownloadManager is null (it would mean it has been - // disabled between pressing the 'install' button and displaying the progress - // bar), but just in case. - if (null == mDownloadManager) return; final UpdateHelper updateHelper = new UpdateHelper(); final Query query = new Query().setFilterById(mId); int lastProgress = 0; setIndeterminate(true); while (!isInterrupted()) { - final Cursor cursor = mDownloadManager.query(query); + final Cursor cursor = mDownloadManagerWrapper.query(query); if (null == cursor) { // Can't contact DownloadManager: this should never happen. return; diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java index 1d9b9991e..80def701d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java @@ -350,7 +350,8 @@ public final class DictionaryProvider extends ContentProvider { clientId); if (null == results) { return Collections.<WordListInfo>emptyList(); - } else { + } + try { final HashMap<String, WordListInfo> dicts = new HashMap<String, WordListInfo>(); final int idIndex = results.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); final int localeIndex = results.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); @@ -416,8 +417,9 @@ public final class DictionaryProvider extends ContentProvider { } } while (results.moveToNext()); } - results.close(); return Collections.unmodifiableCollection(dicts.values()); + } finally { + results.close(); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java index 7bbd041e7..dae2f22a4 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java @@ -283,59 +283,70 @@ public final class DictionarySettingsFragment extends PreferenceFragment final ArrayList<Preference> result = new ArrayList<Preference>(); result.add(createErrorMessage(activity, R.string.cannot_connect_to_dict_service)); return result; - } else if (!cursor.moveToFirst()) { - final ArrayList<Preference> result = new ArrayList<Preference>(); - result.add(createErrorMessage(activity, R.string.no_dictionaries_available)); - cursor.close(); - return result; - } else { - final String systemLocaleString = Locale.getDefault().toString(); - final TreeMap<String, WordListPreference> prefMap = - new TreeMap<String, WordListPreference>(); - final int idIndex = cursor.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); - final int versionIndex = cursor.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); - final int localeIndex = cursor.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); - final int descriptionIndex = cursor.getColumnIndex(MetadataDbHelper.DESCRIPTION_COLUMN); - final int statusIndex = cursor.getColumnIndex(MetadataDbHelper.STATUS_COLUMN); - final int filesizeIndex = cursor.getColumnIndex(MetadataDbHelper.FILESIZE_COLUMN); - do { - final String wordlistId = cursor.getString(idIndex); - final int version = cursor.getInt(versionIndex); - final String localeString = cursor.getString(localeIndex); - final Locale locale = new Locale(localeString); - final String description = cursor.getString(descriptionIndex); - final int status = cursor.getInt(statusIndex); - final int matchLevel = LocaleUtils.getMatchLevel(systemLocaleString, localeString); - final String matchLevelString = LocaleUtils.getMatchLevelSortedString(matchLevel); - final int filesize = cursor.getInt(filesizeIndex); - // The key is sorted in lexicographic order, according to the match level, then - // the description. - final String key = matchLevelString + "." + description + "." + wordlistId; - final WordListPreference existingPref = prefMap.get(key); - if (null == existingPref || existingPref.hasPriorityOver(status)) { - final WordListPreference oldPreference = mCurrentPreferenceMap.get(key); - final WordListPreference pref; - if (null != oldPreference - && oldPreference.mVersion == version - && oldPreference.mLocale.equals(locale)) { - // If the old preference has all the new attributes, reuse it. We test - // for version and locale because although attributes other than status - // need to be the same, others have been tested through the key of the - // map. Also, status may differ so we don't want to use #equals() here. - pref = oldPreference; - pref.setStatus(status); - } else { - // Otherwise, discard it and create a new one instead. - pref = new WordListPreference(activity, mDictionaryListInterfaceState, - mClientId, wordlistId, version, locale, description, status, - filesize); + } + try { + if (!cursor.moveToFirst()) { + final ArrayList<Preference> result = new ArrayList<Preference>(); + result.add(createErrorMessage(activity, R.string.no_dictionaries_available)); + return result; + } else { + final String systemLocaleString = Locale.getDefault().toString(); + final TreeMap<String, WordListPreference> prefMap = + new TreeMap<String, WordListPreference>(); + final int idIndex = cursor.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN); + final int versionIndex = cursor.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); + final int localeIndex = cursor.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); + final int descriptionIndex = + cursor.getColumnIndex(MetadataDbHelper.DESCRIPTION_COLUMN); + final int statusIndex = cursor.getColumnIndex(MetadataDbHelper.STATUS_COLUMN); + final int filesizeIndex = cursor.getColumnIndex(MetadataDbHelper.FILESIZE_COLUMN); + do { + final String wordlistId = cursor.getString(idIndex); + final int version = cursor.getInt(versionIndex); + final String localeString = cursor.getString(localeIndex); + final Locale locale = new Locale(localeString); + final String description = cursor.getString(descriptionIndex); + final int status = cursor.getInt(statusIndex); + final int matchLevel = + LocaleUtils.getMatchLevel(systemLocaleString, localeString); + final String matchLevelString = + LocaleUtils.getMatchLevelSortedString(matchLevel); + final int filesize = cursor.getInt(filesizeIndex); + // The key is sorted in lexicographic order, according to the match level, then + // the description. + final String key = matchLevelString + "." + description + "." + wordlistId; + final WordListPreference existingPref = prefMap.get(key); + if (null == existingPref || existingPref.hasPriorityOver(status)) { + final WordListPreference oldPreference = mCurrentPreferenceMap.get(key); + final WordListPreference pref; + if (null != oldPreference + && oldPreference.mVersion == version + && oldPreference.hasStatus(status) + && oldPreference.mLocale.equals(locale)) { + // If the old preference has all the new attributes, reuse it. Ideally, + // we should reuse the old pref even if its status is different and call + // setStatus here, but setStatus calls Preference#setSummary() which + // needs to be done on the UI thread and we're not on the UI thread + // here. We could do all this work on the UI thread, but in this case + // it's probably lighter to stay on a background thread and throw this + // old preference out. + pref = oldPreference; + } else { + // Otherwise, discard it and create a new one instead. + // TODO: when the status is different from the old one, we need to + // animate the old one out before animating the new one in. + pref = new WordListPreference(activity, mDictionaryListInterfaceState, + mClientId, wordlistId, version, locale, description, status, + filesize); + } + prefMap.put(key, pref); } - prefMap.put(key, pref); - } - } while (cursor.moveToNext()); + } while (cursor.moveToNext()); + mCurrentPreferenceMap = prefMap; + return prefMap.values(); + } + } finally { cursor.close(); - mCurrentPreferenceMap = prefMap; - return prefMap.values(); } } diff --git a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java new file mode 100644 index 000000000..75cc7d4cb --- /dev/null +++ b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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.dictionarypack; + +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileNotFoundException; + +/** + * A class to help with calling DownloadManager methods. + * + * Mostly, the problem here is that most methods from DownloadManager may throw SQL exceptions if + * they can't open the database on disk. We want to avoid crashing in these cases but can't do + * much more, so this class insulates the callers from these. SQLiteException also inherit from + * RuntimeException so they are unchecked :( + * While we're at it, we also insulate callers from the cases where DownloadManager is disabled, + * and getSystemService returns null. + */ +public class DownloadManagerWrapper { + private final static String TAG = DownloadManagerWrapper.class.getSimpleName(); + private final DownloadManager mDownloadManager; + + public DownloadManagerWrapper(final Context context) { + this((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)); + } + + private DownloadManagerWrapper(final DownloadManager downloadManager) { + mDownloadManager = downloadManager; + } + + public void remove(final long... ids) { + try { + if (null != mDownloadManager) { + mDownloadManager.remove(ids); + } + } catch (SQLiteException e) { + // We couldn't remove the file from DownloadManager. Apparently, the database can't + // be opened. It may be a problem with file system corruption. In any case, there is + // not much we can do apart from avoiding crashing. + Log.e(TAG, "Can't remove files with ID " + ids + " from download manager", e); + } catch (IllegalArgumentException e) { + // Not sure how this can happen, but it could be another case where the provider + // is disabled. Or it could be a bug in older versions of the framework. + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + } + + public ParcelFileDescriptor openDownloadedFile(final long fileId) throws FileNotFoundException { + try { + if (null != mDownloadManager) { + return mDownloadManager.openDownloadedFile(fileId); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't open downloaded file with ID " + fileId, e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + // We come here if mDownloadManager is null or if an exception was thrown. + throw new FileNotFoundException(); + } + + public Cursor query(final Query query) { + try { + if (null != mDownloadManager) { + return mDownloadManager.query(query); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't query the download manager", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + // We come here if mDownloadManager is null or if an exception was thrown. + return null; + } + + public long enqueue(final Request request) { + try { + if (null != mDownloadManager) { + return mDownloadManager.enqueue(request); + } + } catch (SQLiteException e) { + Log.e(TAG, "Can't enqueue a request with the download manager", e); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Can't find the content URL for DownloadManager?", e); + } + return 0; + } +} diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java index ff5aba6d8..4a8fa51ee 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java @@ -45,10 +45,8 @@ public class MetadataDbHelper extends SQLiteOpenHelper { // This is the first released version of the database that implements CLIENTID. It is // used to identify the versions for upgrades. This should never change going forward. private static final int METADATA_DATABASE_VERSION_WITH_CLIENTID = 6; - // This is the current database version. It should be updated when the database schema - // gets updated. It is passed to the framework constructor of SQLiteOpenHelper, so - // that's what the framework uses to track our database version. - private static final int METADATA_DATABASE_VERSION = 6; + // The current database version. + private static final int CURRENT_METADATA_DATABASE_VERSION = 7; private final static long NOT_A_DOWNLOAD_ID = -1; @@ -169,7 +167,7 @@ public class MetadataDbHelper extends SQLiteOpenHelper { private MetadataDbHelper(final Context context, final String clientId) { super(context, METADATA_DATABASE_NAME_STEM + (TextUtils.isEmpty(clientId) ? "" : "." + clientId), - null, METADATA_DATABASE_VERSION); + null, CURRENT_METADATA_DATABASE_VERSION); mContext = context; mClientId = clientId; } @@ -219,22 +217,45 @@ public class MetadataDbHelper extends SQLiteOpenHelper { /** * Upgrade the database. Upgrade from version 3 is supported. + * Version 3 has a DB named METADATA_DATABASE_NAME_STEM containing a table METADATA_TABLE_NAME. + * Version 6 and above has a DB named METADATA_DATABASE_NAME_STEM containing a + * table CLIENT_TABLE_NAME, and for each client a table called METADATA_TABLE_STEM + "." + the + * name of the client and contains a table METADATA_TABLE_NAME. + * For schemas, see the above create statements. The schemas have never changed so far. + * + * This method is called by the framework. See {@link SQLiteOpenHelper#onUpgrade} + * @param db The database we are upgrading + * @param oldVersion The old database version (the one on the disk) + * @param newVersion The new database version as supplied to the constructor of SQLiteOpenHelper */ @Override public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { if (METADATA_DATABASE_INITIAL_VERSION == oldVersion - && METADATA_DATABASE_VERSION_WITH_CLIENTID == newVersion) { + && METADATA_DATABASE_VERSION_WITH_CLIENTID <= newVersion + && CURRENT_METADATA_DATABASE_VERSION >= newVersion) { // Upgrade from version METADATA_DATABASE_INITIAL_VERSION to version // METADATA_DATABASE_VERSION_WITH_CLIENT_ID + // Only the default database should contain the client table, so we test for mClientId. if (TextUtils.isEmpty(mClientId)) { - // Only the default database should contain the client table. - // Anyway in version 3 only the default table existed so the emptyness + // Anyway in version 3 only the default table existed so the emptiness // test should always be true, but better check to be sure. createClientTable(db); } + } else if (METADATA_DATABASE_VERSION_WITH_CLIENTID < newVersion + && CURRENT_METADATA_DATABASE_VERSION >= newVersion) { + // Here we drop the client table, so that all clients send us their information again. + // The client table contains the URL to hit to update the available dictionaries list, + // but the info about the dictionaries themselves is stored in the table called + // METADATA_TABLE_NAME and we want to keep it, so we only drop the client table. + db.execSQL("DROP TABLE IF EXISTS " + CLIENT_TABLE_NAME); + // Only the default database should contain the client table, so we test for mClientId. + if (TextUtils.isEmpty(mClientId)) { + createClientTable(db); + } } else { - // Version 3 was the earliest version, so we should never come here. If we do, we - // have no idea what this database is, so we'd better wipe it off. + // If we're not in the above case, either we are upgrading from an earlier versionCode + // and we should wipe the database, or we are handling a version we never heard about + // (can only be a bug) so it's safer to wipe the database. db.execSQL("DROP TABLE IF EXISTS " + METADATA_TABLE_NAME); db.execSQL("DROP TABLE IF EXISTS " + CLIENT_TABLE_NAME); onCreate(db); @@ -533,12 +554,17 @@ public class MetadataDbHelper extends SQLiteOpenHelper { PENDINGID_COLUMN + "= ?", new String[] { Long.toString(id) }, null, null, null); - // There should never be more than one result. If because of some bug there are, returning - // only one result is the right thing to do, because we couldn't handle several anyway - // and we should still handle one. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + if (null == cursor) { + return null; + } + try { + // There should never be more than one result. If because of some bug there are, + // returning only one result is the right thing to do, because we couldn't handle + // several anyway and we should still handle one. + return getFirstLineAsContentValues(cursor); + } finally { + cursor.close(); + } } /** @@ -559,11 +585,16 @@ public class MetadataDbHelper extends SQLiteOpenHelper { new String[] { id, Integer.toString(STATUS_INSTALLED), Integer.toString(STATUS_DELETING) }, null, null, null); - // There should only be one result, but if there are several, we can't tell which - // is the best, so we just return the first one. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + if (null == cursor) { + return null; + } + try { + // There should only be one result, but if there are several, we can't tell which + // is the best, so we just return the first one. + return getFirstLineAsContentValues(cursor); + } finally { + cursor.close(); + } } /** @@ -622,10 +653,15 @@ public class MetadataDbHelper extends SQLiteOpenHelper { METADATA_TABLE_COLUMNS, WORDLISTID_COLUMN + "= ? AND " + VERSION_COLUMN + "= ?", new String[] { id, Integer.toString(version) }, null, null, null); - // This is a lookup by primary key, so there can't be more than one result. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + if (null == cursor) { + return null; + } + try { + // This is a lookup by primary key, so there can't be more than one result. + return getFirstLineAsContentValues(cursor); + } finally { + cursor.close(); + } } /** @@ -641,10 +677,15 @@ public class MetadataDbHelper extends SQLiteOpenHelper { METADATA_TABLE_COLUMNS, WORDLISTID_COLUMN + "= ?", new String[] { id }, null, null, VERSION_COLUMN + " DESC", "1"); - // This is a lookup by primary key, so there can't be more than one result. - final ContentValues result = getFirstLineAsContentValues(cursor); - cursor.close(); - return result; + if (null == cursor) { + return null; + } + try { + // This is a lookup by primary key, so there can't be more than one result. + return getFirstLineAsContentValues(cursor); + } finally { + cursor.close(); + } } /** diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java index a0147b6d6..5c2289911 100644 --- a/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java @@ -44,8 +44,7 @@ public class MetadataHandler { */ private static List<WordListMetadata> makeMetadataObject(final Cursor results) { final ArrayList<WordListMetadata> buildingMetadata = new ArrayList<WordListMetadata>(); - - if (results.moveToFirst()) { + if (null != results && results.moveToFirst()) { final int localeColumn = results.getColumnIndex(MetadataDbHelper.LOCALE_COLUMN); final int typeColumn = results.getColumnIndex(MetadataDbHelper.TYPE_COLUMN); final int descriptionColumn = @@ -61,7 +60,6 @@ public class MetadataHandler { final int versionIndex = results.getColumnIndex(MetadataDbHelper.VERSION_COLUMN); final int formatVersionIndex = results.getColumnIndex(MetadataDbHelper.FORMATVERSION_COLUMN); - do { buildingMetadata.add(new WordListMetadata(results.getString(idIndex), results.getInt(typeColumn), @@ -75,8 +73,6 @@ public class MetadataHandler { results.getInt(formatVersionIndex), 0, results.getString(localeColumn))); } while (results.moveToNext()); - - results.close(); } return Collections.unmodifiableList(buildingMetadata); } @@ -92,9 +88,14 @@ public class MetadataHandler { // If clientId is null, we get a cursor on the default database (see // MetadataDbHelper#getInstance() for more on this) final Cursor results = MetadataDbHelper.queryCurrentMetadata(context, clientId); - final List<WordListMetadata> resultList = makeMetadataObject(results); - results.close(); - return resultList; + // If null, we should return makeMetadataObject(null), so we go through. + try { + return makeMetadataObject(results); + } finally { + if (null != results) { + results.close(); + } + } } /** diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java index 0e7c3bb7e..dcff490db 100644 --- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java @@ -249,13 +249,7 @@ public final class UpdateHandler { metadataRequest.setVisibleInDownloadsUi( res.getBoolean(R.bool.metadata_downloads_visible_in_download_UI)); - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - if (null == manager) { - // Download manager is not installed or disabled. - // TODO: fall back to self-managed download? - return; - } + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); cancelUpdateWithDownloadManager(context, metadataUri, manager); final long downloadId; synchronized (sSharedIdProtector) { @@ -278,10 +272,10 @@ public final class UpdateHandler { * * @param context the context to open the database on * @param metadataUri the URI to cancel - * @param manager an instance of DownloadManager + * @param manager an wrapped instance of DownloadManager */ private static void cancelUpdateWithDownloadManager(final Context context, - final String metadataUri, final DownloadManager manager) { + final String metadataUri, final DownloadManagerWrapper manager) { synchronized (sSharedIdProtector) { final long metadataDownloadId = MetadataDbHelper.getMetadataDownloadIdForURI(context, metadataUri); @@ -306,10 +300,9 @@ public final class UpdateHandler { * @param clientId the ID of the client we want to cancel the update of */ public static void cancelUpdate(final Context context, final String clientId) { - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); final String metadataUri = MetadataDbHelper.getMetadataUriAsString(context, clientId); - if (null != manager) cancelUpdateWithDownloadManager(context, metadataUri, manager); + cancelUpdateWithDownloadManager(context, metadataUri, manager); } /** @@ -323,15 +316,15 @@ public final class UpdateHandler { * download request id, which is not known before submitting the request to the download * manager. Hence, it only updates the relevant line. * - * @param manager the download manager service to register the request with. + * @param manager a wrapped download manager service to register the request with. * @param request the request to register. * @param db the metadata database. * @param id the id of the word list. * @param version the version of the word list. * @return the download id returned by the download manager. */ - public static long registerDownloadRequest(final DownloadManager manager, final Request request, - final SQLiteDatabase db, final String id, final int version) { + public static long registerDownloadRequest(final DownloadManagerWrapper manager, + final Request request, final SQLiteDatabase db, final String id, final int version) { DebugLogUtils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version); final long downloadId; synchronized (sSharedIdProtector) { @@ -345,8 +338,8 @@ public final class UpdateHandler { /** * Retrieve information about a specific download from DownloadManager. */ - private static CompletedDownloadInfo getCompletedDownloadInfo(final DownloadManager manager, - final long downloadId) { + private static CompletedDownloadInfo getCompletedDownloadInfo( + final DownloadManagerWrapper manager, final long downloadId) { final Query query = new Query().setFilterById(downloadId); final Cursor cursor = manager.query(query); @@ -425,8 +418,7 @@ public final class UpdateHandler { DebugLogUtils.l("DownloadFinished with id", fileId); if (NOT_AN_ID == fileId) return; // Spurious wake-up: ignore - final DownloadManager manager = - (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + final DownloadManagerWrapper manager = new DownloadManagerWrapper(context); final CompletedDownloadInfo downloadInfo = getCompletedDownloadInfo(manager, fileId); final ArrayList<DownloadRecord> recordList = @@ -517,7 +509,7 @@ public final class UpdateHandler { } private static boolean handleDownloadedFile(final Context context, - final DownloadRecord downloadRecord, final DownloadManager manager, + final DownloadRecord downloadRecord, final DownloadManagerWrapper manager, final long fileId) { try { // {@link handleWordList(Context,InputStream,ContentValues)}. diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java index ba1fce1a8..aea16af0d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java +++ b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java @@ -98,6 +98,10 @@ public final class WordListPreference extends Preference { setSummary(getSummary(status)); } + public boolean hasStatus(final int status) { + return status == mStatus; + } + @Override public View onCreateView(final ViewGroup parent) { final View orphanedView = mInterfaceState.findFirstOrphanedView(); @@ -217,6 +221,7 @@ public final class WordListPreference extends Preference { progressBar.setIds(mClientId, mWordlistId); progressBar.setMax(mFilesize); final boolean showProgressBar = (MetadataDbHelper.STATUS_DOWNLOADING == mStatus); + setSummary(getSummary(mStatus)); status.setVisibility(showProgressBar ? View.INVISIBLE : View.VISIBLE); progressBar.setVisibility(showProgressBar ? View.VISIBLE : View.INVISIBLE); diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java index ab6b70c04..8b808c6b3 100644 --- a/java/src/com/android/inputmethod/event/Combiner.java +++ b/java/src/com/android/inputmethod/event/Combiner.java @@ -16,14 +16,33 @@ package com.android.inputmethod.event; +import java.util.ArrayList; + /** - * A generic interface for combiners. + * A generic interface for combiners. Combiners are objects that transform chains of input events + * into committable strings and manage feedback to show to the user on the combining state. */ public interface Combiner { /** - * Combine an event with the existing state and return the new event. + * Process an event, possibly combining it with the existing state and return the new event. + * + * If this event does not result in any new event getting passed down the chain, this method + * returns null. It may also modify the previous event list if appropriate. + * + * @param previousEvents the previous events in this composition. * @param event the event to combine with the existing state. * @return the resulting event. */ - Event combine(Event event); + Event processEvent(ArrayList<Event> previousEvents, Event event); + + /** + * Get the feedback that should be shown to the user for the current state of this combiner. + * @return A CharSequence representing the feedback to show users. It may include styles. + */ + CharSequence getCombiningStateFeedback(); + + /** + * Reset the state of this combiner, for example when the cursor was moved. + */ + void reset(); } diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java new file mode 100644 index 000000000..8b59dc52a --- /dev/null +++ b/java/src/com/android/inputmethod/event/CombinerChain.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 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.event; + +import android.text.SpannableStringBuilder; +import android.text.TextUtils; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.util.ArrayList; + +/** + * This class implements the logic chain between receiving events and generating code points. + * + * Event sources are multiple. It may be a hardware keyboard, a D-PAD, a software keyboard, + * or any exotic input source. + * This class will orchestrate the composing chain that starts with an event as its input. Each + * composer will be given turns one after the other. + * The output is composed of two sequences of code points: the first, representing the already + * finished combining part, will be shown normally as the composing string, while the second is + * feedback on the composing state and will typically be shown with different styling such as + * a colored background. + */ +public class CombinerChain { + // The already combined text, as described above + private StringBuilder mCombinedText; + // The feedback on the composing state, as described above + private SpannableStringBuilder mStateFeedback; + private final ArrayList<Combiner> mCombiners; + + /** + * Create an combiner chain. + * + * The combiner chain takes events as inputs and outputs code points and combining state. + * For example, if the input language is Japanese, the combining chain will typically perform + * kana conversion. + * + * @param combinerList A list of combiners to be applied in order. + */ + public CombinerChain(final Combiner... combinerList) { + mCombiners = CollectionUtils.newArrayList(); + // The dead key combiner is always active, and always first + mCombiners.add(new DeadKeyCombiner()); + mCombinedText = new StringBuilder(); + mStateFeedback = new SpannableStringBuilder(); + } + + public void reset() { + mCombinedText.setLength(0); + mStateFeedback.clear(); + for (final Combiner c : mCombiners) { + c.reset(); + } + } + + /** + * Pass a new event through the whole chain. + * @param previousEvents the list of previous events in this composition + * @param newEvent the new event to process + */ + public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { + final ArrayList<Event> modifiablePreviousEvents = new ArrayList<Event>(previousEvents); + Event event = newEvent; + for (final Combiner combiner : mCombiners) { + // A combiner can never return more than one event; it can return several + // code points, but they should be encapsulated within one event. + event = combiner.processEvent(modifiablePreviousEvents, event); + if (null == event) { + // Combiners return null if they eat the event. + break; + } + } + if (null != event) { + // TODO: figure out the generic way of doing this + if (Constants.CODE_DELETE == event.mKeyCode) { + final int length = mCombinedText.length(); + if (length > 0) { + final int lastCodePoint = mCombinedText.codePointBefore(length); + mCombinedText.delete(length - Character.charCount(lastCodePoint), length); + } + } else { + final CharSequence textToCommit = event.getTextToCommit(); + if (!TextUtils.isEmpty(textToCommit)) { + mCombinedText.append(textToCommit); + } + } + } + mStateFeedback.clear(); + for (int i = mCombiners.size() - 1; i >= 0; --i) { + mStateFeedback.append(mCombiners.get(i).getCombiningStateFeedback()); + } + } + + /** + * Get the char sequence that should be displayed as the composing word. It may include + * styling spans. + */ + public CharSequence getComposingWordWithCombiningFeedback() { + final SpannableStringBuilder s = new SpannableStringBuilder(mCombinedText); + return s.append(mStateFeedback); + } +} diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java index 52987d571..bef4d8594 100644 --- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java +++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java @@ -21,14 +21,17 @@ import android.view.KeyCharacterMap; import com.android.inputmethod.latin.Constants; +import java.util.ArrayList; + /** * A combiner that handles dead keys. */ public class DeadKeyCombiner implements Combiner { + // TODO: make this a list of events instead final StringBuilder mDeadSequence = new StringBuilder(); @Override - public Event combine(final Event event) { + public Event processEvent(final ArrayList<Event> previousEvents, final Event event) { if (null == event) return null; // Just in case some combiner is broken if (TextUtils.isEmpty(mDeadSequence)) { if (event.isDead()) { @@ -43,19 +46,33 @@ public class DeadKeyCombiner implements Combiner { final int resultingCodePoint = KeyCharacterMap.getDeadChar(deadCodePoint, event.mCodePoint); if (0 == resultingCodePoint) { - // We can't combine both characters. We need to commit the dead key as a committable + // We can't combine both characters. We need to commit the dead key as a separate // character, and the next char too unless it's a space (because as a special case, // dead key + space should result in only the dead key being committed - that's // how dead keys work). // If the event is a space, we should commit the dead char alone, but if it's // not, we need to commit both. - return Event.createCommittableEvent(deadCodePoint, - Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */); + // TODO: this is not necessarily triggered by hardware key events, so it's not + // a good idea to masquerade as one. This should be typed as a software + // composite event or something. + return Event.createHardwareKeypressEvent(deadCodePoint, event.mKeyCode, + Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */, + false /* isKeyRepeat */); } else { // We could combine the characters. - return Event.createCommittableEvent(resultingCodePoint, null /* next */); + return Event.createHardwareKeypressEvent(resultingCodePoint, event.mKeyCode, + null /* next */, false /* isKeyRepeat */); } } } + @Override + public void reset() { + mDeadSequence.setLength(0); + } + + @Override + public CharSequence getCombiningStateFeedback() { + return mDeadSequence; + } } diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index 1f3320eb7..4a9163c8e 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -16,6 +16,10 @@ package com.android.inputmethod.event; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.utils.StringUtils; + /** * Class representing a generic input event as handled by Latin IME. * @@ -32,62 +36,227 @@ public class Event { // Should the types below be represented by separate classes instead? It would be cleaner // but probably a bit too much // An event we don't handle in Latin IME, for example pressing Ctrl on a hardware keyboard. - final public static int EVENT_NOT_HANDLED = 0; - // A character that is already final, for example pressing an alphabetic character on a - // hardware qwerty keyboard. - final public static int EVENT_COMMITTABLE = 1; - // A dead key, which means a character that should combine with what is coming next. Examples - // include the "^" character on an azerty keyboard which combines with "e" to make "ê", or - // AltGr+' on a dvorak international keyboard which combines with "e" to make "é". This is - // true regardless of the language or combining mode, and should be seen as a property of the - // key - a dead key followed by another key with which it can combine should be regarded as if - // the keyboard actually had such a key. - final public static int EVENT_DEAD = 2; + final public static int EVENT_TYPE_NOT_HANDLED = 0; + // A key press that is part of input, for example pressing an alphabetic character on a + // hardware qwerty keyboard. It may be part of a sequence that will be re-interpreted later + // through combination. + final public static int EVENT_TYPE_INPUT_KEYPRESS = 1; // A toggle event is triggered by a key that affects the previous character. An example would // be a numeric key on a 10-key keyboard, which would toggle between 1 - a - b - c with // repeated presses. - final public static int EVENT_TOGGLE = 3; + final public static int EVENT_TYPE_TOGGLE = 2; // A mode event instructs the combiner to change modes. The canonical example would be the // hankaku/zenkaku key on a Japanese keyboard, or even the caps lock key on a qwerty keyboard // if handled at the combiner level. - final public static int EVENT_MODE_KEY = 4; + final public static int EVENT_TYPE_MODE_KEY = 3; + // An event corresponding to a gesture. + final public static int EVENT_TYPE_GESTURE = 4; + // An event corresponding to the manual pick of a suggestion. + final public static int EVENT_TYPE_SUGGESTION_PICKED = 5; + // An event corresponding to a string generated by some software process. + final public static int EVENT_TYPE_SOFTWARE_GENERATED_STRING = 6; + + // 0 is a valid code point, so we use -1 here. + final public static int NOT_A_CODE_POINT = -1; + // -1 is a valid key code, so we use 0 here. + final public static int NOT_A_KEY_CODE = 0; - final private static int NOT_A_CODE_POINT = 0; + final private static int FLAG_NONE = 0; + // This event is a dead character, usually input by a dead key. Examples include dead-acute + // or dead-abovering. + final private static int FLAG_DEAD = 0x1; + // This event is coming from a key repeat, software or hardware. + final private static int FLAG_REPEAT = 0x2; - final private int mType; // The type of event - one of the constants above + final private int mEventType; // The type of event - one of the constants above // The code point associated with the event, if relevant. This is a unicode code point, and // has nothing to do with other representations of the key. It is only relevant if this event - // is the right type: COMMITTABLE or DEAD or TOGGLE, but for a mode key like hankaku/zenkaku or - // ctrl, there is no code point associated so this should be NOT_A_CODE_POINT to avoid - // unintentional use of its value when it's not relevant. + // is of KEYPRESS type, but for a mode key like hankaku/zenkaku or ctrl, there is no code point + // associated so this should be NOT_A_CODE_POINT to avoid unintentional use of its value when + // it's not relevant. final public int mCodePoint; + + // If applicable, this contains the string that should be input. + final public CharSequence mText; + + // The key code associated with the event, if relevant. This is relevant whenever this event + // has been triggered by a key press, but not for a gesture for example. This has conceptually + // no link to the code point, although keys that enter a straight code point may often set + // this to be equal to mCodePoint for convenience. If this is not a key, this must contain + // NOT_A_KEY_CODE. + final public int mKeyCode; + + // Coordinates of the touch event, if relevant. If useful, we may want to replace this with + // a MotionEvent or something in the future. This is only relevant when the keypress is from + // a software keyboard obviously, unless there are touch-sensitive hardware keyboards in the + // future or some other awesome sauce. + final public int mX; + final public int mY; + + // Some flags that can't go into the key code. It's a bit field of FLAG_* + final private int mFlags; + + // If this is of type EVENT_TYPE_SUGGESTION_PICKED, this must not be null (and must be null in + // other cases). + final public SuggestedWordInfo mSuggestedWordInfo; + // The next event, if any. Null if there is no next event yet. final public Event mNextEvent; // This method is private - to create a new event, use one of the create* utility methods. - private Event(final int type, final int codePoint, final Event next) { - mType = type; + private Event(final int type, final CharSequence text, final int codePoint, final int keyCode, + final int x, final int y, final SuggestedWordInfo suggestedWordInfo, final int flags, + final Event next) { + mEventType = type; + mText = text; mCodePoint = codePoint; + mKeyCode = keyCode; + mX = x; + mY = y; + mSuggestedWordInfo = suggestedWordInfo; + mFlags = flags; mNextEvent = next; + // Sanity checks + // mSuggestedWordInfo is non-null if and only if the type is SUGGESTION_PICKED + if (EVENT_TYPE_SUGGESTION_PICKED == mEventType) { + if (null == mSuggestedWordInfo) { + throw new RuntimeException("Wrong event: SUGGESTION_PICKED event must have a " + + "non-null SuggestedWordInfo"); + } + } else { + if (null != mSuggestedWordInfo) { + throw new RuntimeException("Wrong event: only SUGGESTION_PICKED events may have " + + "a non-null SuggestedWordInfo"); + } + } } - public static Event createDeadEvent(final int codePoint, final Event next) { - return new Event(EVENT_DEAD, codePoint, next); + public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode, + final int x, final int y, final boolean isKeyRepeat) { + return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, x, y, + null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, null); } - public static Event createCommittableEvent(final int codePoint, final Event next) { - return new Event(EVENT_COMMITTABLE, codePoint, next); + public static Event createHardwareKeypressEvent(final int codePoint, final int keyCode, + final Event next, final boolean isKeyRepeat) { + return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, + Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE, + null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, next); } - public static Event createNotHandledEvent() { - return new Event(EVENT_NOT_HANDLED, NOT_A_CODE_POINT, null); + // This creates an input event for a dead character. @see {@link #FLAG_DEAD} + public static Event createDeadEvent(final int codePoint, final int keyCode, final Event next) { + // TODO: add an argument or something if we ever create a software layout with dead keys. + return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, + Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE, + null /* suggestedWordInfo */, FLAG_DEAD, next); + } + + /** + * Create an input event with nothing but a code point. This is the most basic possible input + * event; it contains no information on many things the IME requires to function correctly, + * so avoid using it unless really nothing is known about this input. + * @param codePoint the code point. + * @return an event for this code point. + */ + public static Event createEventForCodePointFromUnknownSource(final int codePoint) { + // TODO: should we have a different type of event for this? After all, it's not a key press. + return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, + null /* suggestedWordInfo */, FLAG_NONE, null /* next */); + } + + /** + * Creates an input event with a code point and x, y coordinates. This is typically used when + * resuming a previously-typed word, when the coordinates are still known. + * @param codePoint the code point to input. + * @param x the X coordinate. + * @param y the Y coordinate. + * @return an event for this code point and coordinates. + */ + public static Event createEventForCodePointFromAlreadyTypedText(final int codePoint, + final int x, final int y) { + // TODO: should we have a different type of event for this? After all, it's not a key press. + return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, NOT_A_KEY_CODE, + x, y, null /* suggestedWordInfo */, FLAG_NONE, null /* next */); + } + + /** + * Creates an input event representing the manual pick of a suggestion. + * @return an event for this suggestion pick. + */ + public static Event createSuggestionPickedEvent(final SuggestedWordInfo suggestedWordInfo) { + return new Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, + NOT_A_CODE_POINT, NOT_A_KEY_CODE, + Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, + suggestedWordInfo, FLAG_NONE, null /* next */); + } + + /** + * Creates an input event with a CharSequence. This is used by some software processes whose + * output is a string, possibly with styling. Examples include press on a multi-character key, + * or combination that outputs a string. + * @param text the CharSequence associated with this event. + * @param keyCode the key code, or NOT_A_KEYCODE if not applicable. + * @return an event for this text. + */ + public static Event createSoftwareTextEvent(final CharSequence text, final int keyCode) { + return new Event(EVENT_TYPE_SOFTWARE_GENERATED_STRING, text, NOT_A_CODE_POINT, keyCode, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, + null /* suggestedWordInfo */, FLAG_NONE, null /* next */); } - public boolean isCommittable() { - return EVENT_COMMITTABLE == mType; + /** + * Creates an input event representing the manual pick of a punctuation suggestion. + * @return an event for this suggestion pick. + */ + public static Event createPunctuationSuggestionPickedEvent( + final SuggestedWordInfo suggestedWordInfo) { + final int primaryCode = suggestedWordInfo.mWord.charAt(0); + return new Event(EVENT_TYPE_SUGGESTION_PICKED, suggestedWordInfo.mWord, primaryCode, + NOT_A_KEY_CODE, Constants.SUGGESTION_STRIP_COORDINATE, + Constants.SUGGESTION_STRIP_COORDINATE, suggestedWordInfo, FLAG_NONE, + null /* next */); } + public static Event createNotHandledEvent() { + return new Event(EVENT_TYPE_NOT_HANDLED, null /* text */, NOT_A_CODE_POINT, NOT_A_KEY_CODE, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, + null /* suggestedWordInfo */, FLAG_NONE, null); + } + + // Returns whether this event is for a dead character. @see {@link #FLAG_DEAD} public boolean isDead() { - return EVENT_DEAD == mType; + return 0 != (FLAG_DEAD & mFlags); + } + + public boolean isKeyRepeat() { + return 0 != (FLAG_REPEAT & mFlags); + } + + // Returns whether this is a fake key press from the suggestion strip. This happens with + // punctuation signs selected from the suggestion strip. + public boolean isSuggestionStripPress() { + return EVENT_TYPE_SUGGESTION_PICKED == mEventType; + } + + public boolean isHandled() { + return EVENT_TYPE_NOT_HANDLED != mEventType; + } + + public CharSequence getTextToCommit() { + switch (mEventType) { + case EVENT_TYPE_MODE_KEY: + case EVENT_TYPE_NOT_HANDLED: + case EVENT_TYPE_TOGGLE: + return ""; + case EVENT_TYPE_INPUT_KEYPRESS: + return StringUtils.newSingleCodePointString(mCodePoint); + case EVENT_TYPE_GESTURE: + case EVENT_TYPE_SOFTWARE_GENERATED_STRING: + case EVENT_TYPE_SUGGESTION_PICKED: + return mText; + } + throw new RuntimeException("Unknown event type: " + mEventType); } } diff --git a/java/src/com/android/inputmethod/event/EventInterpreter.java b/java/src/com/android/inputmethod/event/EventInterpreter.java deleted file mode 100644 index 726b9206b..000000000 --- a/java/src/com/android/inputmethod/event/EventInterpreter.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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.event; - -import android.util.SparseArray; -import android.view.KeyEvent; - -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.LatinIME; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.util.ArrayList; - -/** - * This class implements the logic between receiving events and generating code points. - * - * Event sources are multiple. It may be a hardware keyboard, a D-PAD, a software keyboard, - * or any exotic input source. - * This class will orchestrate the decoding chain that starts with an event and ends up with - * a stream of code points + decoding state. - */ -public class EventInterpreter { - // TODO: Implement an object pool for events, as we'll create a lot of them - // TODO: Create a combiner - // TODO: Create an object type to represent input material + visual feedback + decoding state - // TODO: Create an interface to call back to Latin IME through the above object - - final EventDecoderSpec mDecoderSpec; - final SparseArray<HardwareEventDecoder> mHardwareEventDecoders; - final SoftwareEventDecoder mSoftwareEventDecoder; - final LatinIME mLatinIme; - final ArrayList<Combiner> mCombiners; - - /** - * Create a default interpreter. - * - * This creates a default interpreter that does nothing. A default interpreter should normally - * only be used for fallback purposes, when we really don't know what we want to do with input. - * - * @param latinIme a reference to the ime. - */ - public EventInterpreter(final LatinIME latinIme) { - this(null, latinIme); - } - - /** - * Create an event interpreter according to a specification. - * - * The specification contains information about what to do with events. Typically, it will - * contain information about the type of keyboards - for example, if hardware keyboard(s) is/are - * attached, their type will be included here so that the decoder knows what to do with each - * keypress (a 10-key keyboard is not handled like a qwerty-ish keyboard). - * It also contains information for combining characters. For example, if the input language - * is Japanese, the specification will typically request kana conversion. - * Also note that the specification can be null. This means that we need to create a default - * interpreter that does no specific combining, and assumes the most common cases. - * - * @param specification the specification for event interpretation. null for default. - * @param latinIme a reference to the ime. - */ - public EventInterpreter(final EventDecoderSpec specification, final LatinIME latinIme) { - mDecoderSpec = null != specification ? specification : new EventDecoderSpec(); - // For both, we expect to have only one decoder in almost all cases, hence the default - // capacity of 1. - mHardwareEventDecoders = new SparseArray<HardwareEventDecoder>(1); - mSoftwareEventDecoder = new SoftwareKeyboardEventDecoder(); - mCombiners = CollectionUtils.newArrayList(); - mCombiners.add(new DeadKeyCombiner()); - mLatinIme = latinIme; - } - - // Helper method to decode a hardware key event into a generic event, and execute any - // necessary action. - public boolean onHardwareKeyEvent(final KeyEvent hardwareKeyEvent) { - final Event decodedEvent = getHardwareKeyEventDecoder(hardwareKeyEvent.getDeviceId()) - .decodeHardwareKey(hardwareKeyEvent); - return onEvent(decodedEvent); - } - - public boolean onSoftwareEvent() { - final Event decodedEvent = getSoftwareEventDecoder().decodeSoftwareEvent(); - return onEvent(decodedEvent); - } - - private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) { - final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId); - if (null != decoder) return decoder; - // TODO: create the decoder according to the specification - final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId); - mHardwareEventDecoders.put(deviceId, newDecoder); - return newDecoder; - } - - private SoftwareEventDecoder getSoftwareEventDecoder() { - // Within the context of Latin IME, since we never present several software interfaces - // at the time, we should never need multiple software event decoders at a time. - return mSoftwareEventDecoder; - } - - private boolean onEvent(final Event event) { - Event currentlyProcessingEvent = event; - boolean processed = false; - for (int i = 0; i < mCombiners.size(); ++i) { - currentlyProcessingEvent = mCombiners.get(i).combine(event); - } - while (null != currentlyProcessingEvent) { - if (currentlyProcessingEvent.isCommittable()) { - mLatinIme.onCodeInput(currentlyProcessingEvent.mCodePoint, - Constants.EXTERNAL_KEYBOARD_COORDINATE, - Constants.EXTERNAL_KEYBOARD_COORDINATE); - processed = true; - } else if (event.isDead()) { - processed = true; - } - currentlyProcessingEvent = currentlyProcessingEvent.mNextEvent; - } - return processed; - } -} diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java index 720d07433..05ba99923 100644 --- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java +++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java @@ -46,28 +46,36 @@ public class HardwareKeyboardEventDecoder implements HardwareEventDecoder { // do not necessarily map to a unicode character. This represents a physical key, like // the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock. final int keyCode = keyEvent.getKeyCode(); + final boolean isKeyRepeat = (0 != keyEvent.getRepeatCount()); if (KeyEvent.KEYCODE_DEL == keyCode) { - return Event.createCommittableEvent(Constants.CODE_DELETE, null /* next */); + return Event.createHardwareKeypressEvent(Event.NOT_A_CODE_POINT, Constants.CODE_DELETE, + null /* next */, isKeyRepeat); } if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode || KeyEvent.KEYCODE_ENTER == keyCode) { if (0 != (codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT)) { // A dead key. return Event.createDeadEvent( - codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK, null /* next */); + codePointAndFlags & KeyCharacterMap.COMBINING_ACCENT_MASK, keyCode, + null /* next */); } if (KeyEvent.KEYCODE_ENTER == keyCode) { // The Enter key. If the Shift key is not being pressed, this should send a // CODE_ENTER to trigger the action if any, or a carriage return otherwise. If the // Shift key is being pressed, this should send a CODE_SHIFT_ENTER and let // Latin IME decide what to do with it. - return Event.createCommittableEvent(keyEvent.isShiftPressed() - ? Constants.CODE_SHIFT_ENTER : Constants.CODE_ENTER, - null /* next */); + if (keyEvent.isShiftPressed()) { + return Event.createHardwareKeypressEvent(Event.NOT_A_CODE_POINT, + Constants.CODE_SHIFT_ENTER, null /* next */, isKeyRepeat); + } else { + return Event.createHardwareKeypressEvent(Constants.CODE_ENTER, keyCode, + null /* next */, isKeyRepeat); + } } - // If not Enter, then we have a committable character. This should be committed - // right away, taking into account the current state. - return Event.createCommittableEvent(codePointAndFlags, null /* next */); + // If not Enter, then this is just a regular keypress event for a normal character + // that can be committed right away, taking into account the current state. + return Event.createHardwareKeypressEvent(keyCode, codePointAndFlags, null /* next */, + isKeyRepeat); } return Event.createNotHandledEvent(); } diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java new file mode 100644 index 000000000..4fe9b403e --- /dev/null +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014 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.event; + +import com.android.inputmethod.latin.settings.SettingsValues; + +/** + * An object encapsulating a single transaction for input. + */ +public class InputTransaction { + // UPDATE_LATER is stronger than UPDATE_NOW. The reason for this is, if we have to update later, + // it's because something will change that we can't evaluate now, which means that even if we + // re-evaluate now we'll have to do it again later. The only case where that wouldn't apply + // would be if we needed to update now to find out the new state right away, but then we + // can't do it with this deferred mechanism anyway. + public static final int SHIFT_NO_UPDATE = 0; + public static final int SHIFT_UPDATE_NOW = 1; + public static final int SHIFT_UPDATE_LATER = 2; + + // Initial conditions + public final SettingsValues mSettingsValues; + public final Event mEvent; + public final long mTimestamp; + public final int mSpaceState; + public final int mShiftState; + + // Outputs + private int mRequiredShiftUpdate = SHIFT_NO_UPDATE; + private boolean mRequiresUpdateSuggestions = false; + + public InputTransaction(final SettingsValues settingsValues, final Event event, + final long timestamp, final int spaceState, final int shiftState) { + mSettingsValues = settingsValues; + mEvent = event; + mTimestamp = timestamp; + mSpaceState = spaceState; + mShiftState = shiftState; + } + + /** + * Indicate that this transaction requires some type of shift update. + * @param updateType What type of shift update this requires. + */ + public void requireShiftUpdate(final int updateType) { + mRequiredShiftUpdate = Math.max(mRequiredShiftUpdate, updateType); + } + + /** + * Gets what type of shift update this transaction requires. + * @return The shift update type. + */ + public int getRequiredShiftUpdate() { + return mRequiredShiftUpdate; + } + + /** + * Indicate that this transaction requires updating the suggestions. + */ + public void setRequiresUpdateSuggestions() { + mRequiresUpdateSuggestions = true; + } + + /** + * Find out whether this transaction requires updating the suggestions. + * @return Whether this transaction requires updating the suggestions. + */ + public boolean requiresUpdateSuggestions() { + return mRequiresUpdateSuggestions; + } +} diff --git a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java b/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java deleted file mode 100644 index d81ee0b37..000000000 --- a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.event; - -/** - * An event decoder for events out of a software keyboard. - * - * This defines the interface for an event decoder that supports events out of a software keyboard. - * This differs significantly from hardware keyboard event decoders in several respects. First, - * a software keyboard does not have a scancode/layout system; the keypresses that insert - * characters output unicode characters directly. - */ -public interface SoftwareEventDecoder extends EventDecoder { - public Event decodeSoftwareEvent(); -} diff --git a/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java b/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java index e23131a30..d56a3cf25 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java @@ -31,17 +31,17 @@ public class EmojiCategoryPageIndicatorView extends LinearLayout { private int mCurrentCategoryPageId = 0; private float mOffset = 0.0f; - public EmojiCategoryPageIndicatorView(Context context) { + public EmojiCategoryPageIndicatorView(final Context context) { this(context, null /* attrs */); } - public EmojiCategoryPageIndicatorView(Context context, AttributeSet attrs) { + public EmojiCategoryPageIndicatorView(final Context context, final AttributeSet attrs) { super(context, attrs); mPaint.setColor(context.getResources().getColor( R.color.emoji_category_page_id_view_foreground)); } - public void setCategoryPageId(int size, int id, float offset) { + public void setCategoryPageId(final int size, final int id, final float offset) { mCategoryPageSize = size; mCurrentCategoryPageId = id; mOffset = offset; @@ -49,7 +49,7 @@ public class EmojiCategoryPageIndicatorView extends LinearLayout { } @Override - protected void onDraw(Canvas canvas) { + protected void onDraw(final Canvas canvas) { if (mCategoryPageSize <= 1) { // If the category is not set yet or contains only one category, // just clear and return. diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java index f12373503..d8b5758a6 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java @@ -23,16 +23,18 @@ import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.Rect; import android.os.Build; +import android.os.CountDownTimer; import android.preference.PreferenceManager; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; -import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -44,8 +46,10 @@ import android.widget.TabHost.OnTabChangeListener; import android.widget.TextView; import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard; -import com.android.inputmethod.keyboard.internal.ScrollKeyboardView; -import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier; +import com.android.inputmethod.keyboard.internal.EmojiLayoutParams; +import com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView; +import com.android.inputmethod.keyboard.internal.KeyDrawParams; +import com.android.inputmethod.keyboard.internal.KeyVisualAttributes; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; @@ -54,10 +58,12 @@ import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; /** * View class to implement Emoji palettes. @@ -71,17 +77,19 @@ import java.util.concurrent.ConcurrentHashMap; * Because of the above reasons, this class doesn't extend {@link KeyboardView}. */ public final class EmojiPalettesView extends LinearLayout implements OnTabChangeListener, - ViewPager.OnPageChangeListener, View.OnClickListener, - ScrollKeyboardView.OnKeyClickListener { - private static final String TAG = EmojiPalettesView.class.getSimpleName(); + ViewPager.OnPageChangeListener, View.OnClickListener, View.OnTouchListener, + EmojiPageKeyboardView.OnKeyEventListener { + static final String TAG = EmojiPalettesView.class.getSimpleName(); private static final boolean DEBUG_PAGER = false; private final int mKeyBackgroundId; private final int mEmojiFunctionalKeyBackgroundId; - private final KeyboardLayoutSet mLayoutSet; private final ColorStateList mTabLabelColor; private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; private EmojiPalettesAdapter mEmojiPalettesAdapter; + private final EmojiLayoutParams mEmojiLayoutParams; + private TextView mAlphabetKeyLeft; + private TextView mAlphabetKeyRight; private TabHost mTabHost; private ViewPager mEmojiPager; private int mCurrentPagerPosition = 0; @@ -116,7 +124,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange "places", "symbols", "emoticons" }; - private static final int[] sCategoryIcon = new int[] { + private static final int[] sCategoryIcon = { R.drawable.ic_emoji_recent_light, R.drawable.ic_emoji_people_light, R.drawable.ic_emoji_objects_light, @@ -126,6 +134,14 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange 0 }; private static final String[] sCategoryLabel = { null, null, null, null, null, null, ":-)" }; + private static final int[] sAccessibilityDescriptionResourceIdsForCategories = { + R.string.spoken_descrption_emoji_category_recents, + R.string.spoken_descrption_emoji_category_people, + R.string.spoken_descrption_emoji_category_objects, + R.string.spoken_descrption_emoji_category_nature, + R.string.spoken_descrption_emoji_category_places, + R.string.spoken_descrption_emoji_category_symbols, + R.string.spoken_descrption_emoji_category_emoticons }; private static final int[] sCategoryElementId = { KeyboardId.ELEMENT_EMOJI_RECENTS, KeyboardId.ELEMENT_EMOJI_CATEGORY1, @@ -135,6 +151,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange KeyboardId.ELEMENT_EMOJI_CATEGORY5, KeyboardId.ELEMENT_EMOJI_CATEGORY6 }; private final SharedPreferences mPrefs; + private final Resources mRes; private final int mMaxPageKeyCount; private final KeyboardLayoutSet mLayoutSet; private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap(); @@ -149,7 +166,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange public EmojiCategory(final SharedPreferences prefs, final Resources res, final KeyboardLayoutSet layoutSet) { mPrefs = prefs; - mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count); + mRes = res; + mMaxPageKeyCount = res.getInteger(R.integer.config_emoji_keyboard_max_page_key_count); mLayoutSet = layoutSet; for (int i = 0; i < sCategoryName.length; ++i) { mCategoryNameToIdMap.put(sCategoryName[i], i); @@ -174,7 +192,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange .loadRecentKeys(mCategoryKeyboardMap.values()); } - private void addShownCategoryId(int categoryId) { + private void addShownCategoryId(final int categoryId) { // Load a keyboard of categoryId getKeyboard(categoryId, 0 /* cagetoryPageId */); final CategoryProperties properties = @@ -182,23 +200,27 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange mShownCategories.add(properties); } - public String getCategoryName(int categoryId, int categoryPageId) { + public String getCategoryName(final int categoryId, final int categoryPageId) { return sCategoryName[categoryId] + "-" + categoryPageId; } - public int getCategoryId(String name) { + public int getCategoryId(final String name) { final String[] strings = name.split("-"); return mCategoryNameToIdMap.get(strings[0]); } - public int getCategoryIcon(int categoryId) { + public int getCategoryIcon(final int categoryId) { return sCategoryIcon[categoryId]; } - public String getCategoryLabel(int categoryId) { + public String getCategoryLabel(final int categoryId) { return sCategoryLabel[categoryId]; } + public String getAccessibilityDescription(final int categoryId) { + return mRes.getString(sAccessibilityDescriptionResourceIdsForCategories[categoryId]); + } + public ArrayList<CategoryProperties> getShownCategories() { return mShownCategories; } @@ -211,7 +233,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return getCategoryPageSize(mCurrentCategoryId); } - public int getCategoryPageSize(int categoryId) { + public int getCategoryPageSize(final int categoryId) { for (final CategoryProperties prop : mShownCategories) { if (prop.mCategoryId == categoryId) { return prop.mPageCount; @@ -222,12 +244,12 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return 0; } - public void setCurrentCategoryId(int categoryId) { + public void setCurrentCategoryId(final int categoryId) { mCurrentCategoryId = categoryId; Settings.writeLastShownEmojiCategoryId(mPrefs, categoryId); } - public void setCurrentCategoryPageId(int id) { + public void setCurrentCategoryPageId(final int id) { mCurrentCategoryPageId = id; } @@ -244,7 +266,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return mCurrentCategoryId == CATEGORY_ID_RECENTS; } - public int getTabIdFromCategoryId(int categoryId) { + public int getTabIdFromCategoryId(final int categoryId) { for (int i = 0; i < mShownCategories.size(); ++i) { if (mShownCategories.get(i).mCategoryId == categoryId) { return i; @@ -255,7 +277,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } // Returns the view pager's page position for the categoryId - public int getPageIdFromCategoryId(int categoryId) { + public int getPageIdFromCategoryId(final int categoryId) { final int lastSavedCategoryPageId = Settings.readLastTypedEmojiCategoryPageId(mPrefs, categoryId); int sum = 0; @@ -274,18 +296,18 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return getTabIdFromCategoryId(CATEGORY_ID_RECENTS); } - private int getCategoryPageCount(int categoryId) { + private int getCategoryPageCount(final int categoryId) { final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); - return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1; + return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1; } // Returns a pair of the category id and the category page id from the view pager's page // position. The category page id is numbered in each category. And the view page position // is the position of the current shown page in the view pager which contains all pages of // all categories. - public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(int position) { + public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(final int position) { int sum = 0; - for (CategoryProperties properties : mShownCategories) { + for (final CategoryProperties properties : mShownCategories) { final int temp = sum; sum += properties.mPageCount; if (sum > position) { @@ -296,7 +318,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } // Returns a keyboard from the view pager's page position. - public DynamicGridKeyboard getKeyboardFromPagePosition(int position) { + public DynamicGridKeyboard getKeyboardFromPagePosition(final int position) { final Pair<Integer, Integer> categoryAndId = getCategoryIdAndPageIdFromPagePosition(position); if (categoryAndId != null) { @@ -305,39 +327,42 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return null; } - public DynamicGridKeyboard getKeyboard(int categoryId, int id) { - synchronized(mCategoryKeyboardMap) { - final long key = (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id; - final DynamicGridKeyboard kbd; - if (!mCategoryKeyboardMap.containsKey(key)) { - if (categoryId != CATEGORY_ID_RECENTS) { - final Keyboard keyboard = - mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); - final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount); - for (int i = 0; i < sortedKeys.length; ++i) { - final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard(mPrefs, - mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxPageKeyCount, categoryId, i /* categoryPageId */); - for (Key emojiKey : sortedKeys[i]) { - if (emojiKey == null) { - break; - } - tempKbd.addKeyLast(emojiKey); - } - mCategoryKeyboardMap.put((((long) categoryId) - << Constants.MAX_INT_BIT_COUNT) | i, tempKbd); + private static final Long getCategoryKeyboardMapKey(final int categoryId, final int id) { + return (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id; + } + + public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { + synchronized (mCategoryKeyboardMap) { + final Long categotyKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id); + if (mCategoryKeyboardMap.containsKey(categotyKeyboardMapKey)) { + return mCategoryKeyboardMap.get(categotyKeyboardMapKey); + } + + if (categoryId == CATEGORY_ID_RECENTS) { + final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, + mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + mMaxPageKeyCount, categoryId); + mCategoryKeyboardMap.put(categotyKeyboardMapKey, kbd); + return kbd; + } + + final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); + final Key[][] sortedKeys = sortKeysIntoPages( + keyboard.getSortedKeys(), mMaxPageKeyCount); + for (int pageId = 0; pageId < sortedKeys.length; ++pageId) { + final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, + mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + mMaxPageKeyCount, categoryId); + for (final Key emojiKey : sortedKeys[pageId]) { + if (emojiKey == null) { + break; } - kbd = mCategoryKeyboardMap.get(key); - } else { - kbd = new DynamicGridKeyboard(mPrefs, - mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxPageKeyCount, categoryId, 0 /* categoryPageId */); - mCategoryKeyboardMap.put(key, kbd); + tempKeyboard.addKeyLast(emojiKey); } - } else { - kbd = mCategoryKeyboardMap.get(key); + mCategoryKeyboardMap.put( + getCategoryKeyboardMapKey(categoryId, pageId), tempKeyboard); } - return kbd; + return mCategoryKeyboardMap.get(categotyKeyboardMapKey); } } @@ -349,33 +374,35 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return sum; } - private Key[][] sortKeys(Key[] inKeys, int maxPageCount) { - Key[] keys = Arrays.copyOf(inKeys, inKeys.length); - Arrays.sort(keys, 0, keys.length, new Comparator<Key>() { - @Override - public int compare(Key lhs, Key rhs) { - final Rect lHitBox = lhs.getHitBox(); - final Rect rHitBox = rhs.getHitBox(); - if (lHitBox.top < rHitBox.top) { - return -1; - } else if (lHitBox.top > rHitBox.top) { - return 1; - } - if (lHitBox.left < rHitBox.left) { - return -1; - } else if (lHitBox.left > rHitBox.left) { - return 1; - } - if (lhs.getCode() == rhs.getCode()) { - return 0; - } - return lhs.getCode() < rhs.getCode() ? -1 : 1; + private static Comparator<Key> EMOJI_KEY_COMPARATOR = new Comparator<Key>() { + @Override + public int compare(final Key lhs, final Key rhs) { + final Rect lHitBox = lhs.getHitBox(); + final Rect rHitBox = rhs.getHitBox(); + if (lHitBox.top < rHitBox.top) { + return -1; + } else if (lHitBox.top > rHitBox.top) { + return 1; + } + if (lHitBox.left < rHitBox.left) { + return -1; + } else if (lHitBox.left > rHitBox.left) { + return 1; } - }); - final int pageCount = (keys.length - 1) / maxPageCount + 1; + if (lhs.getCode() == rhs.getCode()) { + return 0; + } + return lhs.getCode() < rhs.getCode() ? -1 : 1; + } + }; + + private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) { + final ArrayList<Key> keys = CollectionUtils.newArrayList(inKeys); + Collections.sort(keys, EMOJI_KEY_COMPARATOR); + final int pageCount = (keys.size() - 1) / maxPageCount + 1; final Key[][] retval = new Key[pageCount][maxPageCount]; - for (int i = 0; i < keys.length; ++i) { - retval[i / maxPageCount][i % maxPageCount] = keys[i]; + for (int i = 0; i < keys.size(); ++i) { + retval[i / maxPageCount][i % maxPageCount] = keys.get(i); } return retval; } @@ -404,12 +431,12 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( context, null /* editorInfo */); final Resources res = context.getResources(); - final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res); + mEmojiLayoutParams = new EmojiLayoutParams(res); builder.setSubtype(SubtypeSwitcher.getInstance().getEmojiSubtype()); builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res), - emojiLp.mEmojiKeyboardHeight); - builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */); - mLayoutSet = builder.build(); + mEmojiLayoutParams.mEmojiKeyboardHeight); + builder.setOptions(false /* shortcutImeEnabled */, false /* showsVoiceInputKey */, + false /* languageSwitchKeyEnabled */); mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context), context.getResources(), builder.build()); mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(context); @@ -423,7 +450,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final int width = ResourceUtils.getDefaultKeyboardWidth(res) + getPaddingLeft() + getPaddingRight(); final int height = ResourceUtils.getDefaultKeyboardHeight(res) - + res.getDimensionPixelSize(R.dimen.suggestions_strip_height) + + res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height) + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(width, height); } @@ -436,12 +463,14 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate( R.layout.emoji_keyboard_tab_icon, null); iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId)); + iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); tspec.setIndicator(iconView); } if (mEmojiCategory.getCategoryLabel(categoryId) != null) { final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate( R.layout.emoji_keyboard_tab_label, null); textView.setText(mEmojiCategory.getCategoryLabel(categoryId)); + textView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); textView.setTextColor(mTabLabelColor); tspec.setIndicator(textView); } @@ -458,42 +487,60 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange mTabHost.setOnTabChangedListener(this); mTabHost.getTabWidget().setStripEnabled(true); - mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, mLayoutSet, this); + mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this); mEmojiPager = (ViewPager)findViewById(R.id.emoji_keyboard_pager); mEmojiPager.setAdapter(mEmojiPalettesAdapter); mEmojiPager.setOnPageChangeListener(this); mEmojiPager.setOffscreenPageLimit(0); - mEmojiPager.setPersistentDrawingCache(ViewPager.PERSISTENT_NO_CACHE); - final Resources res = getResources(); - final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res); - emojiLp.setPagerProperties(mEmojiPager); + mEmojiPager.setPersistentDrawingCache(PERSISTENT_NO_CACHE); + mEmojiLayoutParams.setPagerProperties(mEmojiPager); mEmojiCategoryPageIndicatorView = (EmojiCategoryPageIndicatorView)findViewById(R.id.emoji_category_page_id_view); - emojiLp.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView); + mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView); setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */); final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar); - emojiLp.setActionBarProperties(actionBar); + mEmojiLayoutParams.setActionBarProperties(actionBar); + // deleteKey depends only on OnTouchListener. final ImageView deleteKey = (ImageView)findViewById(R.id.emoji_keyboard_delete); deleteKey.setTag(Constants.CODE_DELETE); deleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); - final ImageView alphabetKey = (ImageView)findViewById(R.id.emoji_keyboard_alphabet); - alphabetKey.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); - alphabetKey.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL); - alphabetKey.setOnClickListener(this); + + // {@link #mAlphabetKeyLeft}, {@link #mAlphabetKeyRight, and spaceKey depend on + // {@link View.OnClickListener} as well as {@link View.OnTouchListener}. + // {@link View.OnTouchListener} is used as the trigger of key-press, while + // {@link View.OnClickListener} is used as the trigger of key-release which does not occur + // if the event is canceled by moving off the finger from the view. + // The text on alphabet keys are set at + // {@link #startEmojiPalettes(String,int,float,Typeface)}. + mAlphabetKeyLeft = (TextView)findViewById(R.id.emoji_keyboard_alphabet_left); + mAlphabetKeyLeft.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); + mAlphabetKeyLeft.setTag(Constants.CODE_ALPHA_FROM_EMOJI); + mAlphabetKeyLeft.setOnTouchListener(this); + mAlphabetKeyLeft.setOnClickListener(this); + mAlphabetKeyRight = (TextView)findViewById(R.id.emoji_keyboard_alphabet_right); + mAlphabetKeyRight.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); + mAlphabetKeyRight.setTag(Constants.CODE_ALPHA_FROM_EMOJI); + mAlphabetKeyRight.setOnTouchListener(this); + mAlphabetKeyRight.setOnClickListener(this); final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space); spaceKey.setBackgroundResource(mKeyBackgroundId); spaceKey.setTag(Constants.CODE_SPACE); + spaceKey.setOnTouchListener(this); spaceKey.setOnClickListener(this); - emojiLp.setKeyProperties(spaceKey); - final ImageView alphabetKey2 = (ImageView)findViewById(R.id.emoji_keyboard_alphabet2); - alphabetKey2.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); - alphabetKey2.setTag(Constants.CODE_SWITCH_ALPHA_SYMBOL); - alphabetKey2.setOnClickListener(this); + mEmojiLayoutParams.setKeyProperties(spaceKey); + } + + @Override + public boolean dispatchTouchEvent(final MotionEvent ev) { + // Add here to the stack trace to nail down the {@link IllegalArgumentException} exception + // in MotionEvent that sporadically happens. + // TODO: Remove this override method once the issue has been addressed. + return super.dispatchTouchEvent(ev); } @Override @@ -503,7 +550,6 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange updateEmojiCategoryPageIdView(); } - @Override public void onPageSelected(final int position) { final Pair<Integer, Integer> newPos = @@ -522,6 +568,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange @Override public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) { + mEmojiPalettesAdapter.onPageScrolled(); final Pair<Integer, Integer> newPos = mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position); final int newCategoryId = newPos.first; @@ -541,41 +588,100 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } + /** + * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener} + * interface to handle touch events from View-based elements such as the space bar. + * Note that this method is used only for observing {@link MotionEvent#ACTION_DOWN} to trigger + * {@link KeyboardActionListener#onPressKey}. {@link KeyboardActionListener#onReleaseKey} will + * be covered by {@link #onClick} as long as the event is not canceled. + */ @Override - public void onClick(final View v) { - if (v.getTag() instanceof Integer) { - final int code = (Integer)v.getTag(); - registerCode(code); + public boolean onTouch(final View v, final MotionEvent event) { + if (event.getActionMasked() != MotionEvent.ACTION_DOWN) { + return false; + } + final Object tag = v.getTag(); + if (!(tag instanceof Integer)) { + return false; + } + final int code = (Integer) tag; + mKeyboardActionListener.onPressKey( + code, 0 /* repeatCount */, true /* isSinglePointer */); + // It's important to return false here. Otherwise, {@link #onClick} and touch-down visual + // feedback stop working. + return false; + } + + /** + * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnClickListener} + * interface to handle non-canceled touch-up events from View-based elements such as the space + * bar. + */ + @Override + public void onClick(View v) { + final Object tag = v.getTag(); + if (!(tag instanceof Integer)) { return; } + final int code = (Integer) tag; + mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE, + false /* isKeyRepeat */); + mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); } - private void registerCode(final int code) { + /** + * Called from {@link EmojiPageKeyboardView} through + * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * interface to handle touch events from non-View-based elements such as Emoji buttons. + */ + @Override + public void onPressKey(final Key key) { + final int code = key.getCode(); mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */); - mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE); - mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); } + /** + * Called from {@link EmojiPageKeyboardView} through + * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * interface to handle touch events from non-View-based elements such as Emoji buttons. + */ @Override - public void onKeyClick(final Key key) { + public void onReleaseKey(final Key key) { mEmojiPalettesAdapter.addRecentKey(key); mEmojiCategory.saveLastTypedCategoryPage(); final int code = key.getCode(); if (code == Constants.CODE_OUTPUT_TEXT) { mKeyboardActionListener.onTextInput(key.getOutputText()); - return; + } else { + mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE, + false /* isKeyRepeat */); } - registerCode(code); + mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); } public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) { - // TODO: + if (!enabled) return; + // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off? + setLayerType(LAYER_TYPE_HARDWARE, null); } - public void startEmojiPalettes() { + private static void setupAlphabetKey(final TextView alphabetKey, final String label, + final KeyDrawParams params) { + alphabetKey.setText(label); + alphabetKey.setTextColor(params.mTextColor); + alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize); + alphabetKey.setTypeface(params.mTypeface); + } + + public void startEmojiPalettes(final String switchToAlphaLabel, + final KeyVisualAttributes keyVisualAttr) { if (DEBUG_PAGER) { Log.d(TAG, "allocate emoji palettes memory " + mCurrentPagerPosition); } + final KeyDrawParams params = new KeyDrawParams(); + params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr); + setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params); + setupAlphabetKey(mAlphabetKeyRight, switchToAlphaLabel, params); mEmojiPager.setAdapter(mEmojiPalettesAdapter); mEmojiPager.setCurrentItem(mCurrentPagerPosition); } @@ -628,16 +734,15 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } private static class EmojiPalettesAdapter extends PagerAdapter { - private final ScrollKeyboardView.OnKeyClickListener mListener; + private final EmojiPageKeyboardView.OnKeyEventListener mListener; private final DynamicGridKeyboard mRecentsKeyboard; - private final SparseArray<ScrollKeyboardView> mActiveKeyboardViews = + private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = CollectionUtils.newSparseArray(); private final EmojiCategory mEmojiCategory; private int mActivePosition = 0; public EmojiPalettesAdapter(final EmojiCategory emojiCategory, - final KeyboardLayoutSet layoutSet, - final ScrollKeyboardView.OnKeyClickListener listener) { + final EmojiPageKeyboardView.OnKeyEventListener listener) { mEmojiCategory = emojiCategory; mListener = listener; mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0); @@ -665,17 +770,28 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } + public void onPageScrolled() { + // Make sure the delayed key-down event (highlight effect and haptic feedback) will be + // canceled. + final EmojiPageKeyboardView currentKeyboardView = + mActiveKeyboardViews.get(mActivePosition); + if (currentKeyboardView != null) { + currentKeyboardView.releaseCurrentKey(); + } + } + @Override public int getCount() { return mEmojiCategory.getTotalPageCountOfAllCategories(); } @Override - public void setPrimaryItem(final View container, final int position, final Object object) { + public void setPrimaryItem(final ViewGroup container, final int position, + final Object object) { if (mActivePosition == position) { return; } - final ScrollKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition); + final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition); if (oldKeyboardView != null) { oldKeyboardView.releaseCurrentKey(); oldKeyboardView.deallocateMemory(); @@ -688,7 +804,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange if (DEBUG_PAGER) { Log.d(TAG, "instantiate item: " + position); } - final ScrollKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position); + final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position); if (oldKeyboardView != null) { oldKeyboardView.deallocateMemory(); // This may be redundant but wanted to be safer.. @@ -697,18 +813,13 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final Keyboard keyboard = mEmojiCategory.getKeyboardFromPagePosition(position); final LayoutInflater inflater = LayoutInflater.from(container.getContext()); - final View view = inflater.inflate( + final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate( R.layout.emoji_keyboard_page, container, false /* attachToRoot */); - final ScrollKeyboardView keyboardView = (ScrollKeyboardView)view.findViewById( - R.id.emoji_keyboard_page); keyboardView.setKeyboard(keyboard); - keyboardView.setOnKeyClickListener(mListener); - final ScrollViewWithNotifier scrollView = (ScrollViewWithNotifier)view.findViewById( - R.id.emoji_keyboard_scroller); - keyboardView.setScrollView(scrollView); - container.addView(view); + keyboardView.setOnKeyEventListener(mListener); + container.addView(keyboardView); mActiveKeyboardViews.put(position, keyboardView); - return view; + return keyboardView; } @Override @@ -722,7 +833,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange if (DEBUG_PAGER) { Log.d(TAG, "destroy item: " + position + ", " + object.getClass().getSimpleName()); } - final ScrollKeyboardView keyboardView = mActiveKeyboardViews.get(position); + final EmojiPageKeyboardView keyboardView = mActiveKeyboardViews.get(position); if (keyboardView != null) { keyboardView.deallocateMemory(); mActiveKeyboardViews.remove(position); @@ -735,9 +846,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } - // TODO: Do the same things done in PointerTracker private static class DeleteKeyOnTouchListener implements OnTouchListener { - private static final long MAX_REPEAT_COUNT_TIME = 30 * DateUtils.SECOND_IN_MILLIS; + private static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30); private final int mDeleteKeyPressedBackgroundColor; private final long mKeyRepeatStartTimeout; private final long mKeyRepeatInterval; @@ -748,80 +858,117 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange res.getColor(R.color.emoji_key_pressed_background_color); mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout); mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); + mTimer = new CountDownTimer(MAX_REPEAT_COUNT_TIME, mKeyRepeatInterval) { + @Override + public void onTick(long millisUntilFinished) { + final long elapsed = MAX_REPEAT_COUNT_TIME - millisUntilFinished; + if (elapsed < mKeyRepeatStartTimeout) { + return; + } + onKeyRepeat(); + } + @Override + public void onFinish() { + onKeyRepeat(); + } + }; } + /** Key-repeat state. */ + private static final int KEY_REPEAT_STATE_INITIALIZED = 0; + // The key is touched but auto key-repeat is not started yet. + private static final int KEY_REPEAT_STATE_KEY_DOWN = 1; + // At least one key-repeat event has already been triggered and the key is not released. + private static final int KEY_REPEAT_STATE_KEY_REPEAT = 2; + private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; - private DummyRepeatKeyRepeatTimer mTimer; - private synchronized void startRepeat() { - if (mTimer != null) { - abortRepeat(); - } - mTimer = new DummyRepeatKeyRepeatTimer(); - mTimer.start(); - } + // TODO: Do the same things done in PointerTracker + private final CountDownTimer mTimer; + private int mState = KEY_REPEAT_STATE_INITIALIZED; + private int mRepeatCount = 0; - private synchronized void abortRepeat() { - mTimer.abort(); - mTimer = null; + public void setKeyboardActionListener(final KeyboardActionListener listener) { + mKeyboardActionListener = listener; } - // TODO: Remove - // This function is mimicking the repeat code in PointerTracker. - // Specifically referring to PointerTracker#startRepeatKey and PointerTracker#onKeyRepeat. - private class DummyRepeatKeyRepeatTimer extends Thread { - public boolean mAborted = false; - - @Override - public void run() { - int repeatCount = 1; - int timeCount = 0; - while (timeCount < MAX_REPEAT_COUNT_TIME && !mAborted) { - if (timeCount > mKeyRepeatStartTimeout) { - pressDelete(repeatCount); - } - timeCount += mKeyRepeatInterval; - ++repeatCount; - try { - Thread.sleep(mKeyRepeatInterval); - } catch (InterruptedException e) { - } + @Override + public boolean onTouch(final View v, final MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + onTouchDown(v); + return true; + case MotionEvent.ACTION_MOVE: + final float x = event.getX(); + final float y = event.getY(); + if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) { + // Stop generating key events once the finger moves away from the view area. + onTouchCanceled(v); } + return true; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + onTouchUp(v); + return true; } - - public void abort() { - mAborted = true; - } + return false; } - public void pressDelete(int repeatCount) { + private void handleKeyDown() { mKeyboardActionListener.onPressKey( - Constants.CODE_DELETE, repeatCount, true /* isSinglePointer */); - mKeyboardActionListener.onCodeInput( - Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE); + Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */); + } + + private void handleKeyUp() { + mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE, + NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */); mKeyboardActionListener.onReleaseKey( Constants.CODE_DELETE, false /* withSliding */); + ++mRepeatCount; } - public void setKeyboardActionListener(KeyboardActionListener listener) { - mKeyboardActionListener = listener; + private void onTouchDown(final View v) { + mTimer.cancel(); + mRepeatCount = 0; + handleKeyDown(); + v.setBackgroundColor(mDeleteKeyPressedBackgroundColor); + mState = KEY_REPEAT_STATE_KEY_DOWN; + mTimer.start(); } - @Override - public boolean onTouch(View v, MotionEvent event) { - switch(event.getAction()) { - case MotionEvent.ACTION_DOWN: - v.setBackgroundColor(mDeleteKeyPressedBackgroundColor); - pressDelete(0 /* repeatCount */); - startRepeat(); - return true; - case MotionEvent.ACTION_UP: - v.setBackgroundColor(0); - abortRepeat(); - return true; + private void onTouchUp(final View v) { + mTimer.cancel(); + if (mState == KEY_REPEAT_STATE_KEY_DOWN) { + handleKeyUp(); + } + v.setBackgroundColor(Color.TRANSPARENT); + mState = KEY_REPEAT_STATE_INITIALIZED; + } + + private void onTouchCanceled(final View v) { + mTimer.cancel(); + v.setBackgroundColor(Color.TRANSPARENT); + mState = KEY_REPEAT_STATE_INITIALIZED; + } + + // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal. + private void onKeyRepeat() { + switch (mState) { + case KEY_REPEAT_STATE_INITIALIZED: + // Basically this should not happen. + break; + case KEY_REPEAT_STATE_KEY_DOWN: + // Do not call {@link #handleKeyDown} here because it has already been called + // in {@link #onTouchDown}. + handleKeyUp(); + mState = KEY_REPEAT_STATE_KEY_REPEAT; + break; + case KEY_REPEAT_STATE_KEY_REPEAT: + handleKeyDown(); + handleKeyUp(); + break; } - return false; } } } diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index f7ec9509d..816a94300 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -22,14 +22,11 @@ import static com.android.inputmethod.latin.Constants.CODE_SHIFT; import static com.android.inputmethod.latin.Constants.CODE_SWITCH_ALPHA_SYMBOL; import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; -import android.content.res.Resources; import android.content.res.TypedArray; 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.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeySpecParser; @@ -43,9 +40,6 @@ import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.StringUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.util.Arrays; import java.util.Locale; @@ -53,8 +47,6 @@ import java.util.Locale; * Class for describing the position and characteristics of a single key in the keyboard. */ public class Key implements Comparable<Key> { - private static final String TAG = Key.class.getSimpleName(); - /** * The key code (unicode or custom code) that this key generates. */ @@ -84,10 +76,16 @@ public class Key implements Comparable<Key> { 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; + // The bit to calculate the ratio of key label width against key width. If autoXScale bit is on + // and autoYScale bit is off, the key label may be shrunk only for X-direction. + // If both autoXScale and autoYScale bits are on, the key label text size may be auto scaled. 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; + private static final int LABEL_FLAGS_AUTO_Y_SCALE = 0x8000; + private static final int LABEL_FLAGS_AUTO_SCALE = LABEL_FLAGS_AUTO_X_SCALE + | LABEL_FLAGS_AUTO_Y_SCALE; + private static final int LABEL_FLAGS_PRESERVE_CASE = 0x10000; + private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x20000; + private static final int LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL = 0x40000; private static final int LABEL_FLAGS_DISABLE_HINT_LABEL = 0x40000000; private static final int LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS = 0x80000000; @@ -139,8 +137,6 @@ public class Key implements Comparable<Key> { private final OptionalAttributes mOptionalAttributes; - private static final int DEFAULT_TEXT_COLOR = 0xFFFFFFFF; - private static final class OptionalAttributes { /** Text to output when pressed. This can be multiple characters, like ".com" */ public final String mOutputText; @@ -185,22 +181,15 @@ public class Key implements Comparable<Key> { private boolean mEnabled = true; /** - * This constructor is being used only for keys in more keys keyboard. - */ - public Key(final KeyboardParams params, final MoreKeySpec moreKeySpec, final int x, final int y, - final int width, final int height, final int labelFlags) { - this(params, moreKeySpec.mLabel, null, moreKeySpec.mIconId, moreKeySpec.mCode, - moreKeySpec.mOutputText, x, y, width, height, labelFlags, BACKGROUND_TYPE_NORMAL); - } - - /** - * This constructor is being used only for key in popup suggestions pane. + * Constructor for a key on <code>MoreKeyKeyboard</code>, on <code>MoreSuggestions</code>, + * and in a <GridRows/>. */ - public Key(final KeyboardParams params, final String label, final String hintLabel, - final int iconId, final int code, final String outputText, final int x, final int y, - final int width, final int height, final int labelFlags, final int backgroundType) { - mHeight = height - params.mVerticalGap; - mWidth = width - params.mHorizontalGap; + public Key(final String label, final int iconId, final int code, final String outputText, + final String hintLabel, final int labelFlags, final int backgroundType, final int x, + final int y, final int width, final int height, final int horizontalGap, + final int verticalGap) { + mHeight = height - verticalGap; + mWidth = width - horizontalGap; mHintLabel = hintLabel; mLabelFlags = labelFlags; mBackgroundType = backgroundType; @@ -215,7 +204,7 @@ public class Key implements Comparable<Key> { mEnabled = (code != CODE_UNSPECIFIED); mIconId = iconId; // Horizontal gap is divided equally to both sides of the key. - mX = x + params.mHorizontalGap / 2; + mX = x + horizontalGap / 2; mY = y; mHitBox.set(x, y, x + width + 1, y + height); mKeyVisualAttributes = null; @@ -224,25 +213,22 @@ public class Key implements Comparable<Key> { } /** - * Create a key with the given top-left coordinate and extract its attributes from the XML - * parser. - * @param res resources associated with the caller's context + * Create a key with the given top-left coordinate and extract its attributes from a key + * specification string, Key attribute array, key style, and etc. + * + * @param keySpec the key specification. + * @param keyAttr the Key XML attributes array. + * @param keyStyle the {@link KeyStyle} of this key. * @param params the keyboard building parameters. * @param row the row that this key belongs to. row's x-coordinate will be the right edge of * this key. - * @param parser the XML parser containing the attributes for this key - * @throws XmlPullParserException */ - public Key(final Resources res, final KeyboardParams params, final KeyboardRow row, - final XmlPullParser parser) throws XmlPullParserException { + public Key(final String keySpec, final TypedArray keyAttr, final KeyStyle style, + final KeyboardParams params, final KeyboardRow row) { final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap; final int rowHeight = row.getRowHeight(); mHeight = rowHeight - params.mVerticalGap; - final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Key); - - final KeyStyle style = params.mKeyStyles.getKeyStyle(keyAttr, parser); final float keyXPos = row.getKeyX(keyAttr); final float keyWidth = row.getKeyWidth(keyAttr, keyXPos); final int keyYPos = row.getKeyY(); @@ -264,12 +250,6 @@ public class Key implements Comparable<Key> { R.styleable.Keyboard_Key_visualInsetsLeft, baseWidth, baseWidth, 0)); final int visualInsetsRight = Math.round(keyAttr.getFraction( R.styleable.Keyboard_Key_visualInsetsRight, baseWidth, baseWidth, 0)); - mIconId = KeySpecParser.getIconId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyIcon)); - final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyIconDisabled)); - final int previewIconId = KeySpecParser.getIconId(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyIconPreview)); mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags) | row.getDefaultKeyLabelFlags(); @@ -281,19 +261,19 @@ public class Key implements Comparable<Key> { int moreKeysColumn = style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn); int value; - if ((value = KeySpecParser.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) { + if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) { moreKeysColumn = value & MORE_KEYS_COLUMN_MASK; } - if ((value = KeySpecParser.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) { + if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) { moreKeysColumn = MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER | (value & MORE_KEYS_COLUMN_MASK); } - if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) { + if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) { moreKeysColumn |= MORE_KEYS_FLAGS_HAS_LABELS; } - if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) { + if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) { moreKeysColumn |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS; } - if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) { + if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) { moreKeysColumn |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY; } mMoreKeysColumnAndFlags = moreKeysColumn; @@ -305,21 +285,25 @@ public class Key implements Comparable<Key> { additionalMoreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys); } - moreKeys = KeySpecParser.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys); + moreKeys = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys); if (moreKeys != null) { actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS; mMoreKeys = new MoreKeySpec[moreKeys.length]; for (int i = 0; i < moreKeys.length; i++) { - mMoreKeys[i] = new MoreKeySpec( - moreKeys[i], needsToUpperCase, locale, params.mCodesSet); + mMoreKeys[i] = new MoreKeySpec(moreKeys[i], needsToUpperCase, locale); } } else { mMoreKeys = null; } mActionFlags = actionFlags; - final int code = KeySpecParser.parseCode(style.getString(keyAttr, - R.styleable.Keyboard_Key_code), params.mCodesSet, CODE_UNSPECIFIED); + mIconId = KeySpecParser.getIconId(keySpec); + final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr, + R.styleable.Keyboard_Key_keyIconDisabled)); + final int previewIconId = KeySpecParser.getIconId(style.getString(keyAttr, + R.styleable.Keyboard_Key_keyIconPreview)); + + final int code = KeySpecParser.getCode(keySpec); if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) { mLabel = params.mId.mCustomActionLabel; } else if (code >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { @@ -328,25 +312,24 @@ public class Key implements Comparable<Key> { // code point nor as a surrogate pair. mLabel = new StringBuilder().appendCodePoint(code).toString(); } else { - mLabel = KeySpecParser.toUpperCaseOfStringForLocale(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyLabel), needsToUpperCase, locale); + mLabel = StringUtils.toUpperCaseOfStringForLocale( + KeySpecParser.getLabel(keySpec), needsToUpperCase, locale); } if ((mLabelFlags & LABEL_FLAGS_DISABLE_HINT_LABEL) != 0) { mHintLabel = null; } else { - mHintLabel = KeySpecParser.toUpperCaseOfStringForLocale(style.getString(keyAttr, + mHintLabel = StringUtils.toUpperCaseOfStringForLocale(style.getString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel), needsToUpperCase, locale); } - String outputText = KeySpecParser.toUpperCaseOfStringForLocale(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyOutputText), needsToUpperCase, locale); + String outputText = StringUtils.toUpperCaseOfStringForLocale( + KeySpecParser.getOutputText(keySpec), needsToUpperCase, locale); // Choose the first letter of the label as primary code if not specified. if (code == CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) && !TextUtils.isEmpty(mLabel)) { if (StringUtils.codePointCount(mLabel) == 1) { // Use the first letter of the hint label if shiftedLetterActivated flag is // specified. - if (hasShiftedLetterHint() && isShiftedLetterActivated() - && !TextUtils.isEmpty(mHintLabel)) { + if (hasShiftedLetterHint() && isShiftedLetterActivated()) { mCode = mHintLabel.codePointAt(0); } else { mCode = mLabel.codePointAt(0); @@ -365,24 +348,20 @@ public class Key implements Comparable<Key> { mCode = CODE_OUTPUT_TEXT; } } else { - mCode = KeySpecParser.toUpperCaseOfCodeForLocale(code, needsToUpperCase, locale); + mCode = StringUtils.toUpperCaseOfCodeForLocale(code, needsToUpperCase, locale); } - final int altCode = KeySpecParser.toUpperCaseOfCodeForLocale( - KeySpecParser.parseCode(style.getString(keyAttr, - R.styleable.Keyboard_Key_altCode), params.mCodesSet, CODE_UNSPECIFIED), - needsToUpperCase, locale); + final int altCodeInAttr = KeySpecParser.parseCode( + style.getString(keyAttr, R.styleable.Keyboard_Key_altCode), CODE_UNSPECIFIED); + final int altCode = StringUtils.toUpperCaseOfCodeForLocale( + altCodeInAttr, needsToUpperCase, locale); mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode, disabledIconId, previewIconId, visualInsetsLeft, visualInsetsRight); mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr); - keyAttr.recycle(); mHashCode = computeHashCode(this); - if (hasShiftedLetterHint() && TextUtils.isEmpty(mHintLabel)) { - Log.w(TAG, "hasShiftedLetterHint specified without keyHintLabel: " + this); - } } /** - * Copy constructor. + * Copy constructor for DynamicGridKeyboard.GridKey. * * @param key the original key. */ @@ -604,22 +583,7 @@ public class Key implements Comparable<Key> { } public final int selectTextColor(final KeyDrawParams params) { - if (isShiftedLetterActivated()) { - return params.mTextInactivatedColor; - } - if (params.mTextColorStateList == null) { - return DEFAULT_TEXT_COLOR; - } - final int[] state; - // TODO: Hack!!!!!!!! Consider having a new attribute for the functional text labels. - // Currently, we distinguish "input key" from "functional key" by checking the - // length of the label( > 1) and "functional" attributes (= true). - if (mLabel != null && mLabel.length() > 1) { - state = getCurrentDrawableState(); - } else { - state = KEY_STATE_NORMAL; - } - return params.mTextColorStateList.getColorForState(state, DEFAULT_TEXT_COLOR); + return isShiftedLetterActivated() ? params.mTextInactivatedColor : params.mTextColor; } public final int selectHintTextSize(final KeyDrawParams params) { @@ -687,7 +651,8 @@ public class Key implements Comparable<Key> { } public final boolean hasShiftedLetterHint() { - return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0; + return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0 + && !TextUtils.isEmpty(mHintLabel); } public final boolean hasHintLabel() { @@ -702,12 +667,17 @@ public class Key implements Comparable<Key> { return (mLabelFlags & LABEL_FLAGS_WITH_ICON_RIGHT) != 0; } - public final boolean needsXScale() { + public final boolean needsAutoXScale() { return (mLabelFlags & LABEL_FLAGS_AUTO_X_SCALE) != 0; } - public final boolean isShiftedLetterActivated() { - return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0; + public final boolean needsAutoScale() { + return (mLabelFlags & LABEL_FLAGS_AUTO_SCALE) == LABEL_FLAGS_AUTO_SCALE; + } + + private final boolean isShiftedLetterActivated() { + return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0 + && !TextUtils.isEmpty(mHintLabel); } public final int getMoreKeysColumn() { @@ -746,10 +716,14 @@ public class Key implements Comparable<Key> { return (attrs != null) ? attrs.mAltCode : CODE_UNSPECIFIED; } + public int getIconId() { + return mIconId; + } + public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) { final OptionalAttributes attrs = mOptionalAttributes; final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED; - final int iconId = mEnabled ? mIconId : disabledIconId; + final int iconId = mEnabled ? getIconId() : disabledIconId; final Drawable icon = iconSet.getIconDrawable(iconId); if (icon != null) { icon.setAlpha(alpha); @@ -761,7 +735,7 @@ public class Key implements Comparable<Key> { final OptionalAttributes attrs = mOptionalAttributes; final int previewIconId = (attrs != null) ? attrs.mPreviewIconId : ICON_UNDEFINED; return previewIconId != ICON_UNDEFINED - ? iconSet.getIconDrawable(previewIconId) : iconSet.getIconDrawable(mIconId); + ? iconSet.getIconDrawable(previewIconId) : iconSet.getIconDrawable(getIconId()); } public int getWidth() { @@ -928,9 +902,9 @@ public class Key implements Comparable<Key> { } public static class Spacer extends Key { - public Spacer(final Resources res, final KeyboardParams params, final KeyboardRow row, - final XmlPullParser parser) throws XmlPullParserException { - super(res, params, row, parser); + public Spacer(final TypedArray keyAttr, final KeyStyle keyStyle, + final KeyboardParams params, final KeyboardRow row) { + super(null /* keySpec */, keyAttr, keyStyle, params, row); } /** @@ -938,8 +912,9 @@ public class Key implements Comparable<Key> { */ protected Spacer(final KeyboardParams params, final int x, final int y, final int width, final int height) { - super(params, null, null, ICON_UNDEFINED, CODE_UNSPECIFIED, - null, x, y, width, height, 0, BACKGROUND_TYPE_EMPTY); + super(null /* label */, ICON_UNDEFINED, CODE_UNSPECIFIED, null /* outputText */, + null /* hintLabel */, 0 /* labelFlags */, BACKGROUND_TYPE_EMPTY, x, y, width, + height, params.mHorizontalGap, params.mVerticalGap); } } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index befb6fa92..87368d4ef 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -16,9 +16,9 @@ package com.android.inputmethod.keyboard; -import com.android.inputmethod.latin.Constants; - - +/** + * This class handles key detection. + */ public class KeyDetector { private final int mKeyHysteresisDistanceSquared; private final int mKeyHysteresisDistanceForSlidingModifierSquared; @@ -27,31 +27,27 @@ public class KeyDetector { private int mCorrectionX; private int mCorrectionY; - /** - * This class handles key detection. - * - * @param keyHysteresisDistance if the pointer movement distance is smaller than this, the - * movement will not be handled as meaningful movement. The unit is pixel. - */ - public KeyDetector(float keyHysteresisDistance) { - this(keyHysteresisDistance, keyHysteresisDistance); + public KeyDetector() { + this(0.0f /* keyHysteresisDistance */, 0.0f /* keyHysteresisDistanceForSlidingModifier */); } /** - * This class handles key detection. + * Key detection object constructor with key hysteresis distances. * * @param keyHysteresisDistance if the pointer movement distance is smaller than this, the * movement will not be handled as meaningful movement. The unit is pixel. * @param keyHysteresisDistanceForSlidingModifier the same parameter for sliding input that * starts from a modifier key such as shift and symbols key. */ - public KeyDetector(float keyHysteresisDistance, float keyHysteresisDistanceForSlidingModifier) { + public KeyDetector(final float keyHysteresisDistance, + final float keyHysteresisDistanceForSlidingModifier) { mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); mKeyHysteresisDistanceForSlidingModifierSquared = (int)( keyHysteresisDistanceForSlidingModifier * keyHysteresisDistanceForSlidingModifier); } - public void setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { + public void setKeyboard(final Keyboard keyboard, final float correctionX, + final float correctionY) { if (keyboard == null) { throw new NullPointerException(); } @@ -60,28 +56,25 @@ public class KeyDetector { mKeyboard = keyboard; } - public int getKeyHysteresisDistanceSquared(boolean isSlidingFromModifier) { + public int getKeyHysteresisDistanceSquared(final boolean isSlidingFromModifier) { return isSlidingFromModifier ? mKeyHysteresisDistanceForSlidingModifierSquared : mKeyHysteresisDistanceSquared; } - public int getTouchX(int x) { + public int getTouchX(final int x) { return x + mCorrectionX; } // TODO: Remove vertical correction. - public int getTouchY(int y) { + public int getTouchY(final int y) { return y + mCorrectionY; } public Keyboard getKeyboard() { - if (mKeyboard == null) { - throw new IllegalStateException("keyboard isn't set"); - } return mKeyboard; } - public boolean alwaysAllowsSlidingInput() { + public boolean alwaysAllowsKeySelectionByDraggingFinger() { return false; } @@ -92,7 +85,10 @@ public class KeyDetector { * @param y The y-coordinate of a touch point * @return the key that the touch point hits. */ - public Key detectHitKey(int x, int y) { + public Key detectHitKey(final int x, final int y) { + if (mKeyboard == null) { + return null; + } final int touchX = getTouchX(x); final int touchY = getTouchY(y); @@ -117,20 +113,4 @@ public class KeyDetector { } return primaryKey; } - - public static String printableCode(Key key) { - return key != null ? Constants.printableCode(key.getCode()) : "none"; - } - - public static String printableCodes(int[] codes) { - final StringBuilder sb = new StringBuilder(); - boolean addDelimiter = false; - for (final int code : codes) { - if (code == Constants.NOT_A_CODE) break; - if (addDelimiter) sb.append(", "); - sb.append(Constants.printableCode(code)); - addDelimiter = true; - } - return "[" + sb + "]"; - } } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index bc1383aff..f646a03c2 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -23,6 +23,10 @@ import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; + +import java.util.Collections; +import java.util.List; /** * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard @@ -73,10 +77,10 @@ public class Keyboard { /** Maximum column for more keys keyboard */ public final int mMaxMoreKeysKeyboardColumn; - /** Array of keys and icons in this keyboard */ - private final Key[] mKeys; - public final Key[] mShiftKeys; - public final Key[] mAltCodeKeysWhileTyping; + /** List of keys in this keyboard */ + private final List<Key> mSortedKeys; + public final List<Key> mShiftKeys; + public final List<Key> mAltCodeKeysWhileTyping; public final KeyboardIconsSet mIconsSet; private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray(); @@ -99,15 +103,16 @@ public class Keyboard { mTopPadding = params.mTopPadding; mVerticalGap = params.mVerticalGap; - mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]); - mShiftKeys = params.mShiftKeys.toArray(new Key[params.mShiftKeys.size()]); - mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray( - new Key[params.mAltCodeKeysWhileTyping.size()]); + mSortedKeys = Collections.unmodifiableList( + CollectionUtils.newArrayList(params.mSortedKeys)); + mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); + mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping); mIconsSet = params.mIconsSet; mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); + mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys, + params.mTouchPositionCorrection); mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; } @@ -126,7 +131,7 @@ public class Keyboard { mTopPadding = keyboard.mTopPadding; mVerticalGap = keyboard.mVerticalGap; - mKeys = keyboard.mKeys; + mSortedKeys = keyboard.mSortedKeys; mShiftKeys = keyboard.mShiftKeys; mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping; mIconsSet = keyboard.mIconsSet; @@ -151,17 +156,14 @@ public class Keyboard { return mProximityInfo; } - public Key[] getKeys() { - return mKeys; - } - - public Key getKeyFromOutputText(final String outputText) { - for (final Key key : getKeys()) { - if (outputText.equals(key.getOutputText())) { - return key; - } - } - return null; + /** + * Return the sorted list of keys of this keyboard. + * The keys are sorted from top-left to bottom-right order. + * The list may contain {@link Spacer} object as well. + * @return the sorted unmodifiable list of {@link Key}s of this keyboard. + */ + public List<Key> getSortedKeys() { + return mSortedKeys; } public Key getKey(final int code) { @@ -174,7 +176,7 @@ public class Keyboard { return mKeyCache.valueAt(index); } - for (final Key key : getKeys()) { + for (final Key key : getSortedKeys()) { if (key.getCode() == code) { mKeyCache.put(code, key); return key; @@ -190,7 +192,7 @@ public class Keyboard { return true; } - for (final Key key : getKeys()) { + for (final Key key : getSortedKeys()) { if (key == aKey) { mKeyCache.put(key.getCode(), key); return true; @@ -208,13 +210,29 @@ public class Keyboard { * 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 the nearest keys to the given point. If the given + * @return the list 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 Key[] getNearestKeys(final int x, final int y) { + public List<Key> getNearestKeys(final int x, final 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 int[] getCoordinates(final int[] codePoints) { + final int length = codePoints.length; + final int[] coordinates = CoordinateUtils.newCoordinateArray(length); + for (int i = 0; i < length; ++i) { + final Key key = getKey(codePoints[i]); + if (null != key) { + CoordinateUtils.setXYInArray(coordinates, i, + key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2); + } else { + CoordinateUtils.setXYInArray(coordinates, i, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } + } + return coordinates; + } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index dc760e685..c565866b7 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -53,8 +53,10 @@ public interface KeyboardActionListener { * {@link PointerTracker} or so, the value should be * {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the * suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}. + * @param isKeyRepeat true if this is a key repeat, false otherwise */ - public void onCodeInput(int primaryCode, int x, int y); + // TODO: change this to send an Event object instead + public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat); /** * Sends a string of characters to the listener. @@ -107,7 +109,7 @@ public interface KeyboardActionListener { @Override public void onReleaseKey(int primaryCode, boolean withSliding) {} @Override - public void onCodeInput(int primaryCode, int x, int y) {} + public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat) {} @Override public void onTextInput(String text) {} @Override diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 736f13ed6..93a55fe6a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -68,10 +68,9 @@ public final class KeyboardId { public final int mHeight; public final int mMode; public final int mElementId; - private final EditorInfo mEditorInfo; + public final EditorInfo mEditorInfo; public final boolean mClobberSettingsKey; - public final boolean mShortcutKeyEnabled; - public final boolean mShortcutKeyOnSymbols; + public final boolean mSupportsSwitchingToShortcutIme; public final boolean mLanguageSwitchKeyEnabled; public final String mCustomActionLabel; public final boolean mHasShortcutKey; @@ -87,17 +86,11 @@ public final class KeyboardId { mElementId = elementId; mEditorInfo = params.mEditorInfo; mClobberSettingsKey = params.mNoSettingsKey; - mShortcutKeyEnabled = params.mVoiceKeyEnabled; - mShortcutKeyOnSymbols = mShortcutKeyEnabled && !params.mVoiceKeyOnMain; + mSupportsSwitchingToShortcutIme = params.mSupportsSwitchingToShortcutIme; mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled; mCustomActionLabel = (mEditorInfo.actionLabel != null) ? mEditorInfo.actionLabel.toString() : null; - final boolean alphabetMayHaveShortcutKey = isAlphabetKeyboard(elementId) - && !mShortcutKeyOnSymbols; - final boolean symbolsMayHaveShortcutKey = (elementId == KeyboardId.ELEMENT_SYMBOLS) - && mShortcutKeyOnSymbols; - mHasShortcutKey = mShortcutKeyEnabled - && (alphabetMayHaveShortcutKey || symbolsMayHaveShortcutKey); + mHasShortcutKey = mSupportsSwitchingToShortcutIme && params.mShowsVoiceInputKey; mHashCode = computeHashCode(this); } @@ -110,8 +103,8 @@ public final class KeyboardId { id.mHeight, id.passwordInput(), id.mClobberSettingsKey, - id.mShortcutKeyEnabled, - id.mShortcutKeyOnSymbols, + id.mSupportsSwitchingToShortcutIme, + id.mHasShortcutKey, id.mLanguageSwitchKeyEnabled, id.isMultiLine(), id.imeAction(), @@ -131,8 +124,8 @@ public final class KeyboardId { && other.mHeight == mHeight && other.passwordInput() == passwordInput() && other.mClobberSettingsKey == mClobberSettingsKey - && other.mShortcutKeyEnabled == mShortcutKeyEnabled - && other.mShortcutKeyOnSymbols == mShortcutKeyOnSymbols + && other.mSupportsSwitchingToShortcutIme == mSupportsSwitchingToShortcutIme + && other.mHasShortcutKey == mHasShortcutKey && other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled && other.isMultiLine() == isMultiLine() && other.imeAction() == imeAction() @@ -186,21 +179,20 @@ public final class KeyboardId { @Override public String toString() { - return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s %s%s%s%s%s%s%s%s%s]", + return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), mWidth, mHeight, modeName(mMode), - imeAction(), - (navigateNext() ? "navigateNext" : ""), - (navigatePrevious() ? "navigatePrevious" : ""), + actionName(imeAction()), + (navigateNext() ? " navigateNext" : ""), + (navigatePrevious() ? " navigatePrevious" : ""), (mClobberSettingsKey ? " clobberSettingsKey" : ""), (passwordInput() ? " passwordInput" : ""), - (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), - (mShortcutKeyOnSymbols ? " shortcutKeyOnSymbols" : ""), + (mSupportsSwitchingToShortcutIme ? " supportsSwitchingToShortcutIme" : ""), (mHasShortcutKey ? " hasShortcutKey" : ""), (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), - (isMultiLine() ? "isMultiLine" : "") + (isMultiLine() ? " isMultiLine" : "") ); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index 1eccdf341..cde5091c4 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -20,7 +20,6 @@ import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; import static com.android.inputmethod.latin.Constants.ImeOption.NO_SETTINGS_KEY; -import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE; import android.content.Context; import android.content.res.Resources; @@ -34,6 +33,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeysCache; @@ -105,10 +105,10 @@ public final class KeyboardLayoutSet { int mMode; EditorInfo mEditorInfo; boolean mDisableTouchPositionCorrectionDataForTest; - boolean mVoiceKeyEnabled; - // TODO: Remove mVoiceKeyOnMain when it's certainly confirmed that we no longer show - // the voice input key on the symbol layout - boolean mVoiceKeyOnMain; + boolean mIsPasswordField; + boolean mSupportsSwitchingToShortcutIme; + boolean mShowsVoiceInputKey; + boolean mNoMicrophoneKey; boolean mNoSettingsKey; boolean mLanguageSwitchKeyEnabled; InputMethodSubtype mSubtype; @@ -221,16 +221,24 @@ public final class KeyboardLayoutSet { private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo(); - public Builder(final Context context, final EditorInfo editorInfo) { + public Builder(final Context context, final EditorInfo ei) { mContext = context; mPackageName = context.getPackageName(); mResources = context.getResources(); final Params params = mParams; + final EditorInfo editorInfo = (ei != null) ? ei : EMPTY_EDITOR_INFO; params.mMode = getKeyboardMode(editorInfo); - params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; + params.mEditorInfo = editorInfo; + params.mIsPasswordField = InputTypeUtils.isPasswordInputType(editorInfo.inputType); + @SuppressWarnings("deprecation") + final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions( + null, NO_MICROPHONE_COMPAT, editorInfo); + params.mNoMicrophoneKey = InputAttributes.inPrivateImeOptions( + mPackageName, NO_MICROPHONE, editorInfo) + || deprecatedNoMicrophone; params.mNoSettingsKey = InputAttributes.inPrivateImeOptions( - mPackageName, NO_SETTINGS_KEY, params.mEditorInfo); + mPackageName, NO_SETTINGS_KEY, editorInfo); } public Builder setKeyboardGeometry(final int keyboardWidth, final int keyboardHeight) { @@ -240,7 +248,7 @@ public final class KeyboardLayoutSet { } public Builder setSubtype(final InputMethodSubtype subtype) { - final boolean asciiCapable = subtype.containsExtraValueKey(ASCII_CAPABLE); + final boolean asciiCapable = InputMethodSubtypeCompatUtils.isAsciiCapable(subtype); @SuppressWarnings("deprecation") final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions( mPackageName, FORCE_ASCII, mParams.mEditorInfo); @@ -261,18 +269,11 @@ public final class KeyboardLayoutSet { return this; } - // TODO: Remove mVoiceKeyOnMain when it's certainly confirmed that we no longer show - // the voice input key on the symbol layout - public Builder setOptions(final boolean voiceKeyEnabled, final boolean voiceKeyOnMain, - final boolean languageSwitchKeyEnabled) { - @SuppressWarnings("deprecation") - final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions( - null, NO_MICROPHONE_COMPAT, mParams.mEditorInfo); - final boolean noMicrophone = InputAttributes.inPrivateImeOptions( - mPackageName, NO_MICROPHONE, mParams.mEditorInfo) - || deprecatedNoMicrophone; - mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; - mParams.mVoiceKeyOnMain = voiceKeyOnMain; + public Builder setOptions(final boolean isShortcutImeEnabled, + final boolean showsVoiceInputKey, final boolean languageSwitchKeyEnabled) { + mParams.mSupportsSwitchingToShortcutIme = + isShortcutImeEnabled && !mParams.mNoMicrophoneKey && !mParams.mIsPasswordField; + mParams.mShowsVoiceInputKey = showsVoiceInputKey; mParams.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; return this; } @@ -368,9 +369,6 @@ public final class KeyboardLayoutSet { } private static int getKeyboardMode(final EditorInfo editorInfo) { - if (editorInfo == null) - return KeyboardId.MODE_TEXT; - final int inputType = editorInfo.inputType; final int variation = inputType & InputType.TYPE_MASK_VARIATION; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 5abc9ab38..0e667bc1c 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -30,6 +30,7 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; import com.android.inputmethod.keyboard.internal.KeyboardState; +import com.android.inputmethod.keyboard.internal.KeyboardTextsSet; import com.android.inputmethod.latin.InputView; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; @@ -37,35 +38,12 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.WordComposer; -import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.utils.ResourceUtils; public final class KeyboardSwitcher implements KeyboardState.SwitchActions { private static final String TAG = KeyboardSwitcher.class.getSimpleName(); - static final class KeyboardTheme { - public final int mThemeId; - public final int mStyleId; - - // Note: The themeId should be aligned with "themeId" attribute of Keyboard style - // in values/style.xml. - public KeyboardTheme(final int themeId, final int styleId) { - mThemeId = themeId; - mStyleId = styleId; - } - } - - public static final int THEME_INDEX_ICS = 0; - public static final int THEME_INDEX_GB = 1; - public static final int THEME_INDEX_KLP = 2; - public static final int THEME_INDEX_DEFAULT = THEME_INDEX_KLP; - public static final KeyboardTheme[] KEYBOARD_THEMES = { - new KeyboardTheme(THEME_INDEX_ICS, R.style.KeyboardTheme_ICS), - new KeyboardTheme(THEME_INDEX_GB, R.style.KeyboardTheme_GB), - new KeyboardTheme(THEME_INDEX_KLP, R.style.KeyboardTheme_KLP), - }; - private SubtypeSwitcher mSubtypeSwitcher; private SharedPreferences mPrefs; @@ -74,18 +52,20 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { private MainKeyboardView mKeyboardView; private EmojiPalettesView mEmojiPalettesView; private LatinIME mLatinIME; - private Resources mResources; private boolean mIsHardwareAcceleratedDrawingEnabled; private KeyboardState mState; private KeyboardLayoutSet mKeyboardLayoutSet; + // TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}. + private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet(); + private SettingsValues mCurrentSettingsValues; /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of * what user actually typed. */ private boolean mIsAutoCorrectionActive; - private KeyboardTheme mKeyboardTheme = KEYBOARD_THEMES[THEME_INDEX_DEFAULT]; + private KeyboardTheme mKeyboardTheme = KeyboardTheme.getDefaultKeyboardTheme(); private Context mThemeContext; private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); @@ -105,7 +85,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) { mLatinIME = latinIme; - mResources = latinIme.getResources(); mPrefs = prefs; mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mState = new KeyboardState(this); @@ -115,25 +94,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { public void updateKeyboardTheme() { final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper( - mLatinIME, getKeyboardTheme(mLatinIME, mPrefs)); + mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs)); if (themeUpdated && mKeyboardView != null) { mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled)); } } - private static KeyboardTheme getKeyboardTheme(final Context context, - final SharedPreferences prefs) { - final Resources res = context.getResources(); - final int index = Settings.readKeyboardThemeIndex(prefs, res); - if (index >= 0 && index < KEYBOARD_THEMES.length) { - return KEYBOARD_THEMES[index]; - } - final int defaultThemeIndex = Settings.resetAndGetDefaultKeyboardThemeIndex(prefs, res); - Log.w(TAG, "Illegal keyboard theme in preference: " + index + ", default to " - + defaultThemeIndex); - return KEYBOARD_THEMES[defaultThemeIndex]; - } - private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme) { if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) { @@ -145,7 +111,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { return false; } - public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues) { + public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues, + final int currentAutoCapsState, final int currentRecapitalizeState) { final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( mThemeContext, editorInfo); final Resources res = mThemeContext.getResources(); @@ -154,12 +121,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { builder.setKeyboardGeometry(keyboardWidth, keyboardHeight); builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype()); builder.setOptions( - settingsValues.isVoiceKeyEnabled(editorInfo), - true /* always show a voice key on the main keyboard */, - settingsValues.isLanguageSwitchKeyEnabled()); + mSubtypeSwitcher.isShortcutImeEnabled(), + settingsValues.mShowsVoiceInputKey, + mLatinIME.shouldShowLanguageSwitchKey()); mKeyboardLayoutSet = builder.build(); + mCurrentSettingsValues = settingsValues; try { - mState.onLoadKeyboard(); + mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); + mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); @@ -187,18 +156,25 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { final MainKeyboardView keyboardView = mKeyboardView; final Keyboard oldKeyboard = keyboardView.getKeyboard(); keyboardView.setKeyboard(keyboard); - mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); + mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding); keyboardView.setKeyPreviewPopupEnabled( - Settings.readKeyPreviewPopupEnabled(mPrefs, mResources), - Settings.readKeyPreviewPopupDismissDelay(mPrefs, mResources)); + mCurrentSettingsValues.mKeyPreviewPopupOn, + mCurrentSettingsValues.mKeyPreviewPopupDismissDelay); + keyboardView.setKeyPreviewAnimationParams( + mCurrentSettingsValues.mKeyPreviewShowUpStartScale, + mCurrentSettingsValues.mKeyPreviewShowUpDuration, + mCurrentSettingsValues.mKeyPreviewDismissEndScale, + mCurrentSettingsValues.mKeyPreviewDismissDuration); keyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); - final boolean needsToDisplayLanguage = mSubtypeSwitcher.needsToDisplayLanguage( - keyboard.mId.mLocale); - keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, needsToDisplayLanguage, - RichInputMethodManager.getInstance().hasMultipleEnabledIMEsOrSubtypes(true)); + final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType( + keyboard.mId.mSubtype); + final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance() + .hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */); + keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType, + hasMultipleEnabledIMEsOrSubtypes); } public Keyboard getKeyboard() { @@ -208,30 +184,26 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { return null; } - /** - * Update keyboard shift state triggered by connected EditText status change. - */ - public void updateShiftState() { - mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState(), - mLatinIME.getCurrentRecapitalizeState()); - } - // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). - public void resetKeyboardStateToAlphabet() { - mState.onResetKeyboardStateToAlphabet(); + public void resetKeyboardStateToAlphabet(final int currentAutoCapsState, + final int currentRecapitalizeState) { + mState.onResetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState); } - public void onPressKey(final int code, final boolean isSinglePointer) { - mState.onPressKey(code, isSinglePointer, mLatinIME.getCurrentAutoCapsState()); + public void onPressKey(final int code, final boolean isSinglePointer, + final int currentAutoCapsState, final int currentRecapitalizeState) { + mState.onPressKey(code, isSinglePointer, currentAutoCapsState, currentRecapitalizeState); } - public void onReleaseKey(final int code, final boolean withSliding) { - mState.onReleaseKey(code, withSliding); + public void onReleaseKey(final int code, final boolean withSliding, + final int currentAutoCapsState, final int currentRecapitalizeState) { + mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState); } - public void onFinishSlidingInput() { - mState.onFinishSlidingInput(); + public void onFinishSlidingInput(final int currentAutoCapsState, + final int currentRecapitalizeState) { + mState.onFinishSlidingInput(currentAutoCapsState, currentRecapitalizeState); } // Implements {@link KeyboardState.SwitchActions}. @@ -280,7 +252,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { @Override public void setEmojiKeyboard() { mMainKeyboardFrame.setVisibility(View.GONE); - mEmojiPalettesView.startEmojiPalettes(); + mEmojiPalettesView.startEmojiPalettes( + mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), + mKeyboardView.getKeyVisualAttribute()); mEmojiPalettesView.setVisibility(View.VISIBLE); } @@ -290,11 +264,10 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); } - // Implements {@link KeyboardState.SwitchActions}. - @Override - public void requestUpdatingShiftState() { - mState.onUpdateShiftState(mLatinIME.getCurrentAutoCapsState(), - mLatinIME.getCurrentRecapitalizeState()); + // Future method for requesting an updating to the shift state. + public void requestUpdatingShiftState(final int currentAutoCapsState, + final int currentRecapitalizeState) { + mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); } // Implements {@link KeyboardState.SwitchActions}. @@ -325,12 +298,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { /** * Updates state machine to figure out when to automatically switch back to the previous mode. */ - public void onCodeInput(final int code) { - mState.onCodeInput(code, mLatinIME.getCurrentAutoCapsState()); - } - - private boolean isShowingMainKeyboard() { - return null != mKeyboardView && mKeyboardView.isShown(); + public void onCodeInput(final int code, final int currentAutoCapsState, + final int currentRecapitalizeState) { + mState.onCodeInput(code, currentAutoCapsState, currentRecapitalizeState); } public boolean isShowingEmojiPalettes() { @@ -365,10 +335,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } } - public boolean isShowingMainKeyboardOrEmojiPalettes() { - return isShowingMainKeyboard() || isShowingEmojiPalettes(); - } - public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { if (mKeyboardView != null) { mKeyboardView.closing(); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java new file mode 100644 index 000000000..4db72ad4d --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 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.SharedPreferences; +import android.util.Log; + +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.settings.Settings; + +public final class KeyboardTheme { + private static final String TAG = KeyboardTheme.class.getSimpleName(); + + public static final int THEME_ID_ICS = 0; + public static final int THEME_ID_KLP = 2; + private static final int DEFAULT_THEME_ID = THEME_ID_KLP; + + private static final KeyboardTheme[] KEYBOARD_THEMES = { + new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS), + new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP), + }; + + public final int mThemeId; + public final int mStyleId; + + // Note: The themeId should be aligned with "themeId" attribute of Keyboard style + // in values/style.xml. + public KeyboardTheme(final int themeId, final int styleId) { + mThemeId = themeId; + mStyleId = styleId; + } + + private static KeyboardTheme searchKeyboardTheme(final int themeId) { + // TODO: This search algorithm isn't optimal if there are many themes. + for (final KeyboardTheme theme : KEYBOARD_THEMES) { + if (theme.mThemeId == themeId) { + return theme; + } + } + return null; + } + + public static KeyboardTheme getDefaultKeyboardTheme() { + return searchKeyboardTheme(DEFAULT_THEME_ID); + } + + public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) { + final String themeIdString = prefs.getString(Settings.PREF_KEYBOARD_LAYOUT, null); + if (themeIdString == null) { + return getDefaultKeyboardTheme(); + } + try { + final int themeId = Integer.parseInt(themeIdString); + final KeyboardTheme theme = searchKeyboardTheme(themeId); + if (theme != null) { + return theme; + } + Log.w(TAG, "Unknown keyboard theme in preference: " + themeIdString); + } catch (final NumberFormatException e) { + Log.w(TAG, "Illegal keyboard theme in preference: " + themeIdString); + } + // Reset preference to default value. + final String defaultThemeIdString = Integer.toString(DEFAULT_THEME_ID); + prefs.edit().putString(Settings.PREF_KEYBOARD_LAYOUT, defaultThemeIdString).apply(); + return getDefaultKeyboardTheme(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 5578713a0..8ca00b005 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -113,9 +113,6 @@ public class KeyboardView extends View { private final Canvas mOffscreenCanvas = new Canvas(); private final Paint mPaint = new Paint(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); - private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' }; - private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' }; - public KeyboardView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.keyboardViewStyle); } @@ -149,6 +146,10 @@ public class KeyboardView extends View { mPaint.setAntiAlias(true); } + public KeyVisualAttributes getKeyVisualAttribute() { + return mKeyVisualAttributes; + } + private static void blendAlpha(final Paint paint, final int alpha) { final int color = paint.getColor(); paint.setARGB((paint.getAlpha() * alpha) / Constants.Color.ALPHA_OPAQUE, @@ -288,7 +289,7 @@ public class KeyboardView extends View { // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. if (drawAllKeys || isHardwareAccelerated) { // Draw all keys. - for (final Key key : mKeyboard.getKeys()) { + for (final Key key : mKeyboard.getSortedKeys()) { onDrawKey(key, canvas, paint); } } else { @@ -322,7 +323,7 @@ public class KeyboardView extends View { params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE; if (!key.isSpacer()) { - onDrawKeyBackground(key, canvas); + onDrawKeyBackground(key, canvas, mKeyBackground); } onDrawKeyTopVisuals(key, canvas, paint, params); @@ -330,14 +331,14 @@ public class KeyboardView extends View { } // Draw key background. - protected void onDrawKeyBackground(final Key key, final Canvas canvas) { + protected void onDrawKeyBackground(final Key key, final Canvas canvas, + final Drawable background) { final Rect padding = mKeyBackgroundPadding; final int bgWidth = key.getDrawWidth() + padding.left + padding.right; final int bgHeight = key.getHeight() + padding.top + padding.bottom; final int bgX = -padding.left; final int bgY = -padding.top; final int[] drawableState = key.getCurrentDrawableState(); - final Drawable background = mKeyBackground; background.setState(drawableState); final Rect bounds = background.getBounds(); if (bgWidth != bounds.right || bgHeight != bounds.bottom) { @@ -370,10 +371,8 @@ public class KeyboardView extends View { if (label != null) { paint.setTypeface(key.selectTypeface(params)); paint.setTextSize(key.selectTextSize(params)); - final float labelCharHeight = TypefaceUtils.getCharHeight( - KEY_LABEL_REFERENCE_CHAR, paint); - final float labelCharWidth = TypefaceUtils.getCharWidth( - KEY_LABEL_REFERENCE_CHAR, paint); + final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint); + final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint); // Vertical label text alignment. final float baseline = centerY + labelCharHeight / 2.0f; @@ -391,12 +390,12 @@ public class KeyboardView extends View { positionX = centerX - labelCharWidth * 7.0f / 4.0f; paint.setTextAlign(Align.LEFT); } else if (key.hasLabelWithIconLeft() && icon != null) { - labelWidth = TypefaceUtils.getLabelWidth(label, paint) + icon.getIntrinsicWidth() + labelWidth = TypefaceUtils.getStringWidth(label, paint) + icon.getIntrinsicWidth() + LABEL_ICON_MARGIN * keyWidth; positionX = centerX + labelWidth / 2.0f; paint.setTextAlign(Align.RIGHT); } else if (key.hasLabelWithIconRight() && icon != null) { - labelWidth = TypefaceUtils.getLabelWidth(label, paint) + icon.getIntrinsicWidth() + labelWidth = TypefaceUtils.getStringWidth(label, paint) + icon.getIntrinsicWidth() + LABEL_ICON_MARGIN * keyWidth; positionX = centerX - labelWidth / 2.0f; paint.setTextAlign(Align.LEFT); @@ -404,9 +403,15 @@ public class KeyboardView extends View { positionX = centerX; paint.setTextAlign(Align.CENTER); } - if (key.needsXScale()) { - paint.setTextScaleX(Math.min(1.0f, - (keyWidth * MAX_LABEL_RATIO) / TypefaceUtils.getLabelWidth(label, paint))); + if (key.needsAutoXScale()) { + final float ratio = Math.min(1.0f, (keyWidth * MAX_LABEL_RATIO) / + TypefaceUtils.getStringWidth(label, paint)); + if (key.needsAutoScale()) { + final float autoSize = paint.getTextSize() * ratio; + paint.setTextSize(autoSize); + } else { + paint.setTextScaleX(ratio); + } } paint.setColor(key.selectTextColor(params)); @@ -451,36 +456,35 @@ public class KeyboardView extends View { // TODO: Should add a way to specify type face for hint letters paint.setTypeface(Typeface.DEFAULT_BOLD); blendAlpha(paint, params.mAnimAlpha); + final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint); + final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint); + final KeyVisualAttributes visualAttr = key.getVisualAttributes(); + final float adjustmentY = (visualAttr == null) ? 0.0f + : visualAttr.mHintLabelVerticalAdjustment * labelCharHeight; final float hintX, hintY; if (key.hasHintLabel()) { // The hint label is placed just right of the key label. Used mainly on // "phone number" layout. // TODO: Generalize the following calculations. - hintX = positionX - + TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2.0f; - hintY = centerY - + TypefaceUtils.getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f; + hintX = positionX + labelCharWidth * 2.0f; + hintY = centerY + labelCharHeight / 2.0f; paint.setTextAlign(Align.LEFT); } else if (key.hasShiftedLetterHint()) { // The hint label is placed at top-right corner of the key. Used mainly on tablet. - hintX = keyWidth - mKeyShiftedLetterHintPadding - - TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f; + hintX = keyWidth - mKeyShiftedLetterHintPadding - labelCharWidth / 2.0f; paint.getFontMetrics(mFontMetrics); hintY = -mFontMetrics.top; paint.setTextAlign(Align.CENTER); } else { // key.hasHintLetter() // The hint letter is placed at top-right corner of the key. Used mainly on phone. - final float keyNumericHintLabelReferenceCharWidth = - TypefaceUtils.getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint); - final float keyHintLabelStringWidth = - TypefaceUtils.getStringWidth(hintLabel, paint); + final float hintDigitWidth = TypefaceUtils.getReferenceDigitWidth(paint); + final float hintLabelWidth = TypefaceUtils.getStringWidth(hintLabel, paint); hintX = keyWidth - mKeyHintLetterPadding - - Math.max(keyNumericHintLabelReferenceCharWidth, keyHintLabelStringWidth) - / 2.0f; + - Math.max(hintDigitWidth, hintLabelWidth) / 2.0f; hintY = -paint.ascent(); paint.setTextAlign(Align.CENTER); } - canvas.drawText(hintLabel, 0, hintLabel.length(), hintX, hintY, paint); + canvas.drawText(hintLabel, 0, hintLabel.length(), hintX, hintY + adjustmentY, paint); if (LatinImeLogger.sVISUALDEBUG) { final Paint line = new Paint(); @@ -530,7 +534,7 @@ public class KeyboardView extends View { paint.setColor(params.mHintLabelColor); paint.setTextAlign(Align.CENTER); final float hintX = keyWidth - mKeyHintLetterPadding - - TypefaceUtils.getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2.0f; + - TypefaceUtils.getReferenceCharWidth(paint) / 2.0f; final float hintY = keyHeight - mKeyPopupHintLetterPadding; canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint); @@ -582,6 +586,7 @@ public class KeyboardView extends View { paint.setTypeface(mKeyDrawParams.mTypeface); paint.setTextSize(mKeyDrawParams.mLabelSize); } else { + paint.setColor(key.selectTextColor(mKeyDrawParams)); paint.setTypeface(key.selectTypeface(mKeyDrawParams)); paint.setTextSize(key.selectTextSize(mKeyDrawParams)); } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 13db47004..ecef8cc6c 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -28,18 +28,12 @@ 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.preference.PreferenceManager; import android.util.AttributeSet; -import android.util.DisplayMetrics; import android.util.Log; -import android.util.SparseArray; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.inputmethod.InputMethodSubtype; import android.widget.TextView; @@ -47,15 +41,17 @@ import android.widget.TextView; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.annotations.ExternallyReferenced; -import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; -import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; -import com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText; -import com.android.inputmethod.keyboard.internal.GestureTrailsPreview; +import com.android.inputmethod.keyboard.internal.DrawingHandler; +import com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView; +import com.android.inputmethod.keyboard.internal.GestureFloatingTextDrawingPreview; +import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; +import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; +import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; -import com.android.inputmethod.keyboard.internal.PreviewPlacerView; -import com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview; +import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview; +import com.android.inputmethod.keyboard.internal.TimerHandler; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; @@ -64,11 +60,9 @@ import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; -import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; +import com.android.inputmethod.latin.utils.SpacebarLanguageUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils; -import com.android.inputmethod.latin.utils.ViewLayoutUtils; import com.android.inputmethod.research.ResearchLogger; import java.util.WeakHashMap; @@ -78,9 +72,10 @@ import java.util.WeakHashMap; * * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedEnabled * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon - * @attr ref R.styleable#MainKeyboardView_spacebarTextRatio - * @attr ref R.styleable#MainKeyboardView_spacebarTextColor - * @attr ref R.styleable#MainKeyboardView_spacebarTextShadowColor + * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio + * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor + * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor + * @attr ref R.styleable#MainKeyboardView_spacebarBackground * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator @@ -88,7 +83,7 @@ import java.util.WeakHashMap; * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance - * @attr ref R.styleable#MainKeyboardView_slidingKeyInputEnable + * @attr ref R.styleable#MainKeyboardView_keySelectionByDraggingFinger * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout @@ -114,26 +109,27 @@ import java.util.WeakHashMap; * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration */ -public final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler, - PointerTracker.DrawingProxy, MoreKeysPanel.Controller { +public final class MainKeyboardView extends KeyboardView implements PointerTracker.DrawingProxy, + MoreKeysPanel.Controller, DrawingHandler.Callbacks, TimerHandler.Callbacks { private static final String TAG = MainKeyboardView.class.getSimpleName(); /** Listener for {@link KeyboardActionListener}. */ private KeyboardActionListener mKeyboardActionListener; - /* Space key and its icons */ + /* Space key and its icon and background. */ private Key mSpaceKey; - private Drawable mSpaceIcon; + private Drawable mSpacebarIcon; + private final Drawable mSpacebarBackground; // Stuff to draw language name on spacebar. private final int mLanguageOnSpacebarFinalAlpha; private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; - private boolean mNeedsToDisplayLanguage; + private int mLanguageOnSpacebarFormatType; private boolean mHasMultipleEnabledIMEsOrSubtypes; private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; - private final float mSpacebarTextRatio; - private float mSpacebarTextSize; - private final int mSpacebarTextColor; - private final int mSpacebarTextShadowColor; + private final float mLanguageOnSpacebarTextRatio; + private float mLanguageOnSpacebarTextSize; + private final int mLanguageOnSpacebarTextColor; + private final int mLanguageOnSpacebarTextShadowColor; // The minimum x-scale to fit the language name on spacebar. private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; // Stuff to draw auto correction LED on spacebar. @@ -143,25 +139,21 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private static final int SPACE_LED_LENGTH_PERCENT = 80; // Stuff to draw altCodeWhileTyping keys. - private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; - private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; + private final ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; + private final ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; - // Preview placer view - private final PreviewPlacerView mPreviewPlacerView; + // Drawing preview placer view + private final DrawingPreviewPlacerView mDrawingPreviewPlacerView; private final int[] mOriginCoords = CoordinateUtils.newInstance(); - private final GestureFloatingPreviewText mGestureFloatingPreviewText; - private final GestureTrailsPreview mGestureTrailsPreview; - private final SlidingKeyInputPreview mSlidingKeyInputPreview; + private final GestureFloatingTextDrawingPreview mGestureFloatingTextDrawingPreview; + private final GestureTrailsDrawingPreview mGestureTrailsDrawingPreview; + private final SlidingKeyInputDrawingPreview mSlidingKeyInputDrawingPreview; // Key preview - private final int mKeyPreviewLayoutId; - private final int mKeyPreviewOffset; - private final int mKeyPreviewHeight; - private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); - private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); - private boolean mShowKeyPreviewPopup = true; - private int mKeyPreviewLingerTimeout; + private static final boolean FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED = false; + private final KeyPreviewDrawParams mKeyPreviewDrawParams; + private final KeyPreviewChoreographer mKeyPreviewChoreographer; // More keys keyboard private final Paint mBackgroundDimAlphaPaint = new Paint(); @@ -178,244 +170,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // TODO: Make this parameter customizable by user via settings. private int mGestureFloatingPreviewTextLingerTimeout; - private KeyDetector mKeyDetector; + private final KeyDetector mKeyDetector; private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper; - private final KeyTimerHandler mKeyTimerHandler; + private final TimerHandler mKeyTimerHandler; private final int mLanguageOnSpacebarHorizontalMargin; - private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> - implements TimerProxy { - private static final int MSG_TYPING_STATE_EXPIRED = 0; - private static final int MSG_REPEAT_KEY = 1; - private static final int MSG_LONGPRESS_KEY = 2; - private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 3; - private static final int MSG_UPDATE_BATCH_INPUT = 4; - - private final int mIgnoreAltCodeKeyTimeout; - private final int mGestureRecognitionUpdateTime; - - public KeyTimerHandler(final MainKeyboardView outerInstance, - final TypedArray mainKeyboardViewAttr) { - super(outerInstance); - - mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); - mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); - } - - @Override - public void handleMessage(final Message msg) { - final MainKeyboardView keyboardView = getOuterInstance(); - if (keyboardView == null) { - return; - } - final PointerTracker tracker = (PointerTracker) msg.obj; - switch (msg.what) { - case MSG_TYPING_STATE_EXPIRED: - startWhileTypingFadeinAnimation(keyboardView); - break; - case MSG_REPEAT_KEY: - tracker.onKeyRepeat(msg.arg1 /* code */, msg.arg2 /* repeatCount */); - break; - case MSG_LONGPRESS_KEY: - keyboardView.onLongPress(tracker); - break; - case MSG_UPDATE_BATCH_INPUT: - tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); - startUpdateBatchInputTimer(tracker); - break; - } - } - - @Override - public void startKeyRepeatTimer(final PointerTracker tracker, final int repeatCount, - final int delay) { - final Key key = tracker.getKey(); - if (key == null || delay == 0) { - return; - } - sendMessageDelayed( - obtainMessage(MSG_REPEAT_KEY, key.getCode(), repeatCount, tracker), delay); - } - - public void cancelKeyRepeatTimer() { - removeMessages(MSG_REPEAT_KEY); - } - - // TODO: Suppress layout changes in key repeat mode - public boolean isInKeyRepeat() { - return hasMessages(MSG_REPEAT_KEY); - } - - @Override - public void startLongPressTimer(final PointerTracker tracker, final int delay) { - cancelLongPressTimer(); - if (delay <= 0) return; - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); - } - - @Override - public void cancelLongPressTimer() { - removeMessages(MSG_LONGPRESS_KEY); - } - - private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, - final ObjectAnimator animatorToStart) { - if (animatorToCancel == null || animatorToStart == null) { - // TODO: Stop using null as a no-operation animator. - return; - } - float startFraction = 0.0f; - if (animatorToCancel.isStarted()) { - animatorToCancel.cancel(); - startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); - } - final long startTime = (long)(animatorToStart.getDuration() * startFraction); - animatorToStart.start(); - animatorToStart.setCurrentPlayTime(startTime); - } - - private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { - cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, - keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); - } - - private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { - cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, - keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); - } - - @Override - public void startTypingStateTimer(final Key typedKey) { - if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { - return; - } - - final boolean isTyping = isTypingState(); - removeMessages(MSG_TYPING_STATE_EXPIRED); - final MainKeyboardView keyboardView = getOuterInstance(); - - // When user hits the space or the enter key, just cancel the while-typing timer. - final int typedCode = typedKey.getCode(); - if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { - if (isTyping) { - startWhileTypingFadeinAnimation(keyboardView); - } - return; - } - - sendMessageDelayed( - obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); - if (isTyping) { - return; - } - startWhileTypingFadeoutAnimation(keyboardView); - } - - @Override - public boolean isTypingState() { - return hasMessages(MSG_TYPING_STATE_EXPIRED); - } - - @Override - public void startDoubleTapShiftKeyTimer() { - sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY), - ViewConfiguration.getDoubleTapTimeout()); - } - - @Override - public void cancelDoubleTapShiftKeyTimer() { - removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY); - } - - @Override - public boolean isInDoubleTapShiftKeyTimeout() { - return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY); - } - - @Override - public void cancelKeyTimers() { - cancelKeyRepeatTimer(); - cancelLongPressTimer(); - } - - @Override - public void startUpdateBatchInputTimer(final PointerTracker tracker) { - if (mGestureRecognitionUpdateTime <= 0) { - return; - } - removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); - sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), - mGestureRecognitionUpdateTime); - } - - @Override - public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { - removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); - } - - @Override - public void cancelAllUpdateBatchInputTimers() { - removeMessages(MSG_UPDATE_BATCH_INPUT); - } - - public void cancelAllMessages() { - cancelKeyTimers(); - cancelAllUpdateBatchInputTimers(); - } - } - - private final DrawingHandler mDrawingHandler = new DrawingHandler(this); - - public static class DrawingHandler extends StaticInnerHandlerWrapper<MainKeyboardView> { - private static final int MSG_DISMISS_KEY_PREVIEW = 0; - private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; - - public DrawingHandler(final MainKeyboardView outerInstance) { - super(outerInstance); - } - - @Override - public void handleMessage(final Message msg) { - final MainKeyboardView mainKeyboardView = getOuterInstance(); - if (mainKeyboardView == null) return; - final PointerTracker tracker = (PointerTracker) msg.obj; - switch (msg.what) { - case MSG_DISMISS_KEY_PREVIEW: - final TextView previewText = mainKeyboardView.mKeyPreviewTexts.get( - tracker.mPointerId); - if (previewText != null) { - previewText.setVisibility(INVISIBLE); - } - break; - case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: - mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); - break; - } - } - - public void dismissKeyPreview(final long delay, final PointerTracker tracker) { - sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); - } - - public void cancelDismissKeyPreview(final PointerTracker tracker) { - removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker); - } - - private void cancelAllDismissKeyPreviews() { - removeMessages(MSG_DISMISS_KEY_PREVIEW); - } - - public void dismissGestureFloatingPreviewText(final long delay) { - sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); - } - - public void cancelAllMessages() { - cancelAllDismissKeyPreviews(); - } - } + private final DrawingHandler mDrawingHandler = + new DrawingHandler(this); public MainKeyboardView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.mainKeyboardViewStyle); @@ -424,7 +186,26 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); - PointerTracker.init(getResources()); + mDrawingPreviewPlacerView = new DrawingPreviewPlacerView(context, attrs); + + final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( + attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); + final int ignoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); + final int gestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); + mKeyTimerHandler = new TimerHandler( + this, ignoreAltCodeKeyTimeout, gestureRecognitionUpdateTime); + + final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); + final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); + mKeyDetector = new KeyDetector( + keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); + + PointerTracker.init(mainKeyboardViewAttr, mKeyTimerHandler, this /* DrawingProxy */); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final boolean forceNonDistinctMultitouch = prefs.getBoolean( DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); @@ -434,24 +215,22 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null : new NonDistinctMultitouchHelper(); - mPreviewPlacerView = new PreviewPlacerView(context, attrs); - - final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( - attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); final int backgroundDimAlpha = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_backgroundDimAlpha, 0); mBackgroundDimAlphaPaint.setColor(Color.BLACK); mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); + mSpacebarBackground = mainKeyboardViewAttr.getDrawable( + R.styleable.MainKeyboardView_spacebarBackground); mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); - mSpacebarTextRatio = mainKeyboardViewAttr.getFraction( - R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f); - mSpacebarTextColor = mainKeyboardViewAttr.getColor( - R.styleable.MainKeyboardView_spacebarTextColor, 0); - mSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( - R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); + mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction( + R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f); + mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor( + R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0); + mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( + R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0); mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, Constants.Color.ALPHA_OPAQUE); @@ -462,24 +241,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId( R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); - final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); - final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); - mKeyDetector = new KeyDetector( - keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); - mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr); - mKeyPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( - R.styleable.MainKeyboardView_keyPreviewOffset, 0); - mKeyPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( - R.styleable.MainKeyboardView_keyPreviewHeight, 0); - mKeyPreviewLingerTimeout = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); - mKeyPreviewLayoutId = mainKeyboardViewAttr.getResourceId( - R.styleable.MainKeyboardView_keyPreviewLayout, 0); - if (mKeyPreviewLayoutId == 0) { - mShowKeyPreviewPopup = false; - } + mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr); + mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams); + final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( @@ -487,19 +251,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); - PointerTracker.setParameters(mainKeyboardViewAttr); - mGestureFloatingPreviewText = new GestureFloatingPreviewText( - mPreviewPlacerView, mainKeyboardViewAttr); - mPreviewPlacerView.addPreview(mGestureFloatingPreviewText); + mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview( + mDrawingPreviewPlacerView, mainKeyboardViewAttr); + mDrawingPreviewPlacerView.addPreview(mGestureFloatingTextDrawingPreview); - mGestureTrailsPreview = new GestureTrailsPreview( - mPreviewPlacerView, mainKeyboardViewAttr); - mPreviewPlacerView.addPreview(mGestureTrailsPreview); + mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview( + mDrawingPreviewPlacerView, mainKeyboardViewAttr); + mDrawingPreviewPlacerView.addPreview(mGestureTrailsDrawingPreview); - mSlidingKeyInputPreview = new SlidingKeyInputPreview( - mPreviewPlacerView, mainKeyboardViewAttr); - mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); + mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview( + mDrawingPreviewPlacerView, mainKeyboardViewAttr); + mDrawingPreviewPlacerView.addPreview(mSlidingKeyInputDrawingPreview); mainKeyboardViewAttr.recycle(); mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) @@ -513,14 +276,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; - mLanguageOnSpacebarHorizontalMargin = - (int) getResources().getDimension(R.dimen.language_on_spacebar_horizontal_margin); + mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension( + R.dimen.config_language_on_spacebar_horizontal_margin); } @Override public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) { super.setHardwareAcceleratedDrawingEnabled(enabled); - mPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled); + mDrawingPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled); } private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { @@ -536,6 +299,35 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack return animator; } + private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, + final ObjectAnimator animatorToStart) { + if (animatorToCancel == null || animatorToStart == null) { + // TODO: Stop using null as a no-operation animator. + return; + } + float startFraction = 0.0f; + if (animatorToCancel.isStarted()) { + animatorToCancel.cancel(); + startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); + } + final long startTime = (long)(animatorToStart.getDuration() * startFraction); + animatorToStart.start(); + animatorToStart.setCurrentPlayTime(startTime); + } + + // Implements {@link TimerHander.Callbacks} method. + @Override + public void startWhileTypingFadeinAnimation() { + cancelAndStartAnimators( + mAltCodeKeyWhileTypingFadeoutAnimator, mAltCodeKeyWhileTypingFadeinAnimator); + } + + @Override + public void startWhileTypingFadeoutAnimation() { + cancelAndStartAnimators( + mAltCodeKeyWhileTypingFadeinAnimator, mAltCodeKeyWhileTypingFadeoutAnimator); + } + @ExternallyReferenced public int getLanguageOnSpacebarAnimAlpha() { return mLanguageOnSpacebarAnimAlpha; @@ -573,28 +365,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack PointerTracker.setKeyboardActionListener(listener); } - /** - * Returns the {@link KeyboardActionListener} object. - * @return the listener attached to this keyboard - */ - @Override - public KeyboardActionListener getKeyboardActionListener() { - return mKeyboardActionListener; - } - - @Override - public KeyDetector getKeyDetector() { - return mKeyDetector; - } - - @Override - public DrawingProxy getDrawingProxy() { - return this; + // TODO: We should reconsider which coordinate system should be used to represent keyboard + // event. + public int getKeyX(final int x) { + return Constants.isValidCoordinate(x) ? mKeyDetector.getTouchX(x) : x; } - @Override - public TimerProxy getTimerProxy() { - return mKeyTimerHandler; + // TODO: We should reconsider which coordinate system should be used to represent keyboard + // event. + public int getKeyY(final int y) { + return Constants.isValidCoordinate(y) ? mKeyDetector.getTouchY(y) : y; } /** @@ -607,7 +387,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override public void setKeyboard(final Keyboard keyboard) { // Remove any pending messages, except dismissing preview and key repeat. - mKeyTimerHandler.cancelLongPressTimer(); + mKeyTimerHandler.cancelLongPressTimers(); super.setKeyboard(keyboard); mKeyDetector.setKeyboard( keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); @@ -615,10 +395,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack mMoreKeysKeyboardCache.clear(); mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); - mSpaceIcon = (mSpaceKey != null) + mSpacebarIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; - mSpacebarTextSize = keyHeight * mSpacebarTextRatio; + mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio; if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { final int orientation = getContext().getResources().getConfiguration().orientation; ResearchLogger.mainKeyboardView_setKeyboard(keyboard, orientation); @@ -626,7 +406,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // This always needs to be set since the accessibility state can // potentially change without the keyboard being set again. - AccessibleKeyboardViewProxy.getInstance().setKeyboard(); + AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard); } /** @@ -637,26 +417,21 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack * @see #isKeyPreviewPopupEnabled() */ public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { - mShowKeyPreviewPopup = previewEnabled; - mKeyPreviewLingerTimeout = delay; + mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay); + } + + public void setKeyPreviewAnimationParams(final float showUpStartScale, final int showUpDuration, + final float dismissEndScale, final int dismissDuration) { + mKeyPreviewDrawParams.setAnimationParams( + showUpStartScale, showUpDuration, dismissEndScale, dismissDuration); } private void locatePreviewPlacerView() { - if (mPreviewPlacerView.getParent() != null) { - return; - } - final int width = getWidth(); - final int height = getHeight(); - if (width == 0 || height == 0) { - // In transient state. - return; - } getLocationInWindow(mOriginCoords); - final DisplayMetrics dm = getResources().getDisplayMetrics(); - if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) { - // In transient state. - return; - } + mDrawingPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, getWidth(), getHeight()); + } + + private void installPreviewPlacerView() { final View rootView = getRootView(); if (rootView == null) { Log.w(TAG, "Cannot find root view"); @@ -665,11 +440,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); // Note: It'd be very weird if we get null by android.R.id.content. if (windowContentView == null) { - Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView"); - } else { - windowContentView.addView(mPreviewPlacerView); - mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height); + Log.w(TAG, "Cannot find android.R.id.content view to add DrawingPreviewPlacerView"); + return; } + windowContentView.addView(mDrawingPreviewPlacerView); } /** @@ -678,80 +452,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack * @see #setKeyPreviewPopupEnabled(boolean, int) */ public boolean isKeyPreviewPopupEnabled() { - return mShowKeyPreviewPopup; - } - - private void addKeyPreview(final TextView keyPreview) { - locatePreviewPlacerView(); - mPreviewPlacerView.addView( - keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); - } - - private TextView getKeyPreviewText(final int pointerId) { - TextView previewText = mKeyPreviewTexts.get(pointerId); - if (previewText != null) { - return previewText; - } - final Context context = getContext(); - if (mKeyPreviewLayoutId != 0) { - previewText = (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null); - } else { - previewText = new TextView(context); - } - mKeyPreviewTexts.put(pointerId, previewText); - return previewText; + return mKeyPreviewDrawParams.isPopupEnabled(); } - private void dismissAllKeyPreviews() { - final int pointerCount = mKeyPreviewTexts.size(); - for (int id = 0; id < pointerCount; id++) { - final TextView previewText = mKeyPreviewTexts.get(id); - if (previewText != null) { - previewText.setVisibility(INVISIBLE); - } - } + // Implements {@link DrawingHandler.Callbacks} method. + @Override + public void dismissAllKeyPreviews() { + mKeyPreviewChoreographer.dismissAllKeyPreviews(); PointerTracker.setReleasedKeyGraphicsToAllKeys(); } - // Background state set - private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { - { // STATE_MIDDLE - EMPTY_STATE_SET, - { R.attr.state_has_morekeys } - }, - { // STATE_LEFT - { R.attr.state_left_edge }, - { R.attr.state_left_edge, R.attr.state_has_morekeys } - }, - { // STATE_RIGHT - { R.attr.state_right_edge }, - { R.attr.state_right_edge, R.attr.state_has_morekeys } - } - }; - private static final int STATE_MIDDLE = 0; - private static final int STATE_LEFT = 1; - private static final int STATE_RIGHT = 2; - private static final int STATE_NORMAL = 0; - private static final int STATE_HAS_MOREKEYS = 1; - @Override - public void showKeyPreview(final PointerTracker tracker) { - final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; - final Keyboard keyboard = getKeyboard(); - if (!mShowKeyPreviewPopup) { - previewParams.mPreviewVisibleOffset = -keyboard.mVerticalGap; - return; - } - - final TextView previewText = getKeyPreviewText(tracker.mPointerId); - // If the key preview has no parent view yet, add it to the ViewGroup which can place - // key preview absolutely in SoftInputWindow. - if (previewText.getParent() == null) { - addKeyPreview(previewText); - } - - mDrawingHandler.cancelDismissKeyPreview(tracker); - final Key key = tracker.getKey(); + public void showKeyPreview(final Key key) { // 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. @@ -759,97 +471,66 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack return; } - final KeyDrawParams drawParams = mKeyDrawParams; - previewText.setTextColor(drawParams.mPreviewTextColor); - final Drawable background = previewText.getBackground(); - final String label = key.getPreviewLabel(); - // What we show as preview should match what we show on a key top in onDraw(). - if (label != null) { - // TODO Should take care of temporaryShiftLabel here. - previewText.setCompoundDrawables(null, null, null, null); - previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, - key.selectPreviewTextSize(drawParams)); - previewText.setTypeface(key.selectPreviewTypeface(drawParams)); - previewText.setText(label); - } else { - previewText.setCompoundDrawables(null, null, null, - key.getPreviewIcon(keyboard.mIconsSet)); - previewText.setText(null); + final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; + final Keyboard keyboard = getKeyboard(); + if (!previewParams.isPopupEnabled()) { + previewParams.setVisibleOffset(-keyboard.mVerticalGap); + return; } - previewText.measure( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - final int keyDrawWidth = key.getDrawWidth(); - final int previewWidth = previewText.getMeasuredWidth(); - final int previewHeight = mKeyPreviewHeight; - // The width and height of visible part of the key preview background. The content marker - // of the background 9-patch have to cover the visible part of the background. - previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() - - previewText.getPaddingRight(); - previewParams.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop() - - previewText.getPaddingBottom(); - // The distance between the top edge of the parent key and the bottom of the visible part - // of the key preview background. - previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); + locatePreviewPlacerView(); + final TextView previewTextView = mKeyPreviewChoreographer.getKeyPreviewTextView( + key, mDrawingPreviewPlacerView); getLocationInWindow(mOriginCoords); - // The key preview is horizontally aligned with the center of the visible part of the - // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and - // the left/right background is used if such background is specified. - final int statePosition; - int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 - + CoordinateUtils.x(mOriginCoords); - if (previewX < 0) { - previewX = 0; - statePosition = STATE_LEFT; - } else if (previewX > getWidth() - previewWidth) { - previewX = getWidth() - previewWidth; - statePosition = STATE_RIGHT; - } else { - statePosition = STATE_MIDDLE; - } - // The key preview is placed vertically above the top edge of the parent key with an - // arbitrary offset. - final int previewY = key.getY() - previewHeight + mKeyPreviewOffset - + CoordinateUtils.y(mOriginCoords); - - if (background != null) { - final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; - background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); - } - ViewLayoutUtils.placeViewAt( - previewText, previewX, previewY, previewWidth, previewHeight); - previewText.setVisibility(VISIBLE); + mKeyPreviewChoreographer.placeKeyPreview(key, previewTextView, keyboard.mIconsSet, + mKeyDrawParams, getWidth(), mOriginCoords); + mKeyPreviewChoreographer.showKeyPreview(key, previewTextView, isHardwareAccelerated()); } + // Implements {@link TimerHandler.Callbacks} method. @Override - public void dismissKeyPreview(final PointerTracker tracker) { - mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); + public void dismissKeyPreviewWithoutDelay(final Key key) { + mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */); + // To redraw key top letter. + invalidateKey(key); + } + + @Override + public void dismissKeyPreview(final Key key) { + if (!isHardwareAccelerated()) { + // TODO: Implement preference option to control key preview method and duration. + mDrawingHandler.dismissKeyPreview(mKeyPreviewDrawParams.getLingerTimeout(), key); + return; + } + mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */); } public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { - mSlidingKeyInputPreview.setPreviewEnabled(enabled); + mSlidingKeyInputDrawingPreview.setPreviewEnabled(enabled); } @Override public void showSlidingKeyInputPreview(final PointerTracker tracker) { locatePreviewPlacerView(); - mSlidingKeyInputPreview.setPreviewPosition(tracker); + mSlidingKeyInputDrawingPreview.setPreviewPosition(tracker); } @Override public void dismissSlidingKeyInputPreview() { - mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); + mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview(); } private void setGesturePreviewMode(final boolean isGestureTrailEnabled, final boolean isGestureFloatingPreviewTextEnabled) { - mGestureFloatingPreviewText.setPreviewEnabled(isGestureFloatingPreviewTextEnabled); - mGestureTrailsPreview.setPreviewEnabled(isGestureTrailEnabled); + mGestureFloatingTextDrawingPreview.setPreviewEnabled(isGestureFloatingPreviewTextEnabled); + mGestureTrailsDrawingPreview.setPreviewEnabled(isGestureTrailEnabled); } + // Implements {@link DrawingHandler.Callbacks} method. + @Override public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { locatePreviewPlacerView(); - mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); + mGestureFloatingTextDrawingPreview.setSuggetedWords(suggestedWords); } public void dismissGestureFloatingPreviewText() { @@ -862,9 +543,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final boolean showsFloatingPreviewText) { locatePreviewPlacerView(); if (showsFloatingPreviewText) { - mGestureFloatingPreviewText.setPreviewPosition(tracker); + mGestureFloatingTextDrawingPreview.setPreviewPosition(tracker); } - mGestureTrailsPreview.setPreviewPosition(tracker); + mGestureTrailsDrawingPreview.setPreviewPosition(tracker); } // Note that this method is called from a non-UI thread. @@ -883,6 +564,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + installPreviewPlacerView(); // Notify the ResearchLogger (development only diagnostics) that the keyboard view has // been attached. This is needed to properly show the splash screen, which requires that // the window token of the KeyboardView be non-null. @@ -894,7 +576,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mPreviewPlacerView.removeAllViews(); + mDrawingPreviewPlacerView.removeAllViews(); // Notify the ResearchLogger (development only diagnostics) that the keyboard view has // been detached. This is needed to invalidate the reference of {@link MainKeyboardView} // to null. @@ -922,11 +604,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack return moreKeysKeyboardView; } + // Implements {@link TimerHandler.Callbacks} method. /** * Called when a key is long pressed. * @param tracker the pointer tracker which pressed the parent key */ - private void onLongPress(final PointerTracker tracker) { + @Override + public void onLongPress(final PointerTracker tracker) { if (isShowingMoreKeysPanel()) { return; } @@ -942,8 +626,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int moreKeyCode = key.getMoreKeys()[0].mCode; tracker.onLongPressed(); listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */); - listener.onCodeInput(moreKeyCode, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + listener.onCodeInput(moreKeyCode, Constants.NOT_A_COORDINATE, + Constants.NOT_A_COORDINATE, false /* isKeyRepeat */); listener.onReleaseKey(moreKeyCode, false /* withSliding */); return; } @@ -979,26 +663,24 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // aligned with the bottom edge of the visible part of the key preview. // {@code mPreviewVisibleOffset} has been set appropriately in // {@link KeyboardView#showKeyPreview(PointerTracker)}. - final int pointY = key.getY() + mKeyPreviewDrawParams.mPreviewVisibleOffset; + final int pointY = key.getY() + mKeyPreviewDrawParams.getVisibleOffset(); moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); tracker.onShowMoreKeysPanel(moreKeysPanel); + // TODO: Implement zoom in animation of more keys panel. + dismissKeyPreviewWithoutDelay(key); } - public boolean isInSlidingKeyInput() { + public boolean isInDraggingFinger() { if (isShowingMoreKeysPanel()) { return true; } - return PointerTracker.isAnyInSlidingKeyInput(); + return PointerTracker.isAnyInDraggingFinger(); } @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) { locatePreviewPlacerView(); - // TODO: Remove this check - if (panel.isShowingInParent()) { - panel.dismissMoreKeysPanel(); - } - mPreviewPlacerView.addView(panel.getContainerView()); + panel.showInParent(mDrawingPreviewPlacerView); mMoreKeysPanel = panel; dimEntireKeyboard(true /* dimmed */); } @@ -1008,15 +690,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { + public void onCancelMoreKeysPanel() { PointerTracker.dismissAllMoreKeysPanels(); } @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { + public void onDismissMoreKeysPanel() { dimEntireKeyboard(false /* dimmed */); if (isShowingMoreKeysPanel()) { - mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView()); + mMoreKeysPanel.removeFromParent(); mMoreKeysPanel = null; } } @@ -1034,14 +716,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override - public boolean dispatchTouchEvent(MotionEvent event) { - if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { - return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); - } - return super.dispatchTouchEvent(event); - } - - @Override public boolean onTouchEvent(final MotionEvent me) { if (getKeyboard() == null) { return false; @@ -1049,10 +723,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack if (mNonDistinctMultitouchHelper != null) { if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) { // Key repeating timer will be canceled if 2 or more keys are in action. - mKeyTimerHandler.cancelKeyRepeatTimer(); + mKeyTimerHandler.cancelKeyRepeatTimers(); } // Non distinct multitouch screen support - mNonDistinctMultitouchHelper.processMotionEvent(me, this); + mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector); return true; } return processMotionEvent(me); @@ -1069,8 +743,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int index = me.getActionIndex(); final int id = me.getPointerId(index); - final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); - tracker.processMotionEvent(me, this); + final PointerTracker tracker = PointerTracker.getPointerTracker(id); + // When a more keys panel is showing, we should ignore other fingers' single touch events + // other than the finger that is showing the more keys panel. + if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel() + && PointerTracker.getActivePointerTrackerCount() == 1) { + return true; + } + tracker.processMotionEvent(me, mKeyDetector); return true; } @@ -1099,8 +779,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override public boolean dispatchHoverEvent(final MotionEvent event) { if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { - final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); - return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); + return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent( + event, mKeyDetector); } // Reflection doesn't support calling superclass methods. @@ -1121,14 +801,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, - final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { - mNeedsToDisplayLanguage = needsToDisplayLanguage; + final int languageOnSpacebarFormatType, + final boolean hasMultipleEnabledIMEsOrSubtypes) { + mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType; mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; if (animator == null) { - mNeedsToDisplayLanguage = false; + mLanguageOnSpacebarFormatType = LanguageOnSpacebarHelper.FORMAT_TYPE_NONE; } else { - if (subtypeChanged && needsToDisplayLanguage) { + if (subtypeChanged + && languageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) { setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); if (animator.isStarted()) { animator.cancel(); @@ -1169,12 +851,30 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } } + // Draw key background. + @Override + protected void onDrawKeyBackground(final Key key, final Canvas canvas, + final Drawable background) { + if (key.getCode() == Constants.CODE_SPACE) { + super.onDrawKeyBackground(key, canvas, mSpacebarBackground); + return; + } + super.onDrawKeyBackground(key, canvas, background); + } + @Override protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, final KeyDrawParams params) { if (key.altCodeWhileTyping() && key.isEnabled()) { params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; } + // Don't draw key top letter when key preview is showing. + if (FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED + && mKeyPreviewChoreographer.isShowingKeyPreview(key)) { + // TODO: Fade out animation for the key top letter, and fade in animation for the key + // background color when the user presses the key. + return; + } final int code = key.getCode(); if (code == Constants.CODE_SPACE) { drawSpacebar(key, canvas, paint); @@ -1193,7 +893,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) { final int maxTextWidth = width - mLanguageOnSpacebarHorizontalMargin * 2; paint.setTextScaleX(1.0f); - final float textWidth = TypefaceUtils.getLabelWidth(text, paint); + final float textWidth = TypefaceUtils.getStringWidth(text, paint); if (textWidth < width) { return true; } @@ -1204,29 +904,25 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } paint.setTextScaleX(scaleX); - return TypefaceUtils.getLabelWidth(text, paint) < maxTextWidth; + return TypefaceUtils.getStringWidth(text, paint) < maxTextWidth; } // Layout language name on spacebar. private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype, final int width) { - // Choose appropriate language name to fit into the width. - final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype); - if (fitsTextIntoWidth(width, fullText, paint)) { - return fullText; + if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) { + final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype); + if (fitsTextIntoWidth(width, fullText, paint)) { + return fullText; + } } - final String middleText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); + final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype); if (fitsTextIntoWidth(width, middleText, paint)) { return middleText; } - final String shortText = SubtypeLocaleUtils.getShortDisplayName(subtype); - if (fitsTextIntoWidth(width, shortText, paint)) { - return shortText; - } - return ""; } @@ -1235,20 +931,20 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack final int height = key.getHeight(); // If input language are explicitly selected. - if (mNeedsToDisplayLanguage) { + if (mLanguageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) { paint.setTextAlign(Align.CENTER); paint.setTypeface(Typeface.DEFAULT); - paint.setTextSize(mSpacebarTextSize); + paint.setTextSize(mLanguageOnSpacebarTextSize); final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; final String language = layoutLanguageOnSpacebar(paint, subtype, width); // Draw language text with shadow final float descent = paint.descent(); final float textHeight = -paint.ascent() + descent; final float baseline = height / 2 + textHeight / 2; - paint.setColor(mSpacebarTextShadowColor); + paint.setColor(mLanguageOnSpacebarTextShadowColor); paint.setAlpha(mLanguageOnSpacebarAnimAlpha); canvas.drawText(language, width / 2, baseline - descent - 1, paint); - paint.setColor(mSpacebarTextColor); + paint.setColor(mLanguageOnSpacebarTextColor); paint.setAlpha(mLanguageOnSpacebarAnimAlpha); canvas.drawText(language, width / 2, baseline - descent, paint); } @@ -1260,18 +956,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack 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(); + } else if (mSpacebarIcon != null) { + final int iconWidth = mSpacebarIcon.getIntrinsicWidth(); + final int iconHeight = mSpacebarIcon.getIntrinsicHeight(); int x = (width - iconWidth) / 2; int y = height - iconHeight; - drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); + drawIcon(canvas, mSpacebarIcon, x, y, iconWidth, iconHeight); } } @Override public void deallocateMemory() { super.deallocateMemory(); - mGestureTrailsPreview.deallocateMemory(); + mDrawingPreviewPlacerView.deallocateMemory(); } } diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index 6b76e2461..5a9d4755f 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -21,25 +21,29 @@ public final class MoreKeysDetector extends KeyDetector { private final int mSlideAllowanceSquareTop; public MoreKeysDetector(float slideAllowance) { - super(/* keyHysteresisDistance */0); + super(); mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance); // Top slide allowance is slightly longer (sqrt(2) times) than other edges. mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2; } @Override - public boolean alwaysAllowsSlidingInput() { + public boolean alwaysAllowsKeySelectionByDraggingFinger() { return true; } @Override - public Key detectHitKey(int x, int y) { + public Key detectHitKey(final int x, final int y) { + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) { + return null; + } final int touchX = getTouchX(x); final int touchY = getTouchY(y); Key nearestKey = null; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - for (final Key key : getKeyboard().getKeys()) { + for (final Key key : keyboard.getSortedKeys()) { final int dist = key.squaredDistanceToEdge(touchX, touchY); if (dist < nearestDist) { nearestKey = key; diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index 8256d4623..a72f79137 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -223,7 +223,7 @@ public final class MoreKeysKeyboard extends Keyboard { } public int getDefaultKeyCoordX() { - return mLeftKeys * mColumnWidth; + return mLeftKeys * mColumnWidth + mLeftPadding; } public int getX(final int n, final int row) { @@ -285,7 +285,7 @@ public final class MoreKeysKeyboard extends Keyboard { // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}. final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview() && moreKeys.length == 1 - && keyPreviewDrawParams.mPreviewVisibleWidth > 0; + && keyPreviewDrawParams.getVisibleWidth() > 0; if (singleMoreKeyWithPreview) { // Use pre-computed width and height if this more keys keyboard has only one key to // mitigate visual flicker between key preview and more keys keyboard. @@ -294,11 +294,11 @@ public final class MoreKeysKeyboard extends Keyboard { // left/right/top paddings. The bottom paddings of both backgrounds don't need to // be considered because the vertical positions of both backgrounds were already // adjusted with their bottom paddings deducted. - width = keyPreviewDrawParams.mPreviewVisibleWidth; - height = keyPreviewDrawParams.mPreviewVisibleHeight + mParams.mVerticalGap; + width = keyPreviewDrawParams.getVisibleWidth(); + height = keyPreviewDrawParams.getVisibleHeight() + mParams.mVerticalGap; } else { final float padding = context.getResources().getDimension( - R.dimen.more_keys_keyboard_key_horizontal_padding) + R.dimen.config_more_keys_keyboard_key_horizontal_padding) + (parentKey.hasLabelsInMoreKeys() ? mParams.mDefaultKeyWidth * LABEL_PADDING_RATIO : 0.0f); width = getMaxKeyWidth(parentKey, mParams.mDefaultKeyWidth, padding, @@ -327,7 +327,7 @@ public final class MoreKeysKeyboard extends Keyboard { // If the label is single letter, minKeyWidth is enough to hold the label. if (label != null && StringUtils.codePointCount(label) > 1) { maxWidth = Math.max(maxWidth, - (int)(TypefaceUtils.getLabelWidth(label, paint) + padding)); + (int)(TypefaceUtils.getStringWidth(label, paint) + padding)); } } return maxWidth; @@ -343,8 +343,7 @@ public final class MoreKeysKeyboard extends Keyboard { final int row = n / params.mNumColumns; final int x = params.getX(n, row); final int y = params.getY(row); - final Key key = new Key(params, moreKeySpec, x, y, - params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags); + final Key key = moreKeySpec.buildKey(x, y, moreKeyFlags, params); params.markAsEdgeKey(key, row); params.onAddKey(key); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index 973128d36..65242dd76 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; @@ -52,7 +53,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel final Resources res = context.getResources(); mKeyDetector = new MoreKeysDetector( - res.getDimension(R.dimen.more_keys_keyboard_slide_allowance)); + res.getDimension(R.dimen.config_more_keys_keyboard_slide_allowance)); } @Override @@ -81,11 +82,13 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel mListener = listener; final View container = getContainerView(); // The coordinates of panel's left-top corner in parentView's coordinate system. - final int x = pointX - getDefaultCoordX() - container.getPaddingLeft(); - final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); + // We need to consider background drawable paddings. + final int x = pointX - getDefaultCoordX() - container.getPaddingLeft() - getPaddingLeft(); + final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom() + + getPaddingBottom(); parentView.getLocationInWindow(mCoordinates); - // Ensure the horizontal position of the panel does not extend past the screen edges. + // Ensure the horizontal position of the panel does not extend past the parentView edges. final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth(); final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates); final int panelY = y + CoordinateUtils.y(mCoordinates); @@ -119,7 +122,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel onMoveKeyInternal(x, y, pointerId); if (hasOldKey && mCurrentKey == null) { // If the pointer has moved too far away from any target then cancel the panel. - mController.onCancelMoreKeysPanel(this); + mController.onCancelMoreKeysPanel(); } } @@ -139,7 +142,12 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel if (code == Constants.CODE_OUTPUT_TEXT) { mListener.onTextInput(mCurrentKey.getOutputText()); } else if (code != Constants.CODE_UNSPECIFIED) { - mListener.onCodeInput(code, x, y); + if (getKeyboard().hasProximityCharsCorrection(code)) { + mListener.onCodeInput(code, x, y, false /* isKeyRepeat */); + } else { + mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, + false /* isKeyRepeat */); + } } } @@ -177,7 +185,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel if (!isShowingInParent()) { return; } - mController.onDismissMoreKeysPanel(this); + mController.onDismissMoreKeysPanel(); } @Override @@ -214,12 +222,26 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel return true; } - @Override - public View getContainerView() { + private View getContainerView() { return (View)getParent(); } @Override + public void showInParent(final ViewGroup parentView) { + removeFromParent(); + parentView.addView(getContainerView()); + } + + @Override + public void removeFromParent() { + final View containerView = getContainerView(); + final ViewGroup currentParent = (ViewGroup)containerView.getParent(); + if (currentParent != null) { + currentParent.removeView(containerView); + } + } + + @Override public boolean isShowingInParent() { return (getContainerView().getParent() != null); } diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index 886c6286f..7bddd09f6 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -17,6 +17,7 @@ package com.android.inputmethod.keyboard; import android.view.View; +import android.view.ViewGroup; public interface MoreKeysPanel { public interface Controller { @@ -28,24 +29,22 @@ public interface MoreKeysPanel { /** * Remove the current {@link MoreKeysPanel} from the target view. - * @param panel the panel to be dismissed. */ - public void onDismissMoreKeysPanel(final MoreKeysPanel panel); + public void onDismissMoreKeysPanel(); /** * Instructs the parent to cancel the panel (e.g., when entering a different input mode). - * @param panel the panel to be canceled. */ - public void onCancelMoreKeysPanel(final MoreKeysPanel panel); + public void onCancelMoreKeysPanel(); } public static final Controller EMPTY_CONTROLLER = new Controller() { @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) {} @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) {} + public void onDismissMoreKeysPanel() {} @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) {} + public void onCancelMoreKeysPanel() {} }; /** @@ -119,9 +118,16 @@ public interface MoreKeysPanel { public int translateY(int y); /** - * Return the view containing the more keys panel. + * Show this {@link MoreKeysPanel} in the parent view. + * + * @param parentView the {@link ViewGroup} that hosts this {@link MoreKeysPanel}. + */ + public void showInParent(ViewGroup parentView); + + /** + * Remove this {@link MoreKeysPanel} from the parent view. */ - public View getContainerView(); + public void removeFromParent(); /** * Return whether the panel is currently being shown. diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 52f190e77..4777166ea 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -19,16 +19,18 @@ package com.android.inputmethod.keyboard; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.SystemClock; -import android.util.DisplayMetrics; import android.util.Log; import android.view.MotionEvent; -import com.android.inputmethod.accessibility.AccessibilityUtils; -import com.android.inputmethod.keyboard.internal.GestureStroke; -import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams; -import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints; -import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams; +import com.android.inputmethod.keyboard.internal.BatchInputArbiter; +import com.android.inputmethod.keyboard.internal.BatchInputArbiter.BatchInputArbiterListener; +import com.android.inputmethod.keyboard.internal.BogusMoveEventDetector; +import com.android.inputmethod.keyboard.internal.GestureEnabler; +import com.android.inputmethod.keyboard.internal.GestureStrokeDrawingParams; +import com.android.inputmethod.keyboard.internal.GestureStrokeDrawingPoints; +import com.android.inputmethod.keyboard.internal.GestureStrokeRecognitionParams; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; +import com.android.inputmethod.keyboard.internal.TypingTimeRecorder; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.LatinImeLogger; @@ -42,50 +44,18 @@ import com.android.inputmethod.research.ResearchLogger; import java.util.ArrayList; -public final class PointerTracker implements PointerTrackerQueue.Element { +public final class PointerTracker implements PointerTrackerQueue.Element, + BatchInputArbiterListener { private static final String TAG = PointerTracker.class.getSimpleName(); private static final boolean DEBUG_EVENT = false; private static final boolean DEBUG_MOVE_EVENT = false; private static final boolean DEBUG_LISTENER = false; private static boolean DEBUG_MODE = LatinImeLogger.sDBG || DEBUG_EVENT; - /** True if {@link PointerTracker}s should handle gesture events. */ - private static boolean sShouldHandleGesture = false; - private static boolean sMainDictionaryAvailable = false; - private static boolean sGestureHandlingEnabledByInputField = false; - private static boolean sGestureHandlingEnabledByUser = false; - - public interface KeyEventHandler { - /** - * Get KeyDetector object that is used for this PointerTracker. - * @return the KeyDetector object that is used for this PointerTracker - */ - public KeyDetector getKeyDetector(); - - /** - * Get KeyboardActionListener object that is used to register key code and so on. - * @return the KeyboardActionListner for this PointerTracke - */ - public KeyboardActionListener getKeyboardActionListener(); - - /** - * Get DrawingProxy object that is used for this PointerTracker. - * @return the DrawingProxy object that is used for this PointerTracker - */ - public DrawingProxy getDrawingProxy(); - - /** - * Get TimerProxy object that handles key repeat and long press timer event for this - * PointerTracker. - * @return the TimerProxy object that handles key repeat and long press timer event. - */ - public TimerProxy getTimerProxy(); - } - public interface DrawingProxy { public void invalidateKey(Key key); - public void showKeyPreview(PointerTracker tracker); - public void dismissKeyPreview(PointerTracker tracker); + public void showKeyPreview(Key key); + public void dismissKeyPreview(Key key); public void showSlidingKeyInputPreview(PointerTracker tracker); public void dismissSlidingKeyInputPreview(); public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText); @@ -94,13 +64,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { public interface TimerProxy { public void startTypingStateTimer(Key typedKey); public boolean isTypingState(); - public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay); - public void startLongPressTimer(PointerTracker tracker, int delay); - public void cancelLongPressTimer(); + public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay); + public void startLongPressTimerOf(PointerTracker tracker, int delay); + public void cancelLongPressTimerOf(PointerTracker tracker); + public void cancelLongPressShiftKeyTimers(); + public void cancelKeyTimersOf(PointerTracker tracker); public void startDoubleTapShiftKeyTimer(); public void cancelDoubleTapShiftKeyTimer(); public boolean isInDoubleTapShiftKeyTimeout(); - public void cancelKeyTimers(); public void startUpdateBatchInputTimer(PointerTracker tracker); public void cancelUpdateBatchInputTimer(PointerTracker tracker); public void cancelAllUpdateBatchInputTimers(); @@ -111,11 +82,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { @Override public boolean isTypingState() { return false; } @Override - public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay) {} + public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay) {} + @Override + public void startLongPressTimerOf(PointerTracker tracker, int delay) {} @Override - public void startLongPressTimer(PointerTracker tracker, int delay) {} + public void cancelLongPressTimerOf(PointerTracker tracker) {} @Override - public void cancelLongPressTimer() {} + public void cancelLongPressShiftKeyTimers() {} + @Override + public void cancelKeyTimersOf(PointerTracker tracker) {} @Override public void startDoubleTapShiftKeyTimer() {} @Override @@ -123,8 +98,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element { @Override public boolean isInDoubleTapShiftKeyTimeout() { return false; } @Override - public void cancelKeyTimers() {} - @Override public void startUpdateBatchInputTimer(PointerTracker tracker) {} @Override public void cancelUpdateBatchInputTimer(PointerTracker tracker) {} @@ -134,7 +107,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } static final class PointerTrackerParams { - public final boolean mSlidingKeyInputEnabled; + public final boolean mKeySelectionByDraggingFinger; public final int mTouchNoiseThresholdTime; public final int mTouchNoiseThresholdDistance; public final int mSuppressKeyPreviewAfterBatchInputDuration; @@ -142,21 +115,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { public final int mKeyRepeatInterval; public final int mLongPressShiftLockTimeout; - public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); - - private PointerTrackerParams() { - mSlidingKeyInputEnabled = false; - mTouchNoiseThresholdTime = 0; - mTouchNoiseThresholdDistance = 0; - mSuppressKeyPreviewAfterBatchInputDuration = 0; - mKeyRepeatStartTimeout = 0; - mKeyRepeatInterval = 0; - mLongPressShiftLockTimeout = 0; - } - public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) { - mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( - R.styleable.MainKeyboardView_slidingKeyInputEnable, false); + mKeySelectionByDraggingFinger = mainKeyboardViewAttr.getBoolean( + R.styleable.MainKeyboardView_keySelectionByDraggingFinger, false); mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimensionPixelSize( @@ -172,149 +133,36 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } + private static GestureEnabler sGestureEnabler = new GestureEnabler(); + // Parameters for pointer handling. private static PointerTrackerParams sParams; - private static GestureStrokeParams sGestureStrokeParams; - private static GestureStrokePreviewParams sGesturePreviewParams; + private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams; + private static GestureStrokeDrawingParams sGestureStrokeDrawingParams; private static boolean sNeedsPhantomSuddenMoveEventHack; // Move this threshold to resource. // TODO: Device specific parameter would be better for device specific hack? private static final float PHANTOM_SUDDEN_MOVE_THRESHOLD = 0.25f; // in keyWidth - // This hack is applied to certain classes of tablets. - // See {@link #needsProximateBogusDownMoveUpEventHack(Resources)}. - private static boolean sNeedsProximateBogusDownMoveUpEventHack; private static final ArrayList<PointerTracker> sTrackers = CollectionUtils.newArrayList(); private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue(); public final int mPointerId; - private DrawingProxy mDrawingProxy; - private TimerProxy mTimerProxy; - private KeyDetector mKeyDetector; - private KeyboardActionListener mListener = KeyboardActionListener.EMPTY_LISTENER; + private static DrawingProxy sDrawingProxy; + private static TimerProxy sTimerProxy; + private static KeyboardActionListener sListener = KeyboardActionListener.EMPTY_LISTENER; + // The {@link KeyDetector} is set whenever the down event is processed. Also this is updated + // when new {@link Keyboard} is set by {@link #setKeyDetector(KeyDetector)}. + private KeyDetector mKeyDetector = new KeyDetector(); private Keyboard mKeyboard; - private int mPhantonSuddenMoveThreshold; + private int mPhantomSuddenMoveThreshold; private final BogusMoveEventDetector mBogusMoveEventDetector = new BogusMoveEventDetector(); private boolean mIsDetectingGesture = false; // per PointerTracker. private static boolean sInGesture = false; - private static long sGestureFirstDownTime; - private static TimeRecorder sTimeRecorder; - private static final InputPointers sAggregratedPointers = new InputPointers( - GestureStroke.DEFAULT_CAPACITY); - private static int sLastRecognitionPointSize = 0; // synchronized using sAggregratedPointers - private static long sLastRecognitionTime = 0; // synchronized using sAggregratedPointers - - static final class BogusMoveEventDetector { - // Move these thresholds to resource. - // These thresholds' unit is a diagonal length of a key. - private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; - private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; - - private int mAccumulatedDistanceThreshold; - private int mRadiusThreshold; - - // Accumulated distance from actual and artificial down keys. - /* package */ int mAccumulatedDistanceFromDownKey; - private int mActualDownX; - private int mActualDownY; - - public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { - final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); - mAccumulatedDistanceThreshold = (int)( - keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); - mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); - } - - public void onActualDownEvent(final int x, final int y) { - mActualDownX = x; - mActualDownY = y; - } - - public void onDownKey() { - mAccumulatedDistanceFromDownKey = 0; - } - - public void onMoveKey(final int distance) { - mAccumulatedDistanceFromDownKey += distance; - } - - public boolean hasTraveledLongDistance(final int x, final int y) { - final int dx = Math.abs(x - mActualDownX); - final int dy = Math.abs(y - mActualDownY); - // A bogus move event should be a horizontal movement. A vertical movement might be - // a sloppy typing and should be ignored. - return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; - } - - /* package */ int getDistanceFromDownEvent(final int x, final int y) { - return getDistance(x, y, mActualDownX, mActualDownY); - } - - public boolean isCloseToActualDownEvent(final int x, final int y) { - return getDistanceFromDownEvent(x, y) < mRadiusThreshold; - } - } - - static final class TimeRecorder { - private final int mSuppressKeyPreviewAfterBatchInputDuration; - private final int mStaticTimeThresholdAfterFastTyping; // msec - private long mLastTypingTime; - private long mLastLetterTypingTime; - private long mLastBatchInputTime; - - public TimeRecorder(final PointerTrackerParams pointerTrackerParams, - final GestureStrokeParams gestureStrokeParams) { - mSuppressKeyPreviewAfterBatchInputDuration = - pointerTrackerParams.mSuppressKeyPreviewAfterBatchInputDuration; - mStaticTimeThresholdAfterFastTyping = - gestureStrokeParams.mStaticTimeThresholdAfterFastTyping; - } - - public boolean isInFastTyping(final long eventTime) { - final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; - return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; - } - - private boolean wasLastInputTyping() { - return mLastTypingTime >= mLastBatchInputTime; - } - - public void onCodeInput(final int code, final long eventTime) { - // Record the letter typing time when - // 1. Letter keys are typed successively without any batch input in between. - // 2. A letter key is typed within the threshold time since the last any key typing. - // 3. A non-letter key is typed within the threshold time since the last letter key - // typing. - if (Character.isLetter(code)) { - if (wasLastInputTyping() - || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { - mLastLetterTypingTime = eventTime; - } - } else { - if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { - // This non-letter typing should be treated as a part of fast typing. - mLastLetterTypingTime = eventTime; - } - } - mLastTypingTime = eventTime; - } - - public void onEndBatchInput(final long eventTime) { - mLastBatchInputTime = eventTime; - } - - public long getLastLetterTypingTime() { - return mLastLetterTypingTime; - } - - public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { - return !wasLastInputTyping() - && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; - } - } + private static TypingTimeRecorder sTypingTimeRecorder; // The position and time at which first down event occurred. private long mDownTime; @@ -341,92 +189,63 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private MoreKeysPanel mMoreKeysPanel; private static final int MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT = 3; - // true if this pointer is in a sliding key input. - boolean mIsInSlidingKeyInput; - // true if this pointer is in a sliding key input from a modifier key, + // true if this pointer is in the dragging finger mode. + boolean mIsInDraggingFinger; + // true if this pointer is sliding from a modifier key and in the sliding key input mode, // so that further modifier keys should be ignored. - boolean mIsInSlidingKeyInputFromModifier; + boolean mIsInSlidingKeyInput; // if not a NOT_A_CODE, the key of this code is repeating private int mCurrentRepeatingKeyCode = Constants.NOT_A_CODE; - // true if a sliding key input is allowed. - private boolean mIsAllowedSlidingKeyInput; - - private final GestureStrokeWithPreviewPoints mGestureStrokeWithPreviewPoints; - - private static final int SMALL_TABLET_SMALLEST_WIDTH = 600; // dp - private static final int LARGE_TABLET_SMALLEST_WIDTH = 768; // dp - - private static boolean needsProximateBogusDownMoveUpEventHack(final Resources res) { - // The proximate bogus down move up event hack is needed for a device such like, - // 1) is large tablet, or 2) is small tablet and the screen density is less than hdpi. - // Though it seems odd to use screen density as criteria of the quality of the touch - // screen, the small table that has a less density screen than hdpi most likely has been - // made with the touch screen that needs the hack. - final int sw = res.getConfiguration().smallestScreenWidthDp; - final boolean isLargeTablet = (sw >= LARGE_TABLET_SMALLEST_WIDTH); - final boolean isSmallTablet = - (sw >= SMALL_TABLET_SMALLEST_WIDTH && sw < LARGE_TABLET_SMALLEST_WIDTH); - final int densityDpi = res.getDisplayMetrics().densityDpi; - final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH); - final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen); - if (DEBUG_MODE) { - Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack - + " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi); - } - return needsTheHack; - } + // true if dragging finger is allowed. + private boolean mIsAllowedDraggingFinger; - public static void init(final Resources res) { - sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean( - ResourceUtils.getDeviceOverrideValue( - res, R.array.phantom_sudden_move_event_device_list)); - sNeedsProximateBogusDownMoveUpEventHack = needsProximateBogusDownMoveUpEventHack(res); - sParams = PointerTrackerParams.DEFAULT; - sGestureStrokeParams = GestureStrokeParams.DEFAULT; - sGesturePreviewParams = GestureStrokePreviewParams.DEFAULT; - sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); - } + private final BatchInputArbiter mBatchInputArbiter; + private final GestureStrokeDrawingPoints mGestureStrokeDrawingPoints; - public static void setParameters(final TypedArray mainKeyboardViewAttr) { + // TODO: Add PointerTrackerFactory singleton and move some class static methods into it. + public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy timerProxy, + final DrawingProxy drawingProxy) { sParams = new PointerTrackerParams(mainKeyboardViewAttr); - sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr); - sGesturePreviewParams = new GestureStrokePreviewParams(mainKeyboardViewAttr); - sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams); - } + sGestureStrokeRecognitionParams = new GestureStrokeRecognitionParams(mainKeyboardViewAttr); + sGestureStrokeDrawingParams = new GestureStrokeDrawingParams(mainKeyboardViewAttr); + sTypingTimeRecorder = new TypingTimeRecorder( + sGestureStrokeRecognitionParams.mStaticTimeThresholdAfterFastTyping, + sParams.mSuppressKeyPreviewAfterBatchInputDuration); + + final Resources res = mainKeyboardViewAttr.getResources(); + sNeedsPhantomSuddenMoveEventHack = Boolean.parseBoolean( + ResourceUtils.getDeviceOverrideValue(res, + R.array.phantom_sudden_move_event_device_list, Boolean.FALSE.toString())); + BogusMoveEventDetector.init(res); - private static void updateGestureHandlingMode() { - sShouldHandleGesture = sMainDictionaryAvailable - && sGestureHandlingEnabledByInputField - && sGestureHandlingEnabledByUser - && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); + sTimerProxy = timerProxy; + sDrawingProxy = drawingProxy; } // Note that this method is called from a non-UI thread. public static void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { - sMainDictionaryAvailable = mainDictionaryAvailable; - updateGestureHandlingMode(); + sGestureEnabler.setMainDictionaryAvailability(mainDictionaryAvailable); } public static void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { - sGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; - updateGestureHandlingMode(); + sGestureEnabler.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); } - public static PointerTracker getPointerTracker(final int id, final KeyEventHandler handler) { + public static PointerTracker getPointerTracker(final int id) { final ArrayList<PointerTracker> trackers = sTrackers; // Create pointer trackers until we can get 'id+1'-th tracker, if needed. for (int i = trackers.size(); i <= id; i++) { - final PointerTracker tracker = new PointerTracker(i, handler); + final PointerTracker tracker = new PointerTracker(i); trackers.add(tracker); } return trackers.get(id); } - public static boolean isAnyInSlidingKeyInput() { - return sPointerTrackerQueue.isAnyInSlidingKeyInput(); + public static boolean isAnyInDraggingFinger() { + return sPointerTrackerQueue.isAnyInDraggingFinger(); } public static void cancelAllPointerTrackers() { @@ -434,31 +253,27 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } public static void setKeyboardActionListener(final KeyboardActionListener listener) { - final int trackersSize = sTrackers.size(); - for (int i = 0; i < trackersSize; ++i) { - final PointerTracker tracker = sTrackers.get(i); - tracker.mListener = listener; - } + sListener = listener; } public static void setKeyDetector(final KeyDetector keyDetector) { + final Keyboard keyboard = keyDetector.getKeyboard(); + if (keyboard == null) { + return; + } final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); tracker.setKeyDetectorInner(keyDetector); - // Mark that keyboard layout has been changed. - tracker.mKeyboardLayoutHasBeenChanged = true; } - final Keyboard keyboard = keyDetector.getKeyboard(); - sGestureHandlingEnabledByInputField = !keyboard.mId.passwordInput(); - updateGestureHandlingMode(); + sGestureEnabler.setPasswordMode(keyboard.mId.passwordInput()); } public static void setReleasedKeyGraphicsToAllKeys() { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); - tracker.setReleasedKeyGraphics(tracker.mCurrentKey); + tracker.setReleasedKeyGraphics(tracker.getKey()); } } @@ -466,28 +281,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final int trackersSize = sTrackers.size(); for (int i = 0; i < trackersSize; ++i) { final PointerTracker tracker = sTrackers.get(i); - if (tracker.isShowingMoreKeysPanel()) { - tracker.mMoreKeysPanel.dismissMoreKeysPanel(); - tracker.mMoreKeysPanel = null; - } + tracker.dismissMoreKeysPanel(); } } - private PointerTracker(final int id, final KeyEventHandler handler) { - if (handler == null) { - throw new NullPointerException(); - } + private PointerTracker(final int id) { mPointerId = id; - mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints( - id, sGestureStrokeParams, sGesturePreviewParams); - setKeyEventHandler(handler); - } - - private void setKeyEventHandler(final KeyEventHandler handler) { - setKeyDetectorInner(handler.getKeyDetector()); - mListener = handler.getKeyboardActionListener(); - mDrawingProxy = handler.getDrawingProxy(); - mTimerProxy = handler.getTimerProxy(); + mBatchInputArbiter = new BatchInputArbiter(id, sGestureStrokeRecognitionParams); + mGestureStrokeDrawingPoints = new GestureStrokeDrawingPoints(sGestureStrokeDrawingParams); } // Returns true if keyboard has been changed by this callback. @@ -500,10 +301,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { return false; } - final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); + final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onPress : %s%s%s%s", mPointerId, - KeyDetector.printableCode(key), + (key == null ? "none" : Constants.printableCode(key.getCode())), ignoreModifierKey ? " ignoreModifier" : "", key.isEnabled() ? "" : " disabled", repeatCount > 0 ? " repeatCount=" + repeatCount : "")); @@ -512,21 +313,21 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return false; } if (key.isEnabled()) { - mListener.onPressKey(key.getCode(), repeatCount, getActivePointerTrackerCount() == 1); + sListener.onPressKey(key.getCode(), repeatCount, getActivePointerTrackerCount() == 1); final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; mKeyboardLayoutHasBeenChanged = false; - mTimerProxy.startTypingStateTimer(key); + sTimerProxy.startTypingStateTimer(key); return keyboardLayoutHasBeenChanged; } return false; } // Note that we need primaryCode argument because the keyboard may in shifted state and the - // primaryCode is different from {@link Key#mCode}. + // primaryCode is different from {@link Key#mKeyCode}. private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, - final int y, final long eventTime) { - final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); - final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); + final int y, final long eventTime, final boolean isKeyRepeat) { + final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); + final boolean altersCode = key.altCodeWhileTyping() && sTimerProxy.isTypingState(); final int code = altersCode ? key.getAltCode() : primaryCode; if (DEBUG_LISTENER) { final String output = code == Constants.CODE_OUTPUT_TEXT @@ -544,24 +345,29 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. if (key.isEnabled() || altersCode) { - sTimeRecorder.onCodeInput(code, eventTime); + sTypingTimeRecorder.onCodeInput(code, eventTime); if (code == Constants.CODE_OUTPUT_TEXT) { - mListener.onTextInput(key.getOutputText()); + sListener.onTextInput(key.getOutputText()); } else if (code != Constants.CODE_UNSPECIFIED) { - mListener.onCodeInput(code, x, y); + if (mKeyboard.hasProximityCharsCorrection(code)) { + sListener.onCodeInput(code, x, y, isKeyRepeat); + } else { + sListener.onCodeInput(code, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, isKeyRepeat); + } } } } // Note that we need primaryCode argument because the keyboard may be in shifted state and the - // primaryCode is different from {@link Key#mCode}. + // primaryCode is different from {@link Key#mKeyCode}. private void callListenerOnRelease(final Key key, final int primaryCode, final boolean withSliding) { // See the comment at {@link #callListenerOnPressAndCheckKeyboardLayoutChange(Key}}. if (sInGesture || mIsDetectingGesture || mIsTrackingForActionDisabled) { return; } - final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier(); + final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onRelease : %s%s%s%s", mPointerId, Constants.printableCode(primaryCode), @@ -576,7 +382,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } if (key.isEnabled()) { - mListener.onReleaseKey(primaryCode, withSliding); + sListener.onReleaseKey(primaryCode, withSliding); } } @@ -584,7 +390,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onFinishSlidingInput", mPointerId)); } - mListener.onFinishSlidingInput(); + sListener.onFinishSlidingInput(); } private void callListenerOnCancelInput() { @@ -594,33 +400,34 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.pointerTracker_callListenerOnCancelInput(); } - mListener.onCancelInput(); + sListener.onCancelInput(); } private void setKeyDetectorInner(final KeyDetector keyDetector) { final Keyboard keyboard = keyDetector.getKeyboard(); + if (keyboard == null) { + return; + } if (keyDetector == mKeyDetector && keyboard == mKeyboard) { return; } mKeyDetector = keyDetector; - mKeyboard = keyDetector.getKeyboard(); + mKeyboard = keyboard; + // Mark that keyboard layout has been changed. + mKeyboardLayoutHasBeenChanged = true; final int keyWidth = mKeyboard.mMostCommonKeyWidth; final int keyHeight = mKeyboard.mMostCommonKeyHeight; - mGestureStrokeWithPreviewPoints.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); - final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY); - if (newKey != mCurrentKey) { - if (mDrawingProxy != null) { - setReleasedKeyGraphics(mCurrentKey); - } - // Keep {@link #mCurrentKey} that comes from previous keyboard. - } - mPhantonSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); + mBatchInputArbiter.setKeyboardGeometry(keyWidth, mKeyboard.mOccupiedHeight); + // Keep {@link #mCurrentKey} that comes from previous keyboard. The key preview of + // {@link #mCurrentKey} will be dismissed by {@setReleasedKeyGraphics(Key)} via + // {@link onMoveEventInternal(int,int,long)} or {@link #onUpEventInternal(int,int,long)}. + mPhantomSuddenMoveThreshold = (int)(keyWidth * PHANTOM_SUDDEN_MOVE_THRESHOLD); mBogusMoveEventDetector.setKeyboardGeometry(keyWidth, keyHeight); } @Override - public boolean isInSlidingKeyInput() { - return mIsInSlidingKeyInput; + public boolean isInDraggingFinger() { + return mIsInDraggingFinger; } public Key getKey() { @@ -637,7 +444,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void setReleasedKeyGraphics(final Key key) { - mDrawingProxy.dismissKeyPreview(this); + sDrawingProxy.dismissKeyPreview(key); if (key == null) { return; } @@ -668,8 +475,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private static boolean needsToSuppressKeyPreviewPopup(final long eventTime) { - if (!sShouldHandleGesture) return false; - return sTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); + if (!sGestureEnabler.shouldHandleGesture()) return false; + return sTypingTimeRecorder.needsToSuppressKeyPreviewPopup(eventTime); } private void setPressedKeyGraphics(final Key key, final long eventTime) { @@ -678,14 +485,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } // Even if the key is disabled, it should respond if it is in the altCodeWhileTyping state. - final boolean altersCode = key.altCodeWhileTyping() && mTimerProxy.isTypingState(); + final boolean altersCode = key.altCodeWhileTyping() && sTimerProxy.isTypingState(); final boolean needsToUpdateGraphics = key.isEnabled() || altersCode; if (!needsToUpdateGraphics) { return; } if (!key.noKeyPreview() && !sInGesture && !needsToSuppressKeyPreviewPopup(eventTime)) { - mDrawingProxy.showKeyPreview(this); + sDrawingProxy.showKeyPreview(key); } updatePressKeyGraphics(key); @@ -697,7 +504,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } - if (key.altCodeWhileTyping() && mTimerProxy.isTypingState()) { + if (altersCode) { final int altCode = key.getAltCode(); final Key altKey = mKeyboard.getKey(altCode); if (altKey != null) { @@ -711,18 +518,18 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } - private void updateReleaseKeyGraphics(final Key key) { + private static void updateReleaseKeyGraphics(final Key key) { key.onReleased(); - mDrawingProxy.invalidateKey(key); + sDrawingProxy.invalidateKey(key); } - private void updatePressKeyGraphics(final Key key) { + private static void updatePressKeyGraphics(final Key key) { key.onPressed(); - mDrawingProxy.invalidateKey(key); + sDrawingProxy.invalidateKey(key); } - public GestureStrokeWithPreviewPoints getGestureStrokeWithPreviewPoints() { - return mGestureStrokeWithPreviewPoints; + public GestureStrokeDrawingPoints getGestureStrokeDrawingPoints() { + return mGestureStrokeDrawingPoints; } public void getLastCoordinates(final int[] outCoords) { @@ -744,7 +551,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); } - static int getDistance(final int x1, final int y1, final int x2, final int y2) { + private static int getDistance(final int x1, final int y1, final int x2, final int y2) { return (int)Math.hypot(x1 - x2, y1 - y2); } @@ -766,7 +573,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return newKey; } - private static int getActivePointerTrackerCount() { + /* package */ static int getActivePointerTrackerCount() { return sPointerTrackerQueue.size(); } @@ -774,91 +581,59 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return sPointerTrackerQueue.getOldestElement() == this; } - private void mayStartBatchInput(final Key key) { - if (sInGesture || !mGestureStrokeWithPreviewPoints.isStartOfAGesture()) { - return; - } - if (key == null || !Character.isLetter(key.getCode())) { - return; - } + // Implements {@link BatchInputArbiterListener}. + @Override + public void onStartBatchInput() { if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onStartBatchInput", mPointerId)); } - sInGesture = true; - synchronized (sAggregratedPointers) { - sAggregratedPointers.reset(); - sLastRecognitionPointSize = 0; - sLastRecognitionTime = 0; - mListener.onStartBatchInput(); - dismissAllMoreKeysPanels(); - } - mTimerProxy.cancelLongPressTimer(); - // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. - mDrawingProxy.showGestureTrail( - this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); - } - - public void updateBatchInputByTimer(final long eventTime) { - final int gestureTime = (int)(eventTime - sGestureFirstDownTime); - mGestureStrokeWithPreviewPoints.duplicateLastPointWith(gestureTime); - updateBatchInput(eventTime); + sListener.onStartBatchInput(); + dismissAllMoreKeysPanels(); + sTimerProxy.cancelLongPressTimerOf(this); } - private void mayUpdateBatchInput(final long eventTime, final Key key) { - if (key != null) { - updateBatchInput(eventTime); - } + private void showGestureTrail() { if (mIsTrackingForActionDisabled) { return; } // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. - mDrawingProxy.showGestureTrail( + sDrawingProxy.showGestureTrail( this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); } - private void updateBatchInput(final long eventTime) { - synchronized (sAggregratedPointers) { - final GestureStroke stroke = mGestureStrokeWithPreviewPoints; - stroke.appendIncrementalBatchPoints(sAggregratedPointers); - final int size = sAggregratedPointers.getPointerSize(); - if (size > sLastRecognitionPointSize - && stroke.hasRecognitionTimePast(eventTime, sLastRecognitionTime)) { - if (DEBUG_LISTENER) { - Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, - size)); - } - mTimerProxy.startUpdateBatchInputTimer(this); - mListener.onUpdateBatchInput(sAggregratedPointers); - // The listener may change the size of the pointers (when auto-committing - // for example), so we need to get the size from the pointers again. - sLastRecognitionPointSize = sAggregratedPointers.getPointerSize(); - sLastRecognitionTime = eventTime; - } - } + public void updateBatchInputByTimer(final long syntheticMoveEventTime) { + mBatchInputArbiter.updateBatchInputByTimer(syntheticMoveEventTime, this); } - private void mayEndBatchInput(final long eventTime) { - synchronized (sAggregratedPointers) { - mGestureStrokeWithPreviewPoints.appendAllBatchPoints(sAggregratedPointers); - if (getActivePointerTrackerCount() == 1) { - sInGesture = false; - sTimeRecorder.onEndBatchInput(eventTime); - mTimerProxy.cancelAllUpdateBatchInputTimers(); - if (!mIsTrackingForActionDisabled) { - if (DEBUG_LISTENER) { - Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", - mPointerId, sAggregratedPointers.getPointerSize())); - } - mListener.onEndBatchInput(sAggregratedPointers); - } - } + // Implements {@link BatchInputArbiterListener}. + @Override + public void onUpdateBatchInput(final InputPointers aggregatedPointers, final long eventTime) { + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onUpdateBatchInput: batchPoints=%d", mPointerId, + aggregatedPointers.getPointerSize())); } + sListener.onUpdateBatchInput(aggregatedPointers); + } + + // Implements {@link BatchInputArbiterListener}. + @Override + public void onStartUpdateBatchInputTimer() { + sTimerProxy.startUpdateBatchInputTimer(this); + } + + // Implements {@link BatchInputArbiterListener}. + @Override + public void onEndBatchInput(final InputPointers aggregatedPointers, final long eventTime) { + sTypingTimeRecorder.onEndBatchInput(eventTime); + sTimerProxy.cancelAllUpdateBatchInputTimers(); if (mIsTrackingForActionDisabled) { return; } - // A gesture floating preview text will be shown at the oldest pointer/finger on the screen. - mDrawingProxy.showGestureTrail( - this, isOldestTrackerInQueue() /* showsFloatingPreviewText */); + if (DEBUG_LISTENER) { + Log.d(TAG, String.format("[%d] onEndBatchInput : batchPoints=%d", + mPointerId, aggregatedPointers.getPointerSize())); + } + sListener.onEndBatchInput(aggregatedPointers); } private void cancelBatchInput() { @@ -871,19 +646,26 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (DEBUG_LISTENER) { Log.d(TAG, String.format("[%d] onCancelBatchInput", mPointerId)); } - mListener.onCancelBatchInput(); + sListener.onCancelBatchInput(); } - public void processMotionEvent(final MotionEvent me, final KeyEventHandler handler) { + public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) { final int action = me.getActionMasked(); final long eventTime = me.getEventTime(); if (action == MotionEvent.ACTION_MOVE) { + // When this pointer is the only active pointer and is showing a more keys panel, + // we should ignore other pointers' motion event. + final boolean shouldIgnoreOtherPointers = + isShowingMoreKeysPanel() && getActivePointerTrackerCount() == 1; final int pointerCount = me.getPointerCount(); for (int index = 0; index < pointerCount; index++) { final int id = me.getPointerId(index); - final PointerTracker tracker = getPointerTracker(id, handler); + if (shouldIgnoreOtherPointers && id != mPointerId) { + continue; + } final int x = (int)me.getX(index); final int y = (int)me.getY(index); + final PointerTracker tracker = getPointerTracker(id); tracker.onMoveEvent(x, y, eventTime, me); } return; @@ -894,7 +676,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: - onDownEvent(x, y, eventTime, handler); + onDownEvent(x, y, eventTime, keyDetector); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: @@ -907,11 +689,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void onDownEvent(final int x, final int y, final long eventTime, - final KeyEventHandler handler) { + final KeyDetector keyDetector) { if (DEBUG_EVENT) { printTouchEvent("onDownEvent:", x, y, eventTime); } - setKeyEventHandler(handler); + setKeyDetectorInner(keyDetector); // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; if (deltaT < sParams.mTouchNoiseThresholdTime) { @@ -938,7 +720,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } sPointerTrackerQueue.add(this); onDownEventInternal(x, y, eventTime); - if (!sShouldHandleGesture) { + if (!sGestureEnabler.shouldHandleGesture()) { return; } // A gesture should start only from a non-modifier key. Note that the gesture detection is @@ -946,28 +728,36 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard() && key != null && !key.isModifier(); if (mIsDetectingGesture) { - if (getActivePointerTrackerCount() == 1) { - sGestureFirstDownTime = eventTime; - } - mGestureStrokeWithPreviewPoints.onDownEvent(x, y, eventTime, sGestureFirstDownTime, - sTimeRecorder.getLastLetterTypingTime()); + mBatchInputArbiter.addDownEventPoint(x, y, eventTime, + sTypingTimeRecorder.getLastLetterTypingTime(), getActivePointerTrackerCount()); + mGestureStrokeDrawingPoints.onDownEvent( + x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); } } - private boolean isShowingMoreKeysPanel() { + /* package */ boolean isShowingMoreKeysPanel() { return (mMoreKeysPanel != null); } + private void dismissMoreKeysPanel() { + if (isShowingMoreKeysPanel()) { + mMoreKeysPanel.dismissMoreKeysPanel(); + mMoreKeysPanel = null; + } + } + private void onDownEventInternal(final int x, final int y, final long 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 = sParams.mSlidingKeyInputEnabled + // Key selection by dragging finger is allowed when 1) key selection by dragging finger is + // enabled by configuration, 2) this pointer starts dragging from modifier key, or 3) this + // pointer's KeyDetector always allows key selection by dragging finger, such as + // {@link MoreKeysKeyboard}. + mIsAllowedDraggingFinger = sParams.mKeySelectionByDraggingFinger || (key != null && key.isModifier()) - || mKeyDetector.alwaysAllowsSlidingInput(); + || mKeyDetector.alwaysAllowsKeySelectionByDraggingFinger(); mKeyboardLayoutHasBeenChanged = false; mIsTrackingForActionDisabled = false; - resetSlidingKeyInput(); + resetKeySelectionByDraggingFinger(); if (key != null) { // This onPress call may have changed keyboard layout. Those cases are detected at // {@link #setKeyboard}. In those cases, we should update key according to the new @@ -982,43 +772,47 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } - private void startSlidingKeyInput(final Key key) { - if (!mIsInSlidingKeyInput) { - mIsInSlidingKeyInputFromModifier = key.isModifier(); + private void startKeySelectionByDraggingFinger(final Key key) { + if (!mIsInDraggingFinger) { + mIsInSlidingKeyInput = key.isModifier(); } - mIsInSlidingKeyInput = true; + mIsInDraggingFinger = true; } - private void resetSlidingKeyInput() { + private void resetKeySelectionByDraggingFinger() { + mIsInDraggingFinger = false; mIsInSlidingKeyInput = false; - mIsInSlidingKeyInputFromModifier = false; - mDrawingProxy.dismissSlidingKeyInputPreview(); + sDrawingProxy.dismissSlidingKeyInputPreview(); } private void onGestureMoveEvent(final int x, final int y, final long eventTime, final boolean isMajorEvent, final Key key) { - final int gestureTime = (int)(eventTime - sGestureFirstDownTime); - if (mIsDetectingGesture) { - final int beforeLength = mGestureStrokeWithPreviewPoints.getLength(); - final boolean onValidArea = mGestureStrokeWithPreviewPoints.addPointOnKeyboard( - x, y, gestureTime, isMajorEvent); - if (mGestureStrokeWithPreviewPoints.getLength() > beforeLength) { - mTimerProxy.startUpdateBatchInputTimer(this); - } - // If the move event goes out from valid batch input area, cancel batch input. - if (!onValidArea) { - cancelBatchInput(); - return; - } - // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, - // the gestured touch points are still being recorded in case the panel is dismissed. - if (isShowingMoreKeysPanel()) { - return; - } - mayStartBatchInput(key); - if (sInGesture) { - mayUpdateBatchInput(eventTime, key); + if (!mIsDetectingGesture) { + return; + } + final boolean onValidArea = mBatchInputArbiter.addMoveEventPoint( + x, y, eventTime, isMajorEvent, this); + // If the move event goes out from valid batch input area, cancel batch input. + if (!onValidArea) { + cancelBatchInput(); + return; + } + mGestureStrokeDrawingPoints.onMoveEvent( + x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime)); + // If the MoreKeysPanel is showing then do not attempt to enter gesture mode. However, + // the gestured touch points are still being recorded in case the panel is dismissed. + if (isShowingMoreKeysPanel()) { + return; + } + if (!sInGesture && key != null && Character.isLetter(key.getCode()) + && mBatchInputArbiter.mayStartBatchInput(this)) { + sInGesture = true; + } + if (sInGesture) { + if (key != null) { + mBatchInputArbiter.updateBatchInput(eventTime, this); } + showGestureTrail(); } } @@ -1030,7 +824,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } - if (sShouldHandleGesture && me != null) { + if (sGestureEnabler.shouldHandleGesture() && me != null) { // Add historical points to gesture path. final int pointerIndex = me.findPointerIndex(mPointerId); final int historicalSize = me.getHistorySize(); @@ -1048,15 +842,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final int translatedY = mMoreKeysPanel.translateY(y); mMoreKeysPanel.onMoveEvent(translatedX, translatedY, mPointerId, eventTime); onMoveKey(x, y); - if (mIsInSlidingKeyInputFromModifier) { - mDrawingProxy.showSlidingKeyInputPreview(this); + if (mIsInSlidingKeyInput) { + sDrawingProxy.showSlidingKeyInputPreview(this); } return; } onMoveEventInternal(x, y, eventTime); } - private void processSlidingKeyInput(final Key newKey, final int x, final int y, + private void processDraggingFingerInToNewKey(final Key newKey, final int x, final int y, final long eventTime) { // This onPress call may have changed keyboard layout. Those cases are detected // at {@link #setKeyboard}. In those cases, we should update key according @@ -1110,35 +904,35 @@ public final class PointerTracker implements PointerTrackerQueue.Element { onDownEventInternal(x, y, eventTime); } - private void processSildeOutFromOldKey(final Key oldKey) { + private void processDraggingFingerOutFromOldKey(final Key oldKey) { setReleasedKeyGraphics(oldKey); callListenerOnRelease(oldKey, oldKey.getCode(), true /* withSliding */); - startSlidingKeyInput(oldKey); - mTimerProxy.cancelKeyTimers(); + startKeySelectionByDraggingFinger(oldKey); + sTimerProxy.cancelKeyTimersOf(this); } - private void slideFromOldKeyToNewKey(final Key key, final int x, final int y, + private void dragFingerFromOldKeyToNewKey(final Key key, final int x, final int y, final long eventTime, final Key oldKey, final int lastX, final int lastY) { // 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. - processSildeOutFromOldKey(oldKey); + processDraggingFingerOutFromOldKey(oldKey); startRepeatKey(key); - if (mIsAllowedSlidingKeyInput) { - processSlidingKeyInput(key, x, y, eventTime); + if (mIsAllowedDraggingFinger) { + processDraggingFingerInToNewKey(key, x, y, eventTime); } // HACK: On some devices, quick successive touches may be reported as a sudden move by // touch panel firmware. This hack detects such cases and translates the move event to // successive up and down events. // TODO: Should find a way to balance gesture detection and this hack. else if (sNeedsPhantomSuddenMoveEventHack - && getDistance(x, y, lastX, lastY) >= mPhantonSuddenMoveThreshold) { + && getDistance(x, y, lastX, lastY) >= mPhantomSuddenMoveThreshold) { processPhantomSuddenMoveHack(key, x, y, eventTime, oldKey, lastX, lastY); } // HACK: On some devices, quick successive proximate touches may be reported as a bogus // down-move-up event by touch panel firmware. This hack detects such cases and breaks // these events into separate up and down events. - else if (sNeedsProximateBogusDownMoveUpEventHack && sTimeRecorder.isInFastTyping(eventTime) + else if (sTypingTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.isCloseToActualDownEvent(x, y)) { processProximateBogusDownMoveUpEventHack(key, x, y, eventTime, oldKey, lastX, lastY); } @@ -1163,11 +957,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } } - private void slideOutFromOldKey(final Key oldKey, final int x, final int y) { + private void dragFingerOutFromOldKey(final Key oldKey, final int x, final int y) { // The pointer has been slid out from the previous key, we must call onRelease() to // notify that the previous key has been released. - processSildeOutFromOldKey(oldKey); - if (mIsAllowedSlidingKeyInput) { + processDraggingFingerOutFromOldKey(oldKey); + if (mIsAllowedDraggingFinger) { onMoveToNewKey(null, x, y); } else { if (!mIsDetectingGesture) { @@ -1182,7 +976,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { final Key oldKey = mCurrentKey; final Key newKey = onMoveKey(x, y); - if (sShouldHandleGesture) { + if (sGestureEnabler.shouldHandleGesture()) { // Register move event on gesture tracker. onGestureMoveEvent(x, y, eventTime, true /* isMajorEvent */, newKey); if (sInGesture) { @@ -1194,19 +988,19 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (newKey != null) { if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { - slideFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); + dragFingerFromOldKeyToNewKey(newKey, x, y, eventTime, oldKey, lastX, lastY); } else 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. - processSlidingKeyInput(newKey, x, y, eventTime); + processDraggingFingerInToNewKey(newKey, x, y, eventTime); } } else { // newKey == null if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, eventTime, newKey)) { - slideOutFromOldKey(oldKey, x, y); + dragFingerOutFromOldKey(oldKey, x, y); } } - if (mIsInSlidingKeyInputFromModifier) { - mDrawingProxy.showSlidingKeyInputPreview(this); + if (mIsInSlidingKeyInput) { + sDrawingProxy.showSlidingKeyInputPreview(this); } } @@ -1215,7 +1009,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { printTouchEvent("onUpEvent :", x, y, eventTime); } - mTimerProxy.cancelUpdateBatchInputTimer(this); + sTimerProxy.cancelUpdateBatchInputTimer(this); if (!sInGesture) { if (mCurrentKey != null && mCurrentKey.isModifier()) { // Before processing an up event of modifier key, all pointers already being @@ -1237,18 +1031,15 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (DEBUG_EVENT) { printTouchEvent("onPhntEvent:", mLastX, mLastY, eventTime); } - if (isShowingMoreKeysPanel()) { - return; - } onUpEventInternal(mLastX, mLastY, eventTime); cancelTrackingForAction(); } private void onUpEventInternal(final int x, final int y, final long eventTime) { - mTimerProxy.cancelKeyTimers(); + sTimerProxy.cancelKeyTimersOf(this); + final boolean isInDraggingFinger = mIsInDraggingFinger; final boolean isInSlidingKeyInput = mIsInSlidingKeyInput; - final boolean isInSlidingKeyInputFromModifier = mIsInSlidingKeyInputFromModifier; - resetSlidingKeyInput(); + resetKeySelectionByDraggingFinger(); mIsDetectingGesture = false; final Key currentKey = mCurrentKey; mCurrentKey = null; @@ -1272,7 +1063,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (currentKey != null) { callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */); } - mayEndBatchInput(eventTime); + if (mBatchInputArbiter.mayEndBatchInput( + eventTime, getActivePointerTrackerCount(), this)) { + sInGesture = false; + } + showGestureTrail(); return; } @@ -1280,11 +1075,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element { return; } if (currentKey != null && currentKey.isRepeatable() - && (currentKey.getCode() == currentRepeatingKeyCode) && !isInSlidingKeyInput) { + && (currentKey.getCode() == currentRepeatingKeyCode) && !isInDraggingFinger) { return; } detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime); - if (isInSlidingKeyInputFromModifier) { + if (isInSlidingKeyInput) { callListenerOnFinishSlidingInput(); } } @@ -1306,7 +1101,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } public void onLongPressed() { - resetSlidingKeyInput(); + resetKeySelectionByDraggingFinger(); cancelTrackingForAction(); setReleasedKeyGraphics(mCurrentKey); sPointerTrackerQueue.remove(this); @@ -1324,9 +1119,9 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void onCancelEventInternal() { - mTimerProxy.cancelKeyTimers(); + sTimerProxy.cancelKeyTimersOf(this); setReleasedKeyGraphics(mCurrentKey); - resetSlidingKeyInput(); + resetKeySelectionByDraggingFinger(); if (isShowingMoreKeysPanel()) { mMoreKeysPanel.dismissMoreKeysPanel(); mMoreKeysPanel = null; @@ -1335,9 +1130,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element { private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime, final Key newKey) { - if (mKeyDetector == null) { - throw new NullPointerException("keyboard and/or key detector not set"); - } final Key curKey = mCurrentKey; if (newKey == curKey) { return false; @@ -1347,7 +1139,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } // Here curKey points to the different key from newKey. final int keyHysteresisDistanceSquared = mKeyDetector.getKeyHysteresisDistanceSquared( - mIsInSlidingKeyInputFromModifier); + mIsInSlidingKeyInput); final int distanceFromKeyEdgeSquared = curKey.squaredDistanceToEdge(x, y); if (distanceFromKeyEdgeSquared >= keyHysteresisDistanceSquared) { if (DEBUG_MODE) { @@ -1358,14 +1150,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } return true; } - if (sNeedsProximateBogusDownMoveUpEventHack && !mIsAllowedSlidingKeyInput - && sTimeRecorder.isInFastTyping(eventTime) + if (!mIsAllowedDraggingFinger && sTypingTimeRecorder.isInFastTyping(eventTime) && mBogusMoveEventDetector.hasTraveledLongDistance(x, y)) { if (DEBUG_MODE) { final float keyDiagonal = (float)Math.hypot( mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight); final float lengthFromDownRatio = - mBogusMoveEventDetector.mAccumulatedDistanceFromDownKey / keyDiagonal; + mBogusMoveEventDetector.getAccumulatedDistanceFromDownKey() / keyDiagonal; Log.d(TAG, String.format("[%d] isMajorEnoughMoveToBeOnNewKey:" + " %.2f key diagonal from virtual down point", mPointerId, lengthFromDownRatio)); @@ -1376,30 +1167,34 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } private void startLongPressTimer(final Key key) { + // Note that we need to cancel all active long press shift key timers if any whenever we + // start a new long press timer for both non-shift and shift keys. + sTimerProxy.cancelLongPressShiftKeyTimers(); if (sInGesture) return; if (key == null) return; if (!key.isLongPressEnabled()) return; // Caveat: Please note that isLongPressEnabled() can be true even if the current key - // doesn't have its more keys. (e.g. spacebar, globe key) + // doesn't have its more keys. (e.g. spacebar, globe key) If we are in the dragging finger + // mode, we will disable long press timer of such key. // We always need to start the long press timer if the key has its more keys regardless of - // whether or not we are in the sliding input mode. - if (mIsInSlidingKeyInput && key.getMoreKeys() == null) return; - final int delay; - switch (key.getCode()) { - case Constants.CODE_SHIFT: - delay = sParams.mLongPressShiftLockTimeout; - break; - default: - final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout; - if (mIsInSlidingKeyInputFromModifier) { - // We use longer timeout for sliding finger input started from the modifier key. - delay = longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT; - } else { - delay = longpressTimeout; - } - break; + // whether or not we are in the dragging finger mode. + if (mIsInDraggingFinger && key.getMoreKeys() == null) return; + + final int delay = getLongPressTimeout(key.getCode()); + if (delay <= 0) return; + sTimerProxy.startLongPressTimerOf(this, delay); + } + + private int getLongPressTimeout(final int code) { + if (code == Constants.CODE_SHIFT) { + return sParams.mLongPressShiftLockTimeout; + } + final int longpressTimeout = Settings.getInstance().getCurrent().mKeyLongpressTimeout; + if (mIsInSlidingKeyInput) { + // We use longer timeout for sliding finger input started from the modifier key. + return longpressTimeout * MULTIPLIER_FOR_LONG_PRESS_TIMEOUT_IN_SLIDING_INPUT; } - mTimerProxy.startLongPressTimer(this, delay); + return longpressTimeout; } private void detectAndSendKey(final Key key, final int x, final int y, final long eventTime) { @@ -1409,7 +1204,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element { } final int code = key.getCode(); - callListenerOnCodeInput(key, code, x, y, eventTime); + callListenerOnCodeInput(key, code, x, y, eventTime, false /* isKeyRepeat */); callListenerOnRelease(key, code, false /* withSliding */); } @@ -1417,10 +1212,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element { if (sInGesture) return; if (key == null) return; if (!key.isRepeatable()) return; - // Don't start key repeat when we are in sliding input mode. - if (mIsInSlidingKeyInput) return; + // Don't start key repeat when we are in the dragging finger mode. + if (mIsInDraggingFinger) return; final int startRepeatCount = 1; - mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout); + startKeyRepeatTimer(startRepeatCount); } public void onKeyRepeat(final int code, final int repeatCount) { @@ -1432,15 +1227,22 @@ public final class PointerTracker implements PointerTrackerQueue.Element { mCurrentRepeatingKeyCode = code; mIsDetectingGesture = false; final int nextRepeatCount = repeatCount + 1; - mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval); + startKeyRepeatTimer(nextRepeatCount); callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount); - callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis()); + callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis(), + true /* isKeyRepeat */); + } + + private void startKeyRepeatTimer(final int repeatCount) { + final int delay = + (repeatCount == 1) ? sParams.mKeyRepeatStartTimeout : sParams.mKeyRepeatInterval; + sTimerProxy.startKeyRepeatTimerOf(this, repeatCount, delay); } private void printTouchEvent(final String title, final int x, final int y, final long eventTime) { final Key key = mKeyDetector.detectHitKey(x, y); - final String code = KeyDetector.printableCode(key); + final String code = (key == null ? "none" : Constants.printableCode(key.getCode())); Log.d(TAG, String.format("[%d]%s%s %4d %4d %5d %s", mPointerId, (mIsTrackingForActionDisabled ? "-" : " "), title, x, y, eventTime, code)); } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index a0316696c..c89bda40e 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -22,9 +22,13 @@ import android.util.Log; import com.android.inputmethod.keyboard.internal.TouchPositionCorrection; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.JniUtils; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; public class ProximityInfo { private static final String TAG = ProximityInfo.class.getSimpleName(); @@ -34,7 +38,7 @@ 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 final float SEARCH_DISTANCE = 1.2f; - private static final Key[] EMPTY_KEY_ARRAY = new Key[0]; + private static final List<Key> EMPTY_KEY_LIST = Collections.emptyList(); private static final float DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS = 0.15f; private final int mGridWidth; @@ -47,13 +51,13 @@ public class ProximityInfo { private final int mKeyboardHeight; private final int mMostCommonKeyWidth; private final int mMostCommonKeyHeight; - private final Key[] mKeys; - private final Key[][] mGridNeighbors; + private final List<Key> mSortedKeys; + private final List<Key>[] mGridNeighbors; private final String mLocaleStr; ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight, final int minWidth, final int height, final int mostCommonKeyWidth, - final int mostCommonKeyHeight, final Key[] keys, + final int mostCommonKeyHeight, final List<Key> sortedKeys, final TouchPositionCorrection touchPositionCorrection) { if (TextUtils.isEmpty(localeStr)) { mLocaleStr = ""; @@ -69,8 +73,8 @@ public class ProximityInfo { mKeyboardHeight = height; mMostCommonKeyHeight = mostCommonKeyHeight; mMostCommonKeyWidth = mostCommonKeyWidth; - mKeys = keys; - mGridNeighbors = new Key[mGridSize][]; + mSortedKeys = sortedKeys; + mGridNeighbors = new List[mGridSize]; if (minWidth == 0 || height == 0) { // No proximity required. Keyboard might be more keys keyboard. return; @@ -99,7 +103,7 @@ public class ProximityInfo { return key.getCode() >= Constants.CODE_SPACE; } - private static int getProximityInfoKeysCount(final Key[] keys) { + private static int getProximityInfoKeysCount(final List<Key> keys) { int count = 0; for (final Key key : keys) { if (needsProximityInfo(key)) { @@ -110,14 +114,15 @@ public class ProximityInfo { } private long createNativeProximityInfo(final TouchPositionCorrection touchPositionCorrection) { - final Key[][] gridNeighborKeys = mGridNeighbors; + final List<Key>[] gridNeighborKeys = mGridNeighbors; final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE); for (int i = 0; i < mGridSize; ++i) { - final int proximityCharsLength = gridNeighborKeys[i].length; + final List<Key> neighborKeys = gridNeighborKeys[i]; + final int proximityCharsLength = neighborKeys.size(); int infoIndex = i * MAX_PROXIMITY_CHARS_SIZE; for (int j = 0; j < proximityCharsLength; ++j) { - final Key neighborKey = gridNeighborKeys[i][j]; + final Key neighborKey = neighborKeys.get(j); // Excluding from proximityCharsArray if (!needsProximityInfo(neighborKey)) { continue; @@ -142,8 +147,8 @@ public class ProximityInfo { } } - final Key[] keys = mKeys; - final int keyCount = getProximityInfoKeysCount(keys); + final List<Key> sortedKeys = mSortedKeys; + final int keyCount = getProximityInfoKeysCount(sortedKeys); final int[] keyXCoordinates = new int[keyCount]; final int[] keyYCoordinates = new int[keyCount]; final int[] keyWidths = new int[keyCount]; @@ -153,8 +158,8 @@ public class ProximityInfo { final float[] sweetSpotCenterYs; final float[] sweetSpotRadii; - for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) { - final Key key = keys[keyIndex]; + for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) { + final Key key = sortedKeys.get(keyIndex); // Excluding from key coordinate arrays if (!needsProximityInfo(key)) { continue; @@ -177,8 +182,8 @@ public class ProximityInfo { final int rows = touchPositionCorrection.getRows(); final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS * (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight); - for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) { - final Key key = keys[keyIndex]; + for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) { + final Key key = sortedKeys.get(keyIndex); // Excluding from touch position correction arrays if (!needsProximityInfo(key)) { continue; @@ -240,7 +245,7 @@ public class ProximityInfo { private void computeNearestNeighbors() { final int defaultWidth = mMostCommonKeyWidth; - final int keyCount = mKeys.length; + final int keyCount = mSortedKeys.size(); final int gridSize = mGridNeighbors.length; final int threshold = (int) (defaultWidth * SEARCH_DISTANCE); final int thresholdSquared = threshold * threshold; @@ -259,7 +264,7 @@ public class ProximityInfo { final int[] neighborCountPerCell = new int[gridSize]; final int halfCellWidth = mCellWidth / 2; final int halfCellHeight = mCellHeight / 2; - for (final Key key : mKeys) { + for (final Key key : mSortedKeys) { if (key.isSpacer()) continue; /* HOW WE PRE-SELECT THE CELLS (iterate over only the relevant cells, instead of all of them) @@ -353,9 +358,13 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get } for (int i = 0; i < gridSize; ++i) { - final int base = i * keyCount; - mGridNeighbors[i] = - Arrays.copyOfRange(neighborsFlatBuffer, base, base + neighborCountPerCell[i]); + final int indexStart = i * keyCount; + final int indexEnd = indexStart + neighborCountPerCell[i]; + final ArrayList<Key> neighbors = CollectionUtils.newArrayList(indexEnd - indexStart); + for (int index = indexStart; index < indexEnd; index++) { + neighbors.add(neighborsFlatBuffer[index]); + } + mGridNeighbors[i] = Collections.unmodifiableList(neighbors); } } @@ -369,7 +378,7 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get if (primaryKeyCode > Constants.CODE_SPACE) { dest[index++] = primaryKeyCode; } - final Key[] nearestKeys = getNearestKeys(x, y); + final List<Key> nearestKeys = getNearestKeys(x, y); for (Key key : nearestKeys) { if (index >= destLength) { break; @@ -385,9 +394,9 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get } } - public Key[] getNearestKeys(final int x, final int y) { + public List<Key> getNearestKeys(final int x, final int y) { if (mGridNeighbors == null) { - return EMPTY_KEY_ARRAY; + return EMPTY_KEY_LIST; } if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); @@ -395,6 +404,6 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get return mGridNeighbors[index]; } } - return EMPTY_KEY_ARRAY; + return EMPTY_KEY_LIST; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java index b814fc162..3a72aed0d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java @@ -22,36 +22,47 @@ import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; /** - * Abstract base class for previews that are drawn on PreviewPlacerView, e.g., - * GestureFloatingPrevewText, GestureTrail, and SlidingKeyInputPreview. + * Abstract base class for previews that are drawn on DrawingPreviewPlacerView, e.g., + * GestureFloatingTextDrawingPreview, GestureTrailsDrawingPreview, and + * SlidingKeyInputDrawingPreview. */ public abstract class AbstractDrawingPreview { private final View mDrawingView; private boolean mPreviewEnabled; + private boolean mHasValidGeometry; protected AbstractDrawingPreview(final View drawingView) { mDrawingView = drawingView; } - public final View getDrawingView() { + protected final View getDrawingView() { return mDrawingView; } - public final void setPreviewEnabled(final boolean enabled) { - mPreviewEnabled = enabled; + protected final boolean isPreviewEnabled() { + return mPreviewEnabled && mHasValidGeometry; } - public boolean isPreviewEnabled() { - return mPreviewEnabled; + public final void setPreviewEnabled(final boolean enabled) { + mPreviewEnabled = enabled; } - public void setKeyboardGeometry(final int[] originCoords, final int width, final int height) { - // Default implementation is empty. + /** + * Set {@link MainKeyboardView} geometry and position in the {@link SoftInputWindow}. + * The class that is overriding this method must call this super implementation. + * + * @param originCoords the top-left coordinates of the {@link MainKeyboardView} in + * {@link SoftInputWindow} coordinate-system. This is unused but has a point in an + * extended class, such as {@link GestureTrailsDrawingPreview}. + * @param width the width of {@link MainKeyboardView}. + * @param height the height of {@link MainKeyboardView}. + */ + public void setKeyboardViewGeometry(final int[] originCoords, final int width, + final int height) { + mHasValidGeometry = (width > 0 && height > 0); } - public void onDetachFromWindow() { - // Default implementation is empty. - } + public abstract void onDeallocateMemory(); /** * Draws the preview diff --git a/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java new file mode 100644 index 000000000..cd9875955 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2013 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.latin.Constants; +import com.android.inputmethod.latin.InputPointers; + +/** + * This class arbitrates batch input. + * An instance of this class holds a {@link GestureStrokeRecognitionPoints}. + * And it arbitrates multiple strokes gestured by multiple fingers and aggregates those gesture + * points into one batch input. + */ +public class BatchInputArbiter { + public interface BatchInputArbiterListener { + public void onStartBatchInput(); + public void onUpdateBatchInput( + final InputPointers aggregatedPointers, final long moveEventTime); + public void onStartUpdateBatchInputTimer(); + public void onEndBatchInput(final InputPointers aggregatedPointers, final long upEventTime); + } + + // The starting time of the first stroke of a gesture input. + private static long sGestureFirstDownTime; + // The {@link InputPointers} that includes all events of a gesture input. + private static final InputPointers sAggregatedPointers = new InputPointers( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private static int sLastRecognitionPointSize = 0; // synchronized using sAggregatedPointers + private static long sLastRecognitionTime = 0; // synchronized using sAggregatedPointers + + private final GestureStrokeRecognitionPoints mRecognitionPoints; + + public BatchInputArbiter(final int pointerId, final GestureStrokeRecognitionParams params) { + mRecognitionPoints = new GestureStrokeRecognitionPoints(pointerId, params); + } + + public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { + mRecognitionPoints.setKeyboardGeometry(keyWidth, keyboardHeight); + } + + /** + * Calculate elapsed time since the first gesture down. + * @param eventTime the time of this event. + * @return the elapsed time in millisecond from the first gesture down. + */ + public int getElapsedTimeSinceFirstDown(final long eventTime) { + return (int)(eventTime - sGestureFirstDownTime); + } + + /** + * Add a down event point. + * @param x the x-coordinate of this down event. + * @param y the y-coordinate of this down event. + * @param downEventTime the time of this down event. + * @param lastLetterTypingTime the last typing input time. + * @param activePointerCount the number of active pointers when this pointer down event occurs. + */ + public void addDownEventPoint(final int x, final int y, final long downEventTime, + final long lastLetterTypingTime, final int activePointerCount) { + if (activePointerCount == 1) { + sGestureFirstDownTime = downEventTime; + } + final int elapsedTimeSinceFirstDown = getElapsedTimeSinceFirstDown(downEventTime); + final int elapsedTimeSinceLastTyping = (int)(downEventTime - lastLetterTypingTime); + mRecognitionPoints.addDownEventPoint( + x, y, elapsedTimeSinceFirstDown, elapsedTimeSinceLastTyping); + } + + /** + * Add a move event point. + * @param x the x-coordinate of this move event. + * @param y the y-coordinate of this move event. + * @param moveEventTime the time of this move event. + * @param isMajorEvent false if this is a historical move event. + * @param listener {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} of this + * <code>listener</code> may be called if enough move points have been added. + * @return true if this move event occurs on the valid gesture area. + */ + public boolean addMoveEventPoint(final int x, final int y, final long moveEventTime, + final boolean isMajorEvent, final BatchInputArbiterListener listener) { + final int beforeLength = mRecognitionPoints.getLength(); + final boolean onValidArea = mRecognitionPoints.addEventPoint( + x, y, getElapsedTimeSinceFirstDown(moveEventTime), isMajorEvent); + if (mRecognitionPoints.getLength() > beforeLength) { + listener.onStartUpdateBatchInputTimer(); + } + return onValidArea; + } + + /** + * Determine whether the batch input has started or not. + * @param listener {@link BatchInputArbiterListener#onStartBatchInput()} of this + * <code>listener</code> will be called when the batch input has started successfully. + * @return true if the batch input has started successfully. + */ + public boolean mayStartBatchInput(final BatchInputArbiterListener listener) { + if (!mRecognitionPoints.isStartOfAGesture()) { + return false; + } + synchronized (sAggregatedPointers) { + sAggregatedPointers.reset(); + sLastRecognitionPointSize = 0; + sLastRecognitionTime = 0; + listener.onStartBatchInput(); + } + return true; + } + + /** + * Add synthetic move event point. After adding the point, + * {@link #updateBatchInput(long,BatchInputArbiterListener)} will be called internally. + * @param syntheticMoveEventTime the synthetic move event time. + * @param listener the listener to be passed to + * {@link #updateBatchInput(long,BatchInputArbiterListener)}. + */ + public void updateBatchInputByTimer(final long syntheticMoveEventTime, + final BatchInputArbiterListener listener) { + mRecognitionPoints.duplicateLastPointWith( + getElapsedTimeSinceFirstDown(syntheticMoveEventTime)); + updateBatchInput(syntheticMoveEventTime, listener); + } + + /** + * Determine whether we have enough gesture points to lookup dictionary. + * @param moveEventTime the time of this move event. + * @param listener {@link BatchInputArbiterListener#onUpdateBatchInput(InputPointers,long)} of + * this <code>listener</code> will be called when enough event points we have. Also + * {@link BatchInputArbiterListener#onStartUpdateBatchInputTimer()} will be called to have + * possible future synthetic move event. + */ + public void updateBatchInput(final long moveEventTime, + final BatchInputArbiterListener listener) { + synchronized (sAggregatedPointers) { + mRecognitionPoints.appendIncrementalBatchPoints(sAggregatedPointers); + final int size = sAggregatedPointers.getPointerSize(); + if (size > sLastRecognitionPointSize && mRecognitionPoints.hasRecognitionTimePast( + moveEventTime, sLastRecognitionTime)) { + listener.onUpdateBatchInput(sAggregatedPointers, moveEventTime); + listener.onStartUpdateBatchInputTimer(); + // The listener may change the size of the pointers (when auto-committing + // for example), so we need to get the size from the pointers again. + sLastRecognitionPointSize = sAggregatedPointers.getPointerSize(); + sLastRecognitionTime = moveEventTime; + } + } + } + + /** + * Determine whether the batch input has ended successfully or continues. + * @param upEventTime the time of this up event. + * @param activePointerCount the number of active pointers when this pointer up event occurs. + * @param listener {@link BatchInputArbiterListener#onEndBatchInput(InputPointers,long)} of this + * <code>listener</code> will be called when the batch input has started successfully. + * @return true if the batch input has ended successfully. + */ + public boolean mayEndBatchInput(final long upEventTime, final int activePointerCount, + final BatchInputArbiterListener listener) { + synchronized (sAggregatedPointers) { + mRecognitionPoints.appendAllBatchPoints(sAggregatedPointers); + if (activePointerCount == 1) { + listener.onEndBatchInput(sAggregatedPointers, upEventTime); + return true; + } + } + return false; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/BogusMoveEventDetector.java b/java/src/com/android/inputmethod/keyboard/internal/BogusMoveEventDetector.java new file mode 100644 index 000000000..e0589fc97 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/BogusMoveEventDetector.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 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.util.DisplayMetrics; +import android.util.Log; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; + +// This hack is applied to certain classes of tablets. +public final class BogusMoveEventDetector { + private static final String TAG = BogusMoveEventDetector.class.getSimpleName(); + private static final boolean DEBUG_MODE = LatinImeLogger.sDBG; + + // Move these thresholds to resource. + // These thresholds' unit is a diagonal length of a key. + private static final float BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD = 0.53f; + private static final float BOGUS_MOVE_RADIUS_THRESHOLD = 1.14f; + + private static boolean sNeedsProximateBogusDownMoveUpEventHack; + + public static void init(final Resources res) { + // The proximate bogus down move up event hack is needed for a device such like, + // 1) is large tablet, or 2) is small tablet and the screen density is less than hdpi. + // Though it seems odd to use screen density as criteria of the quality of the touch + // screen, the small table that has a less density screen than hdpi most likely has been + // made with the touch screen that needs the hack. + final int screenMetrics = res.getInteger(R.integer.config_screen_metrics); + final boolean isLargeTablet = (screenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET); + final boolean isSmallTablet = (screenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET); + final int densityDpi = res.getDisplayMetrics().densityDpi; + final boolean hasLowDensityScreen = (densityDpi < DisplayMetrics.DENSITY_HIGH); + final boolean needsTheHack = isLargeTablet || (isSmallTablet && hasLowDensityScreen); + if (DEBUG_MODE) { + final int sw = res.getConfiguration().smallestScreenWidthDp; + Log.d(TAG, "needsProximateBogusDownMoveUpEventHack=" + needsTheHack + + " smallestScreenWidthDp=" + sw + " densityDpi=" + densityDpi + + " screenMetrics=" + screenMetrics); + } + sNeedsProximateBogusDownMoveUpEventHack = needsTheHack; + } + + private int mAccumulatedDistanceThreshold; + private int mRadiusThreshold; + + // Accumulated distance from actual and artificial down keys. + /* package */ int mAccumulatedDistanceFromDownKey; + private int mActualDownX; + private int mActualDownY; + + public void setKeyboardGeometry(final int keyWidth, final int keyHeight) { + final float keyDiagonal = (float)Math.hypot(keyWidth, keyHeight); + mAccumulatedDistanceThreshold = (int)( + keyDiagonal * BOGUS_MOVE_ACCUMULATED_DISTANCE_THRESHOLD); + mRadiusThreshold = (int)(keyDiagonal * BOGUS_MOVE_RADIUS_THRESHOLD); + } + + public void onActualDownEvent(final int x, final int y) { + mActualDownX = x; + mActualDownY = y; + } + + public void onDownKey() { + mAccumulatedDistanceFromDownKey = 0; + } + + public void onMoveKey(final int distance) { + mAccumulatedDistanceFromDownKey += distance; + } + + public boolean hasTraveledLongDistance(final int x, final int y) { + if (!sNeedsProximateBogusDownMoveUpEventHack) { + return false; + } + final int dx = Math.abs(x - mActualDownX); + final int dy = Math.abs(y - mActualDownY); + // A bogus move event should be a horizontal movement. A vertical movement might be + // a sloppy typing and should be ignored. + return dx >= dy && mAccumulatedDistanceFromDownKey >= mAccumulatedDistanceThreshold; + } + + public int getAccumulatedDistanceFromDownKey() { + return mAccumulatedDistanceFromDownKey; + } + + public int getDistanceFromDownEvent(final int x, final int y) { + return getDistance(x, y, mActualDownX, mActualDownY); + } + + private static int getDistance(final int x1, final int y1, final int x2, final int y2) { + return (int)Math.hypot(x1 - x2, y1 - y2); + } + + public boolean isCloseToActualDownEvent(final int x, final int y) { + return sNeedsProximateBogusDownMoveUpEventHack + && getDistanceFromDownEvent(x, y) < mRadiusThreshold; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java index 4ccecb2f0..dce7fc57e 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java @@ -17,6 +17,7 @@ package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.StringUtils; import android.text.TextUtils; @@ -29,15 +30,16 @@ import android.text.TextUtils; * marker. An output text may consist of multiple code points separated by comma. * The format of the codesArray element should be: * <pre> - * codePointInHex[,codePoint2InHex]*(|outputTextCodePointInHex[,outputTextCodePoint2InHex]*)? + * label1[,label2]*(|outputText1[,outputText2]*(|minSupportSdkVersion)?)? * </pre> */ // TODO: Write unit tests for this class. public final class CodesArrayParser { // Constants for parsing. - private static final char COMMA = ','; - private static final String VERTICAL_BAR_STRING = "\\|"; - private static final String COMMA_STRING = ","; + private static final char COMMA = Constants.CODE_COMMA; + private static final String COMMA_REGEX = StringUtils.newSingleCodePointString(COMMA); + private static final String VERTICAL_BAR_REGEX = // "\\|" + new String(new char[] { Constants.CODE_BACKSLASH, Constants.CODE_VERTICAL_BAR }); private static final int BASE_HEX = 16; private CodesArrayParser() { @@ -45,7 +47,7 @@ public final class CodesArrayParser { } private static String getLabelSpec(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_STRING, -1); + final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); if (strs.length <= 1) { return codesArraySpec; } @@ -55,7 +57,7 @@ public final class CodesArrayParser { public static String parseLabel(final String codesArraySpec) { final String labelSpec = getLabelSpec(codesArraySpec); final StringBuilder sb = new StringBuilder(); - for (final String codeInHex : labelSpec.split(COMMA_STRING)) { + for (final String codeInHex : labelSpec.split(COMMA_REGEX)) { final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); sb.appendCodePoint(codePoint); } @@ -63,17 +65,15 @@ public final class CodesArrayParser { } private static String getCodeSpec(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_STRING, -1); + final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); if (strs.length <= 1) { return codesArraySpec; } return TextUtils.isEmpty(strs[1]) ? strs[0] : strs[1]; } - // codesArraySpec consists of: - // <label>|<code0>,<code1>,...|<minSupportSdkVersion> public static int getMinSupportSdkVersion(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_STRING, -1); + final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); if (strs.length <= 2) { return 0; } @@ -98,7 +98,7 @@ public final class CodesArrayParser { return null; } final StringBuilder sb = new StringBuilder(); - for (final String codeInHex : codeSpec.split(COMMA_STRING)) { + for (final String codeInHex : codeSpec.split(COMMA_REGEX)) { final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); sb.appendCodePoint(codePoint); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java new file mode 100644 index 000000000..df82becae --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 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.os.Message; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.internal.DrawingHandler.Callbacks; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; + +// TODO: Separate this class into KeyPreviewHandler and BatchInputPreviewHandler or so. +public class DrawingHandler extends LeakGuardHandlerWrapper<Callbacks> { + public interface Callbacks { + public void dismissKeyPreviewWithoutDelay(Key key); + public void dismissAllKeyPreviews(); + public void showGestureFloatingPreviewText(SuggestedWords suggestedWords); + } + + private static final int MSG_DISMISS_KEY_PREVIEW = 0; + private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; + + public DrawingHandler(final Callbacks ownerInstance) { + super(ownerInstance); + } + + @Override + public void handleMessage(final Message msg) { + final Callbacks callbacks = getOwnerInstance(); + if (callbacks == null) { + return; + } + switch (msg.what) { + case MSG_DISMISS_KEY_PREVIEW: + callbacks.dismissKeyPreviewWithoutDelay((Key)msg.obj); + break; + case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: + callbacks.showGestureFloatingPreviewText(SuggestedWords.EMPTY); + break; + } + } + + public void dismissKeyPreview(final long delay, final Key key) { + sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, key), delay); + } + + private void cancelAllDismissKeyPreviews() { + removeMessages(MSG_DISMISS_KEY_PREVIEW); + final Callbacks callbacks = getOwnerInstance(); + if (callbacks == null) { + return; + } + callbacks.dismissAllKeyPreviews(); + } + + public void dismissGestureFloatingPreviewText(final long delay) { + sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); + } + + public void cancelAllMessages() { + cancelAllDismissKeyPreviews(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java index 4c8607da8..fdc2458d4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java @@ -29,12 +29,12 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; import java.util.ArrayList; -public final class PreviewPlacerView extends RelativeLayout { +public final class DrawingPreviewPlacerView extends RelativeLayout { private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance(); private final ArrayList<AbstractDrawingPreview> mPreviews = CollectionUtils.newArrayList(); - public PreviewPlacerView(final Context context, final AttributeSet attrs) { + public DrawingPreviewPlacerView(final Context context, final AttributeSet attrs) { super(context, attrs); setWillNotDraw(false); } @@ -55,20 +55,24 @@ public final class PreviewPlacerView extends RelativeLayout { CoordinateUtils.copy(mKeyboardViewOrigin, originCoords); final int count = mPreviews.size(); for (int i = 0; i < count; i++) { - mPreviews.get(i).setKeyboardGeometry(originCoords, width, height); + mPreviews.get(i).setKeyboardViewGeometry(originCoords, width, height); } } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + public void deallocateMemory() { final int count = mPreviews.size(); for (int i = 0; i < count; i++) { - mPreviews.get(i).onDetachFromWindow(); + mPreviews.get(i).onDeallocateMemory(); } } @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + deallocateMemory(); + } + + @Override public void onDraw(final Canvas canvas) { super.onDraw(canvas); final int originX = CoordinateUtils.x(mKeyboardViewOrigin); diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java index 3133e54be..67a222732 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java @@ -25,11 +25,12 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.JsonUtils; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -50,10 +51,10 @@ public class DynamicGridKeyboard extends Keyboard { private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque(); private final ArrayDeque<Key> mPendingKeys = CollectionUtils.newArrayDeque(); - private Key[] mCachedGridKeys; + private List<Key> mCachedGridKeys; public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard, - final int maxKeyCount, final int categoryId, final int categoryPageId) { + final int maxKeyCount, final int categoryId) { super(templateKeyboard); final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0); final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1); @@ -66,7 +67,7 @@ public class DynamicGridKeyboard extends Keyboard { } private Key getTemplateKey(final int code) { - for (final Key key : super.getKeys()) { + for (final Key key : super.getSortedKeys()) { if (key.getCode() == code) { return key; } @@ -124,7 +125,7 @@ public class DynamicGridKeyboard extends Keyboard { final int keyY0 = getKeyY0(index); final int keyX1 = getKeyX1(index); final int keyY1 = getKeyY1(index); - gridKey.updateCorrdinates(keyX0, keyY0, keyX1, keyY1); + gridKey.updateCoordinates(keyX0, keyY0, keyX1, keyY1); index++; } } @@ -139,36 +140,50 @@ public class DynamicGridKeyboard extends Keyboard { keys.add(key.getCode()); } } - final String jsonStr = StringUtils.listToJsonStr(keys); + final String jsonStr = JsonUtils.listToJsonStr(keys); Settings.writeEmojiRecentKeys(mPrefs, jsonStr); } - private static Key getKey(final Collection<DynamicGridKeyboard> keyboards, final Object o) { - for (final DynamicGridKeyboard kbd : keyboards) { - if (o instanceof Integer) { - final int code = (Integer) o; - final Key key = kbd.getKey(code); - if (key != null) { + private static Key getKeyByCode(final Collection<DynamicGridKeyboard> keyboards, + final int code) { + for (final DynamicGridKeyboard keyboard : keyboards) { + for (final Key key : keyboard.getSortedKeys()) { + if (key.getCode() == code) { return key; } - } else if (o instanceof String) { - final String outputText = (String) o; - final Key key = kbd.getKeyFromOutputText(outputText); - if (key != null) { + } + } + return null; + } + + private static Key getKeyByOutputText(final Collection<DynamicGridKeyboard> keyboards, + final String outputText) { + for (final DynamicGridKeyboard keyboard : keyboards) { + for (final Key key : keyboard.getSortedKeys()) { + if (outputText.equals(key.getOutputText())) { return key; } - } else { - Log.w(TAG, "Invalid object: " + o); } } return null; } - public void loadRecentKeys(Collection<DynamicGridKeyboard> keyboards) { + public void loadRecentKeys(final Collection<DynamicGridKeyboard> keyboards) { final String str = Settings.readEmojiRecentKeys(mPrefs); - final List<Object> keys = StringUtils.jsonStrToList(str); + final List<Object> keys = JsonUtils.jsonStrToList(str); for (final Object o : keys) { - addKeyLast(getKey(keyboards, o)); + final Key key; + if (o instanceof Integer) { + final int code = (Integer)o; + key = getKeyByCode(keyboards, code); + } else if (o instanceof String) { + final String outputText = (String)o; + key = getKeyByOutputText(keyboards, outputText); + } else { + Log.w(TAG, "Invalid object: " + o); + continue; + } + addKeyLast(key); } } @@ -193,20 +208,21 @@ public class DynamicGridKeyboard extends Keyboard { } @Override - public Key[] getKeys() { + public List<Key> getSortedKeys() { synchronized (mLock) { if (mCachedGridKeys != null) { return mCachedGridKeys; } - mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]); + final ArrayList<Key> cachedKeys = new ArrayList<Key>(mGridKeys); + mCachedGridKeys = Collections.unmodifiableList(cachedKeys); return mCachedGridKeys; } } @Override - public Key[] getNearestKeys(final int x, final int y) { + public List<Key> getNearestKeys(final int x, final int y) { // TODO: Calculate the nearest key index in mGridKeys from x and y. - return getKeys(); + return getSortedKeys(); } static final class GridKey extends Key { @@ -217,7 +233,7 @@ public class DynamicGridKeyboard extends Keyboard { super(originalKey); } - public void updateCorrdinates(final int x0, final int y0, final int x1, final int y1) { + public void updateCoordinates(final int x0, final int y0, final int x1, final int y1) { mCurrentX = x0; mCurrentY = y0; getHitBox().set(x0, y0, x1, y1); diff --git a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java index 967448c28..d57ea5a94 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard; +package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; @@ -37,22 +37,22 @@ public class EmojiLayoutParams { private final int mBottomPadding; private final int mTopPadding; - public EmojiLayoutParams(Resources res) { + public EmojiLayoutParams(final Resources res) { final int defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res); final int defaultKeyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res); - mKeyVerticalGap = (int) res.getFraction(R.fraction.key_bottom_gap_holo, - (int) defaultKeyboardHeight, (int) defaultKeyboardHeight); - mBottomPadding = (int) res.getFraction(R.fraction.keyboard_bottom_padding_holo, - (int) defaultKeyboardHeight, (int) defaultKeyboardHeight); - mTopPadding = (int) res.getFraction(R.fraction.keyboard_top_padding_holo, - (int) defaultKeyboardHeight, (int) defaultKeyboardHeight); - mKeyHorizontalGap = (int) (res.getFraction(R.fraction.key_horizontal_gap_holo, + mKeyVerticalGap = (int) res.getFraction(R.fraction.config_key_vertical_gap_holo, + defaultKeyboardHeight, defaultKeyboardHeight); + mBottomPadding = (int) res.getFraction(R.fraction.config_keyboard_bottom_padding_holo, + defaultKeyboardHeight, defaultKeyboardHeight); + mTopPadding = (int) res.getFraction(R.fraction.config_keyboard_top_padding_holo, + defaultKeyboardHeight, defaultKeyboardHeight); + mKeyHorizontalGap = (int) (res.getFraction(R.fraction.config_key_horizontal_gap_holo, defaultKeyboardWidth, defaultKeyboardWidth)); mEmojiCategoryPageIdViewHeight = - (int) (res.getDimension(R.dimen.emoji_category_page_id_height)); + (int) (res.getDimension(R.dimen.config_emoji_category_page_id_height)); final int baseheight = defaultKeyboardHeight - mBottomPadding - mTopPadding + mKeyVerticalGap; - mEmojiActionBarHeight = ((int) baseheight) / DEFAULT_KEYBOARD_ROWS + mEmojiActionBarHeight = baseheight / DEFAULT_KEYBOARD_ROWS - (mKeyVerticalGap - mBottomPadding) / 2; mEmojiPagerHeight = defaultKeyboardHeight - mEmojiActionBarHeight - mEmojiCategoryPageIdViewHeight; @@ -60,26 +60,30 @@ public class EmojiLayoutParams { mEmojiKeyboardHeight = mEmojiPagerHeight - mEmojiPagerBottomMargin - 1; } - public void setPagerProperties(ViewPager vp) { + public void setPagerProperties(final ViewPager vp) { final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams(); lp.height = mEmojiKeyboardHeight; lp.bottomMargin = mEmojiPagerBottomMargin; vp.setLayoutParams(lp); } - public void setCategoryPageIdViewProperties(LinearLayout ll) { + public void setCategoryPageIdViewProperties(final LinearLayout ll) { final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams(); lp.height = mEmojiCategoryPageIdViewHeight; ll.setLayoutParams(lp); } - public void setActionBarProperties(LinearLayout ll) { + public int getActionBarHeight() { + return mEmojiActionBarHeight - mBottomPadding; + } + + public void setActionBarProperties(final LinearLayout ll) { final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams(); - lp.height = mEmojiActionBarHeight - mBottomPadding; + lp.height = getActionBarHeight(); ll.setLayoutParams(lp); } - public void setKeyProperties(ImageView ib) { + public void setKeyProperties(final ImageView ib) { final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ib.getLayoutParams(); lp.leftMargin = mKeyHorizontalGap / 2; lp.rightMargin = mKeyHorizontalGap / 2; diff --git a/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java b/java/src/com/android/inputmethod/keyboard/internal/EmojiPageKeyboardView.java index 9cf68d43d..e175a051e 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/EmojiPageKeyboardView.java @@ -17,101 +17,57 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; +import android.os.Handler; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; -import android.widget.ScrollView; -import android.widget.Scroller; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; /** - * This is an extended {@link KeyboardView} class that hosts a vertical scroll keyboard. + * This is an extended {@link KeyboardView} class that hosts an emoji page keyboard. * Multi-touch unsupported. No {@link PointerTracker}s. No gesture support. - * TODO: Vertical scroll capability should be removed from this class because it's no longer used. */ // TODO: Implement key popup preview. -public final class ScrollKeyboardView extends KeyboardView implements - ScrollViewWithNotifier.ScrollListener, GestureDetector.OnGestureListener { - private static final boolean PAGINATION = false; +public final class EmojiPageKeyboardView extends KeyboardView implements + GestureDetector.OnGestureListener { + private static final long KEY_PRESS_DELAY_TIME = 250; // msec + private static final long KEY_RELEASE_DELAY_TIME = 30; // msec - public interface OnKeyClickListener { - public void onKeyClick(Key key); + public interface OnKeyEventListener { + public void onPressKey(Key key); + public void onReleaseKey(Key key); } - private static final OnKeyClickListener EMPTY_LISTENER = new OnKeyClickListener() { + private static final OnKeyEventListener EMPTY_LISTENER = new OnKeyEventListener() { @Override - public void onKeyClick(final Key key) {} + public void onPressKey(final Key key) {} + @Override + public void onReleaseKey(final Key key) {} }; - private OnKeyClickListener mListener = EMPTY_LISTENER; - private final KeyDetector mKeyDetector = new KeyDetector(0.0f /*keyHysteresisDistance */); + private OnKeyEventListener mListener = EMPTY_LISTENER; + private final KeyDetector mKeyDetector = new KeyDetector(); private final GestureDetector mGestureDetector; - private final Scroller mScroller; - private ScrollViewWithNotifier mScrollView; - - public ScrollKeyboardView(final Context context, final AttributeSet attrs) { + public EmojiPageKeyboardView(final Context context, final AttributeSet attrs) { this(context, attrs, R.attr.keyboardViewStyle); } - public ScrollKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { + public EmojiPageKeyboardView(final Context context, final AttributeSet attrs, + final int defStyle) { super(context, attrs, defStyle); mGestureDetector = new GestureDetector(context, this); mGestureDetector.setIsLongpressEnabled(false /* isLongpressEnabled */); - mScroller = new Scroller(context); - } - - public void setScrollView(final ScrollViewWithNotifier scrollView) { - mScrollView = scrollView; - scrollView.setScrollListener(this); - } - - private final Runnable mScrollTask = new Runnable() { - @Override - public void run() { - final Scroller scroller = mScroller; - final ScrollView scrollView = mScrollView; - scroller.computeScrollOffset(); - scrollView.scrollTo(0, scroller.getCurrY()); - if (!scroller.isFinished()) { - scrollView.post(this); - } - } - }; - - // {@link ScrollViewWithNotified#ScrollListener} methods. - @Override - public void notifyScrollChanged(final int scrollX, final int scrollY, final int oldX, - final int oldY) { - if (PAGINATION) { - mScroller.forceFinished(true /* finished */); - mScrollView.removeCallbacks(mScrollTask); - final int currentTop = mScrollView.getScrollY(); - final int pageHeight = getKeyboard().mBaseHeight; - final int lastPageNo = currentTop / pageHeight; - final int lastPageTop = lastPageNo * pageHeight; - final int nextPageNo = lastPageNo + 1; - final int nextPageTop = Math.min(nextPageNo * pageHeight, getHeight() - pageHeight); - final int scrollTo = (currentTop - lastPageTop) < (nextPageTop - currentTop) - ? lastPageTop : nextPageTop; - final int deltaY = scrollTo - currentTop; - mScroller.startScroll(0, currentTop, 0, deltaY, 300); - mScrollView.post(mScrollTask); - } - } - - @Override - public void notifyOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, - final boolean clampedY) { - releaseCurrentKey(); + mHandler = new Handler(); } - public void setOnKeyClickListener(final OnKeyClickListener listener) { + public void setOnKeyEventListener(final OnKeyEventListener listener) { mListener = listener; } @@ -139,8 +95,10 @@ public final class ScrollKeyboardView extends KeyboardView implements return true; } - // {@link GestureDetector#OnGestureListener} methods. + // {@link GestureEnabler#OnGestureListener} methods. private Key mCurrentKey; + private Runnable mPendingKeyDown; + private final Handler mHandler; private Key getKey(final MotionEvent e) { final int index = e.getActionIndex(); @@ -150,6 +108,8 @@ public final class ScrollKeyboardView extends KeyboardView implements } public void releaseCurrentKey() { + mHandler.removeCallbacks(mPendingKeyDown); + mPendingKeyDown = null; final Key currentKey = mCurrentKey; if (currentKey == null) { return; @@ -167,9 +127,17 @@ public final class ScrollKeyboardView extends KeyboardView implements if (key == null) { return false; } - // TODO: May call {@link KeyboardActionListener#onPressKey(int,int,boolean)}. - key.onPressed(); - invalidateKey(key); + // Do not trigger key-down effect right now in case this is actually a fling action. + mPendingKeyDown = new Runnable() { + @Override + public void run() { + mPendingKeyDown = null; + key.onPressed(); + invalidateKey(key); + mListener.onPressKey(key); + } + }; + mHandler.postDelayed(mPendingKeyDown, KEY_PRESS_DELAY_TIME); return false; } @@ -181,14 +149,28 @@ public final class ScrollKeyboardView extends KeyboardView implements @Override public boolean onSingleTapUp(final MotionEvent e) { final Key key = getKey(e); + final Runnable pendingKeyDown = mPendingKeyDown; + final Key currentKey = mCurrentKey; releaseCurrentKey(); if (key == null) { return false; } - // TODO: May call {@link KeyboardActionListener#onReleaseKey(int,boolean)}. - key.onReleased(); - invalidateKey(key); - mListener.onKeyClick(key); + if (key == currentKey && pendingKeyDown != null) { + pendingKeyDown.run(); + // Trigger key-release event a little later so that a user can see visual feedback. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + key.onReleased(); + invalidateKey(key); + mListener.onReleaseKey(key); + } + }, KEY_RELEASE_DELAY_TIME); + } else { + key.onReleased(); + invalidateKey(key); + mListener.onReleaseKey(key); + } return true; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureEnabler.java b/java/src/com/android/inputmethod/keyboard/internal/GestureEnabler.java new file mode 100644 index 000000000..7d14ae924 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureEnabler.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 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.accessibility.AccessibilityUtils; + +public final class GestureEnabler { + /** True if we should handle gesture events. */ + private boolean mShouldHandleGesture; + private boolean mMainDictionaryAvailable; + private boolean mGestureHandlingEnabledByInputField; + private boolean mGestureHandlingEnabledByUser; + + private void updateGestureHandlingMode() { + mShouldHandleGesture = mMainDictionaryAvailable + && mGestureHandlingEnabledByInputField + && mGestureHandlingEnabledByUser + && !AccessibilityUtils.getInstance().isTouchExplorationEnabled(); + } + + // Note that this method is called from a non-UI thread. + public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { + mMainDictionaryAvailable = mainDictionaryAvailable; + updateGestureHandlingMode(); + } + + public void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { + mGestureHandlingEnabledByUser = gestureHandlingEnabledByUser; + updateGestureHandlingMode(); + } + + public void setPasswordMode(final boolean passwordMode) { + mGestureHandlingEnabledByInputField = !passwordMode; + updateGestureHandlingMode(); + } + + public boolean shouldHandleGesture() { + return mShouldHandleGesture; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java index c6dd9e100..2fa703083 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java @@ -42,7 +42,7 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewVerticalPadding * @attr ref R.styleable#KeyboardView_gestureFloatingPreviewRoundRadius */ -public class GestureFloatingPreviewText extends AbstractDrawingPreview { +public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { protected static final class GesturePreviewTextParams { public final int mGesturePreviewTextOffset; public final int mGesturePreviewTextHeight; @@ -100,11 +100,16 @@ public class GestureFloatingPreviewText extends AbstractDrawingPreview { private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; private final int[] mLastPointerCoords = CoordinateUtils.newInstance(); - public GestureFloatingPreviewText(final View drawingView, final TypedArray typedArray) { + public GestureFloatingTextDrawingPreview(final View drawingView, final TypedArray typedArray) { super(drawingView); mParams = new GesturePreviewTextParams(typedArray); } + @Override + public void onDeallocateMemory() { + // Nothing to do here. + } + public void setSuggetedWords(final SuggestedWords suggestedWords) { if (!isPreviewEnabled()) { return; diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingParams.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingParams.java new file mode 100644 index 000000000..478639d2d --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingParams.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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.TypedArray; + +import com.android.inputmethod.latin.R; + +/** + * This class holds parameters to control how a gesture stroke is sampled and drawn on the screen. + * + * @attr ref R.styleable#MainKeyboardView_gestureTrailMinSamplingDistance + * @attr ref R.styleable#MainKeyboardView_gestureTrailMaxInterpolationAngularThreshold + * @attr ref R.styleable#MainKeyboardView_gestureTrailMaxInterpolationDistanceThreshold + * @attr ref R.styleable#MainKeyboardView_gestureTrailMaxInterpolationSegments + */ +public final class GestureStrokeDrawingParams { + public final double mMinSamplingDistance; // in pixel + public final double mMaxInterpolationAngularThreshold; // in radian + public final double mMaxInterpolationDistanceThreshold; // in pixel + public final int mMaxInterpolationSegments; + + private static final float DEFAULT_MIN_SAMPLING_DISTANCE = 0.0f; // dp + private static final int DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD = 15; // in degree + private static final float DEFAULT_MAX_INTERPOLATION_DISTANCE_THRESHOLD = 0.0f; // dp + private static final int DEFAULT_MAX_INTERPOLATION_SEGMENTS = 4; + + public GestureStrokeDrawingParams(final TypedArray mainKeyboardViewAttr) { + mMinSamplingDistance = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gestureTrailMinSamplingDistance, + DEFAULT_MIN_SAMPLING_DISTANCE); + final int interpolationAngularDegree = mainKeyboardViewAttr.getInteger(R.styleable + .MainKeyboardView_gestureTrailMaxInterpolationAngularThreshold, 0); + mMaxInterpolationAngularThreshold = (interpolationAngularDegree <= 0) + ? Math.toRadians(DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD) + : Math.toRadians(interpolationAngularDegree); + mMaxInterpolationDistanceThreshold = mainKeyboardViewAttr.getDimension(R.styleable + .MainKeyboardView_gestureTrailMaxInterpolationDistanceThreshold, + DEFAULT_MAX_INTERPOLATION_DISTANCE_THRESHOLD); + mMaxInterpolationSegments = mainKeyboardViewAttr.getInteger( + R.styleable.MainKeyboardView_gestureTrailMaxInterpolationSegments, + DEFAULT_MAX_INTERPOLATION_SEGMENTS); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java index ecc67dd44..7d09e9d2f 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java @@ -16,19 +16,19 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.TypedArray; - -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResizableIntArray; -public final class GestureStrokeWithPreviewPoints extends GestureStroke { +/** + * This class holds drawing points to represent a gesture stroke on the screen. + */ +public final class GestureStrokeDrawingPoints { public static final int PREVIEW_CAPACITY = 256; private final ResizableIntArray mPreviewEventTimes = new ResizableIntArray(PREVIEW_CAPACITY); private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY); - private final GestureStrokePreviewParams mPreviewParams; + private final GestureStrokeDrawingParams mDrawingParams; private int mStrokeId; private int mLastPreviewSize; @@ -39,56 +39,11 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { private int mLastY; private double mDistanceFromLastSample; - public static final class GestureStrokePreviewParams { - public final double mMinSamplingDistance; // in pixel - public final double mMaxInterpolationAngularThreshold; // in radian - public final double mMaxInterpolationDistanceThreshold; // in pixel - public final int mMaxInterpolationSegments; - - public static final GestureStrokePreviewParams DEFAULT = new GestureStrokePreviewParams(); - - private static final int DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD = 15; // in degree - - private GestureStrokePreviewParams() { - mMinSamplingDistance = 0.0d; - mMaxInterpolationAngularThreshold = - degreeToRadian(DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD); - mMaxInterpolationDistanceThreshold = mMinSamplingDistance; - mMaxInterpolationSegments = 4; - } - - private static double degreeToRadian(final int degree) { - return degree / 180.0d * Math.PI; - } - - public GestureStrokePreviewParams(final TypedArray mainKeyboardViewAttr) { - mMinSamplingDistance = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gestureTrailMinSamplingDistance, - (float)DEFAULT.mMinSamplingDistance); - final int interpolationAngularDegree = mainKeyboardViewAttr.getInteger(R.styleable - .MainKeyboardView_gestureTrailMaxInterpolationAngularThreshold, 0); - mMaxInterpolationAngularThreshold = (interpolationAngularDegree <= 0) - ? DEFAULT.mMaxInterpolationAngularThreshold - : degreeToRadian(interpolationAngularDegree); - mMaxInterpolationDistanceThreshold = mainKeyboardViewAttr.getDimension(R.styleable - .MainKeyboardView_gestureTrailMaxInterpolationDistanceThreshold, - (float)DEFAULT.mMaxInterpolationDistanceThreshold); - mMaxInterpolationSegments = mainKeyboardViewAttr.getInteger( - R.styleable.MainKeyboardView_gestureTrailMaxInterpolationSegments, - DEFAULT.mMaxInterpolationSegments); - } - } - - public GestureStrokeWithPreviewPoints(final int pointerId, - final GestureStrokeParams strokeParams, - final GestureStrokePreviewParams previewParams) { - super(pointerId, strokeParams); - mPreviewParams = previewParams; + public GestureStrokeDrawingPoints(final GestureStrokeDrawingParams drawingParams) { + mDrawingParams = drawingParams; } - @Override - protected void reset() { - super.reset(); + private void reset() { mStrokeId++; mLastPreviewSize = 0; mLastInterpolatedPreviewIndex = 0; @@ -101,28 +56,29 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { return mStrokeId; } + public void onDownEvent(final int x, final int y, final int elapsedTimeSinceFirstDown) { + reset(); + onMoveEvent(x, y, elapsedTimeSinceFirstDown); + } + private boolean needsSampling(final int x, final int y) { mDistanceFromLastSample += Math.hypot(x - mLastX, y - mLastY); mLastX = x; mLastY = y; final boolean isDownEvent = (mPreviewEventTimes.getLength() == 0); - if (mDistanceFromLastSample >= mPreviewParams.mMinSamplingDistance || isDownEvent) { + if (mDistanceFromLastSample >= mDrawingParams.mMinSamplingDistance || isDownEvent) { mDistanceFromLastSample = 0.0d; return true; } return false; } - @Override - public boolean addPointOnKeyboard(final int x, final int y, final int time, - final boolean isMajorEvent) { + public void onMoveEvent(final int x, final int y, final int elapsedTimeSinceFirstDown) { if (needsSampling(x, y)) { - mPreviewEventTimes.add(time); + mPreviewEventTimes.add(elapsedTimeSinceFirstDown); mPreviewXCoordinates.add(x); mPreviewYCoordinates.add(y); } - return super.addPointOnKeyboard(x, y, time, isMajorEvent); - } /** @@ -132,7 +88,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { * @param xCoords the x-coordinates array of gesture trail to be drawn. * @param yCoords the y-coordinates array of gesture trail to be drawn. * @param types the point types array of gesture trail. This is valid only when - * {@link GestureTrail#DEBUG_SHOW_POINTS} is true. + * {@link GestureTrailDrawingPoints#DEBUG_SHOW_POINTS} is true. */ public void appendPreviewStroke(final ResizableIntArray eventTimes, final ResizableIntArray xCoords, final ResizableIntArray yCoords, @@ -144,8 +100,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { eventTimes.append(mPreviewEventTimes, mLastPreviewSize, length); xCoords.append(mPreviewXCoordinates, mLastPreviewSize, length); yCoords.append(mPreviewYCoordinates, mLastPreviewSize, length); - if (GestureTrail.DEBUG_SHOW_POINTS) { - types.fill(GestureTrail.POINT_TYPE_SAMPLED, types.getLength(), length); + if (GestureTrailDrawingPoints.DEBUG_SHOW_POINTS) { + types.fill(GestureTrailDrawingPoints.POINT_TYPE_SAMPLED, types.getLength(), length); } mLastPreviewSize = mPreviewEventTimes.getLength(); } @@ -162,7 +118,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { * @param xCoords the x-coordinates array of gesture trail to be drawn. * @param yCoords the y-coordinates array of gesture trail to be drawn. * @param types the point types array of gesture trail. This is valid only when - * {@link GestureTrail#DEBUG_SHOW_POINTS} is true. + * {@link GestureTrailDrawingPoints#DEBUG_SHOW_POINTS} is true. * @return the start index of the last interpolated segment of input arrays. */ public int interpolateStrokeAndReturnStartIndexOfLastSegment(final int lastInterpolatedIndex, @@ -188,12 +144,12 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { final double m2 = Math.atan2(mInterpolator.mSlope2Y, mInterpolator.mSlope2X); final double deltaAngle = Math.abs(angularDiff(m2, m1)); final int segmentsByAngle = (int)Math.ceil( - deltaAngle / mPreviewParams.mMaxInterpolationAngularThreshold); + deltaAngle / mDrawingParams.mMaxInterpolationAngularThreshold); final double deltaDistance = Math.hypot(mInterpolator.mP1X - mInterpolator.mP2X, mInterpolator.mP1Y - mInterpolator.mP2Y); final int segmentsByDistance = (int)Math.ceil(deltaDistance - / mPreviewParams.mMaxInterpolationDistanceThreshold); - final int segments = Math.min(mPreviewParams.mMaxInterpolationSegments, + / mDrawingParams.mMaxInterpolationDistanceThreshold); + final int segments = Math.min(mDrawingParams.mMaxInterpolationSegments, Math.max(segmentsByAngle, segmentsByDistance)); final int t1 = eventTimes.get(d1); final int dt = pt[p2] - pt[p1]; @@ -201,19 +157,19 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke { for (int i = 1; i < segments; i++) { final float t = i / (float)segments; mInterpolator.interpolate(t); - eventTimes.add(d1, (int)(dt * t) + t1); - xCoords.add(d1, (int)mInterpolator.mInterpolatedX); - yCoords.add(d1, (int)mInterpolator.mInterpolatedY); - if (GestureTrail.DEBUG_SHOW_POINTS) { - types.add(d1, GestureTrail.POINT_TYPE_INTERPOLATED); + eventTimes.addAt(d1, (int)(dt * t) + t1); + xCoords.addAt(d1, (int)mInterpolator.mInterpolatedX); + yCoords.addAt(d1, (int)mInterpolator.mInterpolatedY); + if (GestureTrailDrawingPoints.DEBUG_SHOW_POINTS) { + types.addAt(d1, GestureTrailDrawingPoints.POINT_TYPE_INTERPOLATED); } d1++; } - eventTimes.add(d1, pt[p2]); - xCoords.add(d1, px[p2]); - yCoords.add(d1, py[p2]); - if (GestureTrail.DEBUG_SHOW_POINTS) { - types.add(d1, GestureTrail.POINT_TYPE_SAMPLED); + eventTimes.addAt(d1, pt[p2]); + xCoords.addAt(d1, px[p2]); + yCoords.addAt(d1, py[p2]); + if (GestureTrailDrawingPoints.DEBUG_SHOW_POINTS) { + types.addAt(d1, GestureTrailDrawingPoints.POINT_TYPE_SAMPLED); } } return lastInterpolatedDrawIndex; diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionParams.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionParams.java new file mode 100644 index 000000000..07b14514c --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionParams.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013 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.TypedArray; + +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.ResourceUtils; + +/** + * This class holds parameters to control how a gesture stroke is sampled and recognized. + * This class also has parameters to distinguish gesture input events from fast typing events. + * + * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping + * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold + * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration + * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom + * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo + * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom + * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo + * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance + * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime + * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold + */ +public final class GestureStrokeRecognitionParams { + // Static threshold for gesture after fast typing + public final int mStaticTimeThresholdAfterFastTyping; // msec + // Static threshold for starting gesture detection + public final float mDetectFastMoveSpeedThreshold; // keyWidth/sec + // Dynamic threshold for gesture after fast typing + public final int mDynamicThresholdDecayDuration; // msec + // Time based threshold values + public final int mDynamicTimeThresholdFrom; // msec + public final int mDynamicTimeThresholdTo; // msec + // Distance based threshold values + public final float mDynamicDistanceThresholdFrom; // keyWidth + public final float mDynamicDistanceThresholdTo; // keyWidth + // Parameters for gesture sampling + public final float mSamplingMinimumDistance; // keyWidth + // Parameters for gesture recognition + public final int mRecognitionMinimumTime; // msec + public final float mRecognitionSpeedThreshold; // keyWidth/sec + + // Default GestureStrokeRecognitionPoints parameters. + public static final GestureStrokeRecognitionParams DEFAULT = + new GestureStrokeRecognitionParams(); + + private GestureStrokeRecognitionParams() { + // These parameter values are default and intended for testing. + mStaticTimeThresholdAfterFastTyping = 350; // msec + mDetectFastMoveSpeedThreshold = 1.5f; // keyWidth/sec + mDynamicThresholdDecayDuration = 450; // msec + mDynamicTimeThresholdFrom = 300; // msec + mDynamicTimeThresholdTo = 20; // msec + mDynamicDistanceThresholdFrom = 6.0f; // keyWidth + mDynamicDistanceThresholdTo = 0.35f; // keyWidth + // The following parameters' change will affect the result of regression test. + mSamplingMinimumDistance = 1.0f / 6.0f; // keyWidth + mRecognitionMinimumTime = 100; // msec + mRecognitionSpeedThreshold = 5.5f; // keyWidth/sec + } + + public GestureStrokeRecognitionParams(final TypedArray mainKeyboardViewAttr) { + mStaticTimeThresholdAfterFastTyping = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping, + DEFAULT.mStaticTimeThresholdAfterFastTyping); + mDetectFastMoveSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, + R.styleable.MainKeyboardView_gestureDetectFastMoveSpeedThreshold, + DEFAULT.mDetectFastMoveSpeedThreshold); + mDynamicThresholdDecayDuration = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureDynamicThresholdDecayDuration, + DEFAULT.mDynamicThresholdDecayDuration); + mDynamicTimeThresholdFrom = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureDynamicTimeThresholdFrom, + DEFAULT.mDynamicTimeThresholdFrom); + mDynamicTimeThresholdTo = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureDynamicTimeThresholdTo, + DEFAULT.mDynamicTimeThresholdTo); + mDynamicDistanceThresholdFrom = ResourceUtils.getFraction(mainKeyboardViewAttr, + R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdFrom, + DEFAULT.mDynamicDistanceThresholdFrom); + mDynamicDistanceThresholdTo = ResourceUtils.getFraction(mainKeyboardViewAttr, + R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdTo, + DEFAULT.mDynamicDistanceThresholdTo); + mSamplingMinimumDistance = ResourceUtils.getFraction(mainKeyboardViewAttr, + R.styleable.MainKeyboardView_gestureSamplingMinimumDistance, + DEFAULT.mSamplingMinimumDistance); + mRecognitionMinimumTime = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureRecognitionMinimumTime, + DEFAULT.mRecognitionMinimumTime); + mRecognitionSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, + R.styleable.MainKeyboardView_gestureRecognitionSpeedThreshold, + DEFAULT.mRecognitionSpeedThreshold); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java index f29ade861..e49e538aa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java @@ -16,16 +16,18 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.TypedArray; import android.util.Log; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.InputPointers; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResizableIntArray; -import com.android.inputmethod.latin.utils.ResourceUtils; -public class GestureStroke { - private static final String TAG = GestureStroke.class.getSimpleName(); +/** + * This class holds event points to recognize a gesture stroke. + * TODO: Should be package private class. + */ +public final class GestureStrokeRecognitionPoints { + private static final String TAG = GestureStrokeRecognitionPoints.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean DEBUG_SPEED = false; @@ -33,14 +35,15 @@ public class GestureStroke { // Proportional to the keyboard height. public static final float EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO = 0.25f; - public static final int DEFAULT_CAPACITY = 128; - private final int mPointerId; - private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); - private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); + private final ResizableIntArray mEventTimes = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private final ResizableIntArray mXCoordinates = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); + private final ResizableIntArray mYCoordinates = new ResizableIntArray( + Constants.DEFAULT_GESTURE_POINTS_CAPACITY); - private final GestureStrokeParams mParams; + private final GestureStrokeRecognitionParams mRecognitionParams; private int mKeyWidth; // pixel private int mMinYCoordinate; // pixel @@ -64,145 +67,85 @@ public class GestureStroke { private int mIncrementalRecognitionSize; private int mLastIncrementalBatchSize; - public static final class GestureStrokeParams { - // Static threshold for gesture after fast typing - public final int mStaticTimeThresholdAfterFastTyping; // msec - // Static threshold for starting gesture detection - public final float mDetectFastMoveSpeedThreshold; // keyWidth/sec - // Dynamic threshold for gesture after fast typing - public final int mDynamicThresholdDecayDuration; // msec - // Time based threshold values - public final int mDynamicTimeThresholdFrom; // msec - public final int mDynamicTimeThresholdTo; // msec - // Distance based threshold values - public final float mDynamicDistanceThresholdFrom; // keyWidth - public final float mDynamicDistanceThresholdTo; // keyWidth - // Parameters for gesture sampling - public final float mSamplingMinimumDistance; // keyWidth - // Parameters for gesture recognition - public final int mRecognitionMinimumTime; // msec - public final float mRecognitionSpeedThreshold; // keyWidth/sec - - // Default GestureStroke parameters. - public static final GestureStrokeParams DEFAULT = new GestureStrokeParams(); - - private GestureStrokeParams() { - // These parameter values are default and intended for testing. - mStaticTimeThresholdAfterFastTyping = 350; // msec - mDetectFastMoveSpeedThreshold = 1.5f; // keyWidth / sec - mDynamicThresholdDecayDuration = 450; // msec - mDynamicTimeThresholdFrom = 300; // msec - mDynamicTimeThresholdTo = 20; // msec - mDynamicDistanceThresholdFrom = 6.0f; // keyWidth - mDynamicDistanceThresholdTo = 0.35f; // keyWidth - // The following parameters' change will affect the result of regression test. - mSamplingMinimumDistance = 1.0f / 6.0f; // keyWidth - mRecognitionMinimumTime = 100; // msec - mRecognitionSpeedThreshold = 5.5f; // keyWidth / sec - } - - public GestureStrokeParams(final TypedArray mainKeyboardViewAttr) { - mStaticTimeThresholdAfterFastTyping = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping, - DEFAULT.mStaticTimeThresholdAfterFastTyping); - mDetectFastMoveSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, - R.styleable.MainKeyboardView_gestureDetectFastMoveSpeedThreshold, - DEFAULT.mDetectFastMoveSpeedThreshold); - mDynamicThresholdDecayDuration = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureDynamicThresholdDecayDuration, - DEFAULT.mDynamicThresholdDecayDuration); - mDynamicTimeThresholdFrom = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureDynamicTimeThresholdFrom, - DEFAULT.mDynamicTimeThresholdFrom); - mDynamicTimeThresholdTo = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureDynamicTimeThresholdTo, - DEFAULT.mDynamicTimeThresholdTo); - mDynamicDistanceThresholdFrom = ResourceUtils.getFraction(mainKeyboardViewAttr, - R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdFrom, - DEFAULT.mDynamicDistanceThresholdFrom); - mDynamicDistanceThresholdTo = ResourceUtils.getFraction(mainKeyboardViewAttr, - R.styleable.MainKeyboardView_gestureDynamicDistanceThresholdTo, - DEFAULT.mDynamicDistanceThresholdTo); - mSamplingMinimumDistance = ResourceUtils.getFraction(mainKeyboardViewAttr, - R.styleable.MainKeyboardView_gestureSamplingMinimumDistance, - DEFAULT.mSamplingMinimumDistance); - mRecognitionMinimumTime = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureRecognitionMinimumTime, - DEFAULT.mRecognitionMinimumTime); - mRecognitionSpeedThreshold = ResourceUtils.getFraction(mainKeyboardViewAttr, - R.styleable.MainKeyboardView_gestureRecognitionSpeedThreshold, - DEFAULT.mRecognitionSpeedThreshold); - } - } - private static final int MSEC_PER_SEC = 1000; - public GestureStroke(final int pointerId, final GestureStrokeParams params) { + // TODO: Make this package private + public GestureStrokeRecognitionPoints(final int pointerId, + final GestureStrokeRecognitionParams recognitionParams) { mPointerId = pointerId; - mParams = params; + mRecognitionParams = recognitionParams; } + // TODO: Make this package private public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) { mKeyWidth = keyWidth; mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); mMaxYCoordinate = keyboardHeight; // TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key? - mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold); - mGestureDynamicDistanceThresholdFrom = - (int)(keyWidth * mParams.mDynamicDistanceThresholdFrom); - mGestureDynamicDistanceThresholdTo = (int)(keyWidth * mParams.mDynamicDistanceThresholdTo); - mGestureSamplingMinimumDistance = (int)(keyWidth * mParams.mSamplingMinimumDistance); - mGestureRecognitionSpeedThreshold = (int)(keyWidth * mParams.mRecognitionSpeedThreshold); + mDetectFastMoveSpeedThreshold = (int)( + keyWidth * mRecognitionParams.mDetectFastMoveSpeedThreshold); + mGestureDynamicDistanceThresholdFrom = (int)( + keyWidth * mRecognitionParams.mDynamicDistanceThresholdFrom); + mGestureDynamicDistanceThresholdTo = (int)( + keyWidth * mRecognitionParams.mDynamicDistanceThresholdTo); + mGestureSamplingMinimumDistance = (int)( + keyWidth * mRecognitionParams.mSamplingMinimumDistance); + mGestureRecognitionSpeedThreshold = (int)( + keyWidth * mRecognitionParams.mRecognitionSpeedThreshold); if (DEBUG) { Log.d(TAG, String.format( "[%d] setKeyboardGeometry: keyWidth=%3d tT=%3d >> %3d tD=%3d >> %3d", mPointerId, keyWidth, - mParams.mDynamicTimeThresholdFrom, - mParams.mDynamicTimeThresholdTo, + mRecognitionParams.mDynamicTimeThresholdFrom, + mRecognitionParams.mDynamicTimeThresholdTo, mGestureDynamicDistanceThresholdFrom, mGestureDynamicDistanceThresholdTo)); } } + // TODO: Make this package private public int getLength() { return mEventTimes.getLength(); } - public void onDownEvent(final int x, final int y, final long downTime, - final long gestureFirstDownTime, final long lastTypingTime) { + // TODO: Make this package private + public void addDownEventPoint(final int x, final int y, final int elapsedTimeSinceFirstDown, + final int elapsedTimeSinceLastTyping) { reset(); - final long elapsedTimeAfterTyping = downTime - lastTypingTime; - if (elapsedTimeAfterTyping < mParams.mStaticTimeThresholdAfterFastTyping) { + if (elapsedTimeSinceLastTyping < mRecognitionParams.mStaticTimeThresholdAfterFastTyping) { mAfterFastTyping = true; } if (DEBUG) { Log.d(TAG, String.format("[%d] onDownEvent: dT=%3d%s", mPointerId, - elapsedTimeAfterTyping, mAfterFastTyping ? " afterFastTyping" : "")); + elapsedTimeSinceLastTyping, mAfterFastTyping ? " afterFastTyping" : "")); } - final int elapsedTimeFromFirstDown = (int)(downTime - gestureFirstDownTime); - addPointOnKeyboard(x, y, elapsedTimeFromFirstDown, true /* isMajorEvent */); + // Call {@link #addEventPoint(int,int,int,boolean)} to record this down event point as a + // major event point. + addEventPoint(x, y, elapsedTimeSinceFirstDown, true /* isMajorEvent */); } private int getGestureDynamicDistanceThreshold(final int deltaTime) { - if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { + if (!mAfterFastTyping || deltaTime >= mRecognitionParams.mDynamicThresholdDecayDuration) { return mGestureDynamicDistanceThresholdTo; } final int decayedThreshold = (mGestureDynamicDistanceThresholdFrom - mGestureDynamicDistanceThresholdTo) - * deltaTime / mParams.mDynamicThresholdDecayDuration; + * deltaTime / mRecognitionParams.mDynamicThresholdDecayDuration; return mGestureDynamicDistanceThresholdFrom - decayedThreshold; } private int getGestureDynamicTimeThreshold(final int deltaTime) { - if (!mAfterFastTyping || deltaTime >= mParams.mDynamicThresholdDecayDuration) { - return mParams.mDynamicTimeThresholdTo; + if (!mAfterFastTyping || deltaTime >= mRecognitionParams.mDynamicThresholdDecayDuration) { + return mRecognitionParams.mDynamicTimeThresholdTo; } final int decayedThreshold = - (mParams.mDynamicTimeThresholdFrom - mParams.mDynamicTimeThresholdTo) - * deltaTime / mParams.mDynamicThresholdDecayDuration; - return mParams.mDynamicTimeThresholdFrom - decayedThreshold; + (mRecognitionParams.mDynamicTimeThresholdFrom + - mRecognitionParams.mDynamicTimeThresholdTo) + * deltaTime / mRecognitionParams.mDynamicThresholdDecayDuration; + return mRecognitionParams.mDynamicTimeThresholdFrom - decayedThreshold; } + // TODO: Make this package private public final boolean isStartOfAGesture() { if (!hasDetectedFastMove()) { return false; @@ -233,6 +176,7 @@ public class GestureStroke { return isStartOfAGesture; } + // TODO: Make this package private public void duplicateLastPointWith(final int time) { final int lastIndex = getLength() - 1; if (lastIndex >= 0) { @@ -248,7 +192,7 @@ public class GestureStroke { } } - protected void reset() { + private void reset() { mIncrementalRecognitionSize = 0; mLastIncrementalBatchSize = 0; mEventTimes.setLength(0); @@ -316,19 +260,20 @@ public class GestureStroke { } /** - * Add a touch event as a gesture point. Returns true if the touch event is on the valid - * gesture area. - * @param x the x-coordinate of the touch event - * @param y the y-coordinate of the touch event + * Add an event point to this gesture stroke recognition points. Returns true if the event + * point is on the valid gesture area. + * @param x the x-coordinate of the event point + * @param y the y-coordinate of the event point * @param time the elapsed time in millisecond from the first gesture down * @param isMajorEvent false if this is a historical move event - * @return true if the touch event is on the valid gesture area + * @return true if the event point is on the valid gesture area */ - public boolean addPointOnKeyboard(final int x, final int y, final int time, + // TODO: Make this package private + public boolean addEventPoint(final int x, final int y, final int time, final boolean isMajorEvent) { final int size = getLength(); if (size <= 0) { - // Down event + // The first event of this stroke (a.k.a. down event). appendPoint(x, y, time); updateMajorEvent(x, y, time); } else { @@ -357,15 +302,18 @@ public class GestureStroke { } } + // TODO: Make this package private public final boolean hasRecognitionTimePast( final long currentTime, final long lastRecognitionTime) { - return currentTime > lastRecognitionTime + mParams.mRecognitionMinimumTime; + return currentTime > lastRecognitionTime + mRecognitionParams.mRecognitionMinimumTime; } + // TODO: Make this package private public final void appendAllBatchPoints(final InputPointers out) { appendBatchPoints(out, getLength()); } + // TODO: Make this package private public final void appendIncrementalBatchPoints(final InputPointers out) { appendBatchPoints(out, mIncrementalRecognitionSize); } @@ -381,10 +329,6 @@ public class GestureStroke { } private static int getDistance(final int x1, final int y1, final int x2, final int y2) { - final int dx = x1 - x2; - final int dy = y1 - y2; - // Note that, in recent versions of Android, FloatMath is actually slower than - // java.lang.Math due to the way the JIT optimizes java.lang.Math. - return (int)Math.sqrt(dx * dx + dy * dy); + return (int)Math.hypot(x1 - x2, y1 - y2); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingParams.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingParams.java new file mode 100644 index 000000000..088f03aa6 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingParams.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 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.TypedArray; + +import com.android.inputmethod.latin.R; + +/** + * This class holds parameters to control how a gesture trail is drawn and animated on the screen. + * + * On the other hand, {@link GestureStrokeDrawingParams} class controls how each gesture stroke is + * sampled and interpolated. This class controls how those gesture strokes are displayed as a + * gesture trail and animated on the screen. + * + * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutStartDelay + * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutDuration + * @attr ref R.styleable#MainKeyboardView_gestureTrailUpdateInterval + * @attr ref R.styleable#MainKeyboardView_gestureTrailColor + * @attr ref R.styleable#MainKeyboardView_gestureTrailWidth + */ +final class GestureTrailDrawingParams { + private static final int FADEOUT_START_DELAY_FOR_DEBUG = 2000; // millisecond + private static final int FADEOUT_DURATION_FOR_DEBUG = 200; // millisecond + + public final int mTrailColor; + public final float mTrailStartWidth; + public final float mTrailEndWidth; + public final float mTrailBodyRatio; + public boolean mTrailShadowEnabled; + public final float mTrailShadowRatio; + public final int mFadeoutStartDelay; + public final int mFadeoutDuration; + public final int mUpdateInterval; + + public final int mTrailLingerDuration; + + public GestureTrailDrawingParams(final TypedArray mainKeyboardViewAttr) { + mTrailColor = mainKeyboardViewAttr.getColor( + R.styleable.MainKeyboardView_gestureTrailColor, 0); + mTrailStartWidth = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gestureTrailStartWidth, 0.0f); + mTrailEndWidth = mainKeyboardViewAttr.getDimension( + R.styleable.MainKeyboardView_gestureTrailEndWidth, 0.0f); + final int PERCENTAGE_INT = 100; + mTrailBodyRatio = (float)mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailBodyRatio, PERCENTAGE_INT) + / (float)PERCENTAGE_INT; + final int trailShadowRatioInt = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailShadowRatio, 0); + mTrailShadowEnabled = (trailShadowRatioInt > 0); + mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT; + mFadeoutStartDelay = GestureTrailDrawingPoints.DEBUG_SHOW_POINTS + ? FADEOUT_START_DELAY_FOR_DEBUG + : mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailFadeoutStartDelay, 0); + mFadeoutDuration = GestureTrailDrawingPoints.DEBUG_SHOW_POINTS + ? FADEOUT_DURATION_FOR_DEBUG + : mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailFadeoutDuration, 0); + mTrailLingerDuration = mFadeoutStartDelay + mFadeoutDuration; + mUpdateInterval = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_gestureTrailUpdateInterval, 0); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java index aca667919..bf4c4da10 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -25,24 +24,22 @@ import android.graphics.Rect; import android.os.SystemClock; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResizableIntArray; -/* - * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutStartDelay - * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutDuration - * @attr ref R.styleable#MainKeyboardView_gestureTrailUpdateInterval - * @attr ref R.styleable#MainKeyboardView_gestureTrailColor - * @attr ref R.styleable#MainKeyboardView_gestureTrailWidth +/** + * This class holds drawing points to represent a gesture trail. The gesture trail may contain + * multiple non-contiguous gesture strokes and will be animated asynchronously from gesture input. + * + * On the other hand, {@link GestureStrokeDrawingPoints} class holds drawing points of each gesture + * stroke. This class holds drawing points of those gesture strokes to draw as a gesture trail. + * Drawing points in this class will be asynchronously removed when fading out animation goes. */ -final class GestureTrail { +final class GestureTrailDrawingPoints { public static final boolean DEBUG_SHOW_POINTS = false; public static final int POINT_TYPE_SAMPLED = 1; public static final int POINT_TYPE_INTERPOLATED = 2; - private static final int FADEOUT_START_DELAY_FOR_DEBUG = 2000; // millisecond - private static final int FADEOUT_DURATION_FOR_DEBUG = 200; // millisecond - private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY; + private static final int DEFAULT_CAPACITY = GestureStrokeDrawingPoints.PREVIEW_CAPACITY; // These three {@link ResizableIntArray}s should be synchronized by {@link #mEventTimes}. private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY); @@ -56,46 +53,6 @@ final class GestureTrail { private int mTrailStartIndex; private int mLastInterpolatedDrawIndex; - static final class Params { - public final int mTrailColor; - public final float mTrailStartWidth; - public final float mTrailEndWidth; - public final float mTrailBodyRatio; - public boolean mTrailShadowEnabled; - public final float mTrailShadowRatio; - public final int mFadeoutStartDelay; - public final int mFadeoutDuration; - public final int mUpdateInterval; - - public final int mTrailLingerDuration; - - public Params(final TypedArray mainKeyboardViewAttr) { - mTrailColor = mainKeyboardViewAttr.getColor( - R.styleable.MainKeyboardView_gestureTrailColor, 0); - mTrailStartWidth = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gestureTrailStartWidth, 0.0f); - mTrailEndWidth = mainKeyboardViewAttr.getDimension( - R.styleable.MainKeyboardView_gestureTrailEndWidth, 0.0f); - final int PERCENTAGE_INT = 100; - mTrailBodyRatio = (float)mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureTrailBodyRatio, PERCENTAGE_INT) - / (float)PERCENTAGE_INT; - final int trailShadowRatioInt = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureTrailShadowRatio, 0); - mTrailShadowEnabled = (trailShadowRatioInt > 0); - mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT; - mFadeoutStartDelay = DEBUG_SHOW_POINTS ? FADEOUT_START_DELAY_FOR_DEBUG - : mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureTrailFadeoutStartDelay, 0); - mFadeoutDuration = DEBUG_SHOW_POINTS ? FADEOUT_DURATION_FOR_DEBUG - : mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureTrailFadeoutDuration, 0); - mTrailLingerDuration = mFadeoutStartDelay + mFadeoutDuration; - mUpdateInterval = mainKeyboardViewAttr.getInt( - R.styleable.MainKeyboardView_gestureTrailUpdateInterval, 0); - } - } - // Use this value as imaginary zero because x-coordinates may be zero. private static final int DOWN_EVENT_MARKER = -128; @@ -112,13 +69,13 @@ final class GestureTrail { ? DOWN_EVENT_MARKER - xCoordOrMark : xCoordOrMark; } - public void addStroke(final GestureStrokeWithPreviewPoints stroke, final long downTime) { + public void addStroke(final GestureStrokeDrawingPoints stroke, final long downTime) { synchronized (mEventTimes) { addStrokeLocked(stroke, downTime); } } - private void addStrokeLocked(final GestureStrokeWithPreviewPoints stroke, final long downTime) { + private void addStrokeLocked(final GestureStrokeDrawingPoints stroke, final long downTime) { final int trailSize = mEventTimes.getLength(); stroke.appendPreviewStroke(mEventTimes, mXCoordinates, mYCoordinates, mPointTypes); if (mEventTimes.getLength() == trailSize) { @@ -126,13 +83,14 @@ final class GestureTrail { } final int[] eventTimes = mEventTimes.getPrimitiveArray(); final int strokeId = stroke.getGestureStrokeId(); - // Because interpolation algorithm in {@link GestureStrokeWithPreviewPoints} can't determine + // Because interpolation algorithm in {@link GestureStrokeDrawingPoints} can't determine // the interpolated points in the last segment of gesture stroke, it may need recalculation // of interpolation when new segments are added to the stroke. // {@link #mLastInterpolatedDrawIndex} holds the start index of the last segment. It may // be updated by the interpolation - // {@link GestureStrokeWithPreviewPoints#interpolatePreviewStroke} - // or by animation {@link #drawGestureTrail(Canvas,Paint,Rect,Params)} below. + // {@link GestureStrokeDrawingPoints#interpolatePreviewStroke} + // or by animation {@link #drawGestureTrail(Canvas,Paint,Rect,GestureTrailDrawingParams)} + // below. final int lastInterpolatedIndex = (strokeId == mCurrentStrokeId) ? mLastInterpolatedDrawIndex : trailSize; mLastInterpolatedDrawIndex = stroke.interpolateStrokeAndReturnStartIndexOfLastSegment( @@ -161,7 +119,7 @@ final class GestureTrail { * @param params gesture trail display parameters * @return the width of a gesture trail */ - private static int getAlpha(final int elapsedTime, final Params params) { + private static int getAlpha(final int elapsedTime, final GestureTrailDrawingParams params) { if (elapsedTime < params.mFadeoutStartDelay) { return Constants.Color.ALPHA_OPAQUE; } @@ -180,7 +138,7 @@ final class GestureTrail { * @param params gesture trail display parameters * @return the width of a gesture trail */ - private static float getWidth(final int elapsedTime, final Params params) { + private static float getWidth(final int elapsedTime, final GestureTrailDrawingParams params) { final float deltaWidth = params.mTrailStartWidth - params.mTrailEndWidth; return params.mTrailStartWidth - (deltaWidth * elapsedTime) / params.mTrailLingerDuration; } @@ -197,14 +155,14 @@ final class GestureTrail { * @return true if some gesture trails remain to be drawn */ public boolean drawGestureTrail(final Canvas canvas, final Paint paint, - final Rect outBoundsRect, final Params params) { + final Rect outBoundsRect, final GestureTrailDrawingParams params) { synchronized (mEventTimes) { return drawGestureTrailLocked(canvas, paint, outBoundsRect, params); } } private boolean drawGestureTrailLocked(final Canvas canvas, final Paint paint, - final Rect outBoundsRect, final Params params) { + final Rect outBoundsRect, final GestureTrailDrawingParams params) { // Initialize bounds rectangle. outBoundsRect.setEmpty(); final int trailSize = mEventTimes.getLength(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java index 19e995548..d8b00c707 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java @@ -29,16 +29,16 @@ import android.util.SparseArray; import android.view.View; import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.keyboard.internal.GestureTrail.Params; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; /** - * Draw gesture trail preview graphics during gesture. + * Draw preview graphics of multiple gesture trails during gesture input. */ -public final class GestureTrailsPreview extends AbstractDrawingPreview { - private final SparseArray<GestureTrail> mGestureTrails = CollectionUtils.newSparseArray(); - private final Params mGestureTrailParams; +public final class GestureTrailsDrawingPreview extends AbstractDrawingPreview { + private final SparseArray<GestureTrailDrawingPoints> mGestureTrails = + CollectionUtils.newSparseArray(); + private final GestureTrailDrawingParams mDrawingParams; private final Paint mGesturePaint; private int mOffscreenWidth; private int mOffscreenHeight; @@ -52,21 +52,23 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { private final DrawingHandler mDrawingHandler; private static final class DrawingHandler - extends StaticInnerHandlerWrapper<GestureTrailsPreview> { + extends LeakGuardHandlerWrapper<GestureTrailsDrawingPreview> { private static final int MSG_UPDATE_GESTURE_TRAIL = 0; - private final Params mGestureTrailParams; + private final GestureTrailDrawingParams mDrawingParams; - public DrawingHandler(final GestureTrailsPreview outerInstance, - final Params gestureTrailParams) { - super(outerInstance); - mGestureTrailParams = gestureTrailParams; + public DrawingHandler(final GestureTrailsDrawingPreview ownerInstance, + final GestureTrailDrawingParams drawingParams) { + super(ownerInstance); + mDrawingParams = drawingParams; } @Override public void handleMessage(final Message msg) { - final GestureTrailsPreview preview = getOuterInstance(); - if (preview == null) return; + final GestureTrailsDrawingPreview preview = getOwnerInstance(); + if (preview == null) { + return; + } switch (msg.what) { case MSG_UPDATE_GESTURE_TRAIL: preview.getDrawingView().invalidate(); @@ -77,14 +79,15 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { public void postUpdateGestureTrailPreview() { removeMessages(MSG_UPDATE_GESTURE_TRAIL); sendMessageDelayed(obtainMessage(MSG_UPDATE_GESTURE_TRAIL), - mGestureTrailParams.mUpdateInterval); + mDrawingParams.mUpdateInterval); } } - public GestureTrailsPreview(final View drawingView, final TypedArray mainKeyboardViewAttr) { + public GestureTrailsDrawingPreview(final View drawingView, + final TypedArray mainKeyboardViewAttr) { super(drawingView); - mGestureTrailParams = new Params(mainKeyboardViewAttr); - mDrawingHandler = new DrawingHandler(this, mGestureTrailParams); + mDrawingParams = new GestureTrailDrawingParams(mainKeyboardViewAttr); + mDrawingHandler = new DrawingHandler(this, mDrawingParams); final Paint gesturePaint = new Paint(); gesturePaint.setAntiAlias(true); gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); @@ -92,19 +95,17 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { } @Override - public void setKeyboardGeometry(final int[] originCoords, final int width, final int height) { - mOffscreenOffsetY = (int)( - height * GestureStroke.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); + public void setKeyboardViewGeometry(final int[] originCoords, final int width, + final int height) { + super.setKeyboardViewGeometry(originCoords, width, height); + mOffscreenOffsetY = (int)(height + * GestureStrokeRecognitionPoints.EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO); mOffscreenWidth = width; mOffscreenHeight = mOffscreenOffsetY + height; } @Override - public void onDetachFromWindow() { - freeOffscreenBuffer(); - } - - public void deallocateMemory() { + public void onDeallocateMemory() { freeOffscreenBuffer(); } @@ -144,9 +145,9 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { // Trails count == fingers count that have ever been active. final int trailsCount = mGestureTrails.size(); for (int index = 0; index < trailsCount; index++) { - final GestureTrail trail = mGestureTrails.valueAt(index); + final GestureTrailDrawingPoints trail = mGestureTrails.valueAt(index); needsUpdatingGestureTrail |= trail.drawGestureTrail(offscreenCanvas, paint, - mGestureTrailBoundsRect, mGestureTrailParams); + mGestureTrailBoundsRect, mDrawingParams); // {@link #mGestureTrailBoundsRect} has bounding box of the trail. dirtyRect.union(mGestureTrailBoundsRect); } @@ -189,15 +190,15 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview { if (!isPreviewEnabled()) { return; } - GestureTrail trail; + GestureTrailDrawingPoints trail; synchronized (mGestureTrails) { trail = mGestureTrails.get(tracker.mPointerId); if (trail == null) { - trail = new GestureTrail(); + trail = new GestureTrailDrawingPoints(); mGestureTrails.put(tracker.mPointerId, trail); } } - trail.addStroke(tracker.getGestureStrokeWithPreviewPoints(), tracker.getDownTime()); + trail.addStroke(tracker.getGestureStrokeDrawingPoints(), tracker.getDownTime()); // TODO: Should narrow the invalidate region. getDrawingView().invalidate(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java index b528b692e..1716fa049 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.ColorStateList; import android.graphics.Typeface; import com.android.inputmethod.latin.utils.ResourceUtils; @@ -33,7 +32,7 @@ public final class KeyDrawParams { public int mHintLabelSize; public int mPreviewTextSize; - public ColorStateList mTextColorStateList; + public int mTextColor; public int mTextInactivatedColor; public int mTextShadowColor; public int mHintLetterColor; @@ -58,7 +57,7 @@ public final class KeyDrawParams { mHintLabelSize = copyFrom.mHintLabelSize; mPreviewTextSize = copyFrom.mPreviewTextSize; - mTextColorStateList = copyFrom.mTextColorStateList; + mTextColor = copyFrom.mTextColor; mTextInactivatedColor = copyFrom.mTextInactivatedColor; mTextShadowColor = copyFrom.mTextShadowColor; mHintLetterColor = copyFrom.mHintLetterColor; @@ -90,8 +89,8 @@ public final class KeyDrawParams { attr.mShiftedLetterHintRatio, mShiftedLetterHintSize); mHintLabelSize = selectTextSize(keyHeight, attr.mHintLabelRatio, mHintLabelSize); mPreviewTextSize = selectTextSize(keyHeight, attr.mPreviewTextRatio, mPreviewTextSize); - mTextColorStateList = - attr.mTextColorStateList != null ? attr.mTextColorStateList : mTextColorStateList; + + mTextColor = selectColor(attr.mTextColor, mTextColor); mTextInactivatedColor = selectColor(attr.mTextInactivatedColor, mTextInactivatedColor); mTextShadowColor = selectColor(attr.mTextShadowColor, mTextShadowColor); mHintLetterColor = selectColor(attr.mHintLetterColor, mHintLetterColor); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java new file mode 100644 index 000000000..625d1f0a4 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2014 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.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; +import com.android.inputmethod.latin.utils.ViewLayoutUtils; + +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.HashSet; + +/** + * This class controls pop up key previews. This class decides: + * - what kind of key previews should be shown. + * - where key previews should be placed. + * - how key previews should be shown and dismissed. + */ +public final class KeyPreviewChoreographer { + // Free {@link TextView} pool that can be used for key preview. + private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque(); + // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. + private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = CollectionUtils.newHashMap(); + + private final KeyPreviewDrawParams mParams; + + public KeyPreviewChoreographer(final KeyPreviewDrawParams params) { + mParams = params; + } + + public TextView getKeyPreviewTextView(final Key key, final ViewGroup placerView) { + TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); + if (previewTextView != null) { + return previewTextView; + } + previewTextView = mFreeKeyPreviewTextViews.poll(); + if (previewTextView != null) { + return previewTextView; + } + final Context context = placerView.getContext(); + if (mParams.mLayoutId != 0) { + previewTextView = (TextView)LayoutInflater.from(context) + .inflate(mParams.mLayoutId, null); + } else { + previewTextView = new TextView(context); + } + placerView.addView(previewTextView, ViewLayoutUtils.newLayoutParam(placerView, 0, 0)); + return previewTextView; + } + + public boolean isShowingKeyPreview(final Key key) { + return mShowingKeyPreviewTextViews.containsKey(key); + } + + public void dismissAllKeyPreviews() { + for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) { + dismissKeyPreview(key, false /* withAnimation */); + } + } + + public void dismissKeyPreview(final Key key, final boolean withAnimation) { + if (key == null) { + return; + } + final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); + if (previewTextView == null) { + return; + } + final Object tag = previewTextView.getTag(); + if (withAnimation) { + if (tag instanceof KeyPreviewAnimations) { + final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; + animation.startDismiss(); + return; + } + } + // Dismiss preview without animation. + mShowingKeyPreviewTextViews.remove(key); + if (tag instanceof Animator) { + ((Animator)tag).cancel(); + } + previewTextView.setTag(null); + previewTextView.setVisibility(View.INVISIBLE); + mFreeKeyPreviewTextViews.add(previewTextView); + } + + // Background state set + private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { + { // STATE_MIDDLE + {}, + { R.attr.state_has_morekeys } + }, + { // STATE_LEFT + { R.attr.state_left_edge }, + { R.attr.state_left_edge, R.attr.state_has_morekeys } + }, + { // STATE_RIGHT + { R.attr.state_right_edge }, + { R.attr.state_right_edge, R.attr.state_has_morekeys } + } + }; + private static final int STATE_MIDDLE = 0; + private static final int STATE_LEFT = 1; + private static final int STATE_RIGHT = 2; + private static final int STATE_NORMAL = 0; + private static final int STATE_HAS_MOREKEYS = 1; + + public void placeKeyPreview(final Key key, final TextView previewTextView, + final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams, + final int keyboardViewWidth, final int[] originCoords) { + previewTextView.setTextColor(drawParams.mPreviewTextColor); + final Drawable background = previewTextView.getBackground(); + final String label = key.getPreviewLabel(); + // What we show as preview should match what we show on a key top in onDraw(). + if (label != null) { + // TODO Should take care of temporaryShiftLabel here. + previewTextView.setCompoundDrawables(null, null, null, null); + previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, + key.selectPreviewTextSize(drawParams)); + previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); + previewTextView.setText(label); + } else { + previewTextView.setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet)); + previewTextView.setText(null); + } + + previewTextView.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mParams.setGeometry(previewTextView); + final int previewWidth = previewTextView.getMeasuredWidth(); + final int previewHeight = mParams.mPreviewHeight; + final int keyDrawWidth = key.getDrawWidth(); + // The key preview is horizontally aligned with the center of the visible part of the + // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and + // the left/right background is used if such background is specified. + final int statePosition; + int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 + + CoordinateUtils.x(originCoords); + if (previewX < 0) { + previewX = 0; + statePosition = STATE_LEFT; + } else if (previewX > keyboardViewWidth - previewWidth) { + previewX = keyboardViewWidth - previewWidth; + statePosition = STATE_RIGHT; + } else { + statePosition = STATE_MIDDLE; + } + // The key preview is placed vertically above the top edge of the parent key with an + // arbitrary offset. + final int previewY = key.getY() - previewHeight + mParams.mPreviewOffset + + CoordinateUtils.y(originCoords); + + if (background != null) { + final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; + background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); + } + ViewLayoutUtils.placeViewAt( + previewTextView, previewX, previewY, previewWidth, previewHeight); + previewTextView.setPivotX(previewWidth / 2.0f); + previewTextView.setPivotY(previewHeight); + } + + public void showKeyPreview(final Key key, final TextView previewTextView, + final boolean withAnimation) { + if (!withAnimation) { + previewTextView.setVisibility(View.VISIBLE); + mShowingKeyPreviewTextViews.put(key, previewTextView); + return; + } + + // Show preview with animation. + final Animator showUpAnimation = createShowUpAniation(key, previewTextView); + final Animator dismissAnimation = createDismissAnimation(key, previewTextView); + final KeyPreviewAnimations animation = new KeyPreviewAnimations( + showUpAnimation, dismissAnimation); + previewTextView.setTag(animation); + animation.startShowUp(); + } + + private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f; + private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = + new AccelerateInterpolator(); + private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = + new DecelerateInterpolator(); + + private Animator createShowUpAniation(final Key key, final TextView previewTextView) { + // TODO: Optimization for no scale animation and no duration. + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_X, mParams.getShowUpStartScale(), + KEY_PREVIEW_SHOW_UP_END_SCALE); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_Y, mParams.getShowUpStartScale(), + KEY_PREVIEW_SHOW_UP_END_SCALE); + final AnimatorSet showUpAnimation = new AnimatorSet(); + showUpAnimation.play(scaleXAnimation).with(scaleYAnimation); + showUpAnimation.setDuration(mParams.getShowUpDuration()); + showUpAnimation.setInterpolator(DECELERATE_INTERPOLATOR); + showUpAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(final Animator animation) { + showKeyPreview(key, previewTextView, false /* withAnimation */); + } + }); + return showUpAnimation; + } + + private Animator createDismissAnimation(final Key key, final TextView previewTextView) { + // TODO: Optimization for no scale animation and no duration. + final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_X, mParams.getDismissEndScale()); + final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( + previewTextView, View.SCALE_Y, mParams.getDismissEndScale()); + final AnimatorSet dismissAnimation = new AnimatorSet(); + dismissAnimation.play(scaleXAnimation).with(scaleYAnimation); + final int dismissDuration = Math.min( + mParams.getDismissDuration(), mParams.getLingerTimeout()); + dismissAnimation.setDuration(dismissDuration); + dismissAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); + dismissAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(final Animator animation) { + dismissKeyPreview(key, false /* withAnimation */); + } + }); + return dismissAnimation; + } + + private static class KeyPreviewAnimations extends AnimatorListenerAdapter { + private final Animator mShowUpAnimation; + private final Animator mDismissAnimation; + + public KeyPreviewAnimations(final Animator showUpAnimation, + final Animator dismissAnimation) { + mShowUpAnimation = showUpAnimation; + mDismissAnimation = dismissAnimation; + } + + public void startShowUp() { + mShowUpAnimation.start(); + } + + public void startDismiss() { + if (mShowUpAnimation.isRunning()) { + mShowUpAnimation.addListener(this); + return; + } + mDismissAnimation.start(); + } + + @Override + public void onAnimationEnd(final Animator animation) { + mDismissAnimation.start(); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java index 609d1a57f..37e5c889d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java @@ -16,7 +16,23 @@ package com.android.inputmethod.keyboard.internal; +import android.content.res.TypedArray; +import android.view.View; + +import com.android.inputmethod.latin.R; + public final class KeyPreviewDrawParams { + // XML attributes of {@link MainKeyboardView}. + public final int mLayoutId; + public final int mPreviewOffset; + public final int mPreviewHeight; + private int mShowUpDuration; + private int mDismissDuration; + private float mShowUpStartScale; + private float mDismissEndScale; + private int mLingerTimeout; + private boolean mShowPopup = true; + // The graphical geometry of the key preview. // <-width-> // +-------+ ^ @@ -34,11 +50,92 @@ public final class KeyPreviewDrawParams { // paddings. To align the more keys keyboard panel's visible part with the visible part of // the background, we need to record the width and height of key preview that don't include // invisible paddings. - public int mPreviewVisibleWidth; - public int mPreviewVisibleHeight; + private int mVisibleWidth; + private int mVisibleHeight; // The key preview may have an arbitrary offset and its background that may have a bottom // padding. To align the more keys keyboard and the key preview we also need to record the // offset between the top edge of parent key and the bottom of the visible part of key // preview background. - public int mPreviewVisibleOffset; + private int mVisibleOffset; + + public KeyPreviewDrawParams(final TypedArray mainKeyboardViewAttr) { + mPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( + R.styleable.MainKeyboardView_keyPreviewOffset, 0); + mPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( + R.styleable.MainKeyboardView_keyPreviewHeight, 0); + mLingerTimeout = mainKeyboardViewAttr.getInt( + R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); + mLayoutId = mainKeyboardViewAttr.getResourceId( + R.styleable.MainKeyboardView_keyPreviewLayout, 0); + if (mLayoutId == 0) { + mShowPopup = false; + } + } + + public void setVisibleOffset(final int previewVisibleOffset) { + mVisibleOffset = previewVisibleOffset; + } + + public int getVisibleOffset() { + return mVisibleOffset; + } + + public void setGeometry(final View previewTextView) { + final int previewWidth = previewTextView.getMeasuredWidth(); + final int previewHeight = mPreviewHeight; + // The width and height of visible part of the key preview background. The content marker + // of the background 9-patch have to cover the visible part of the background. + mVisibleWidth = previewWidth - previewTextView.getPaddingLeft() + - previewTextView.getPaddingRight(); + mVisibleHeight = previewHeight - previewTextView.getPaddingTop() + - previewTextView.getPaddingBottom(); + // The distance between the top edge of the parent key and the bottom of the visible part + // of the key preview background. + setVisibleOffset(mPreviewOffset - previewTextView.getPaddingBottom()); + } + + public int getVisibleWidth() { + return mVisibleWidth; + } + + public int getVisibleHeight() { + return mVisibleHeight; + } + + public void setPopupEnabled(final boolean enabled, final int lingerTimeout) { + mShowPopup = enabled; + mLingerTimeout = lingerTimeout; + } + + public boolean isPopupEnabled() { + return mShowPopup; + } + + public int getLingerTimeout() { + return mLingerTimeout; + } + + public void setAnimationParams(final float showUpStartScale, final int showUpDuration, + final float dismissEndScale, final int dismissDuration) { + mShowUpStartScale = showUpStartScale; + mShowUpDuration = showUpDuration; + mDismissEndScale = dismissEndScale; + mDismissDuration = dismissDuration; + } + + public float getShowUpStartScale() { + return mShowUpStartScale; + } + + public int getShowUpDuration() { + return mShowUpDuration; + } + + public float getDismissEndScale() { + return mDismissEndScale; + } + + public int getDismissDuration() { + return mDismissDuration; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index 22f5b3dd1..48ba8e051 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -19,114 +19,54 @@ package com.android.inputmethod.keyboard.internal; import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT; import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; -import android.text.TextUtils; - import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.StringUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - /** - * The string parser of more keys specification. - * The specification is comma separated texts each of which represents one "more key". - * The specification might have label or string resource reference in it. These references are - * expanded before parsing comma. - * - Label reference should be a string representation of label (!text/label_name) - * - String resource reference should be a string representation of resource (!text/resource_name) - * Each "more key" specification is one of the following: - * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText). - * - Icon followed by keyOutputText or code (!icon/icon_name|!code/code_name) - * - Icon should be a string representation of icon (!icon/icon_name). - * - Code should be a code point presented by hexadecimal string prefixed with "0x", or a string - * representation of code (!code/code_name). + * The string parser of the key specification. + * + * Each key specification is one of the following: + * - Label optionally followed by keyOutputText (keyLabel|keyOutputText). + * - Label optionally followed by code point (keyLabel|!code/code_name). + * - Icon followed by keyOutputText (!icon/icon_name|keyOutputText). + * - Icon followed by code point (!icon/icon_name|!code/code_name). + * Label and keyOutputText are one of the following: + * - Literal string. + * - Label reference represented by (!text/label_name), see {@link KeyboardTextsSet}. + * - String resource reference represented by (!text/resource_name), see {@link KeyboardTextsSet}. + * Icon is represented by (!icon/icon_name), see {@link KeyboardIconsSet}. + * Code is one of the following: + * - Code point presented by hexadecimal string prefixed with "0x" + * - Code reference represented by (!code/code_name), see {@link KeyboardCodesSet}. * Special character, comma ',' backslash '\', and bar '|' can be escaped by '\' character. - * Note that the '\' is also parsed by XML parser and CSV parser as well. - * See {@link KeyboardIconsSet} about icon_name. + * Note that the '\' is also parsed by XML parser and {@link MoreKeySpec#splitKeySpecs(String)} + * as well. */ +// TODO: Rename to KeySpec and make this class to the key specification object. public final class KeySpecParser { - private static final boolean DEBUG = LatinImeLogger.sDBG; - - private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; - // Constants for parsing. - private static final char COMMA = ','; - private static final char BACKSLASH = '\\'; - private static final char VERTICAL_BAR = '|'; - private static final String PREFIX_TEXT = "!text/"; - static final String PREFIX_ICON = "!icon/"; - private static final String PREFIX_CODE = "!code/"; + private static final char BACKSLASH = Constants.CODE_BACKSLASH; + private static final char VERTICAL_BAR = Constants.CODE_VERTICAL_BAR; private static final String PREFIX_HEX = "0x"; - private static final String ADDITIONAL_MORE_KEY_MARKER = "%"; private KeySpecParser() { // Intentional empty constructor for utility class. } - /** - * Split the text containing multiple key specifications separated by commas into an array of - * key specifications. - * A key specification can contain a character escaped by the backslash character, including a - * comma character. - * Note that an empty key specification will be eliminated from the result array. - * - * @param text the text containing multiple key specifications. - * @return an array of key specification text. Null if the specified <code>text</code> is empty - * or has no key specifications. - */ - public static String[] splitKeySpecs(final String text) { - final int size = text.length(); - if (size == 0) { - return null; - } - // Optimization for one-letter key specification. - if (size == 1) { - return text.charAt(0) == COMMA ? null : new String[] { text }; - } + private static boolean hasIcon(final String keySpec) { + return keySpec.startsWith(KeyboardIconsSet.PREFIX_ICON); + } - ArrayList<String> list = null; - int start = 0; - // The characters in question in this loop are COMMA and BACKSLASH. These characters never - // match any high or low surrogate character. So it is OK to iterate through with char - // index. - 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 = CollectionUtils.newArrayList(); - } - list.add(text.substring(start, pos)); - } - // Skip comma - start = pos + 1; - } else if (c == BACKSLASH) { - // 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; + private static boolean hasCode(final String keySpec, final int labelEnd) { + if (labelEnd <= 0 || labelEnd + 1 >= keySpec.length()) { + return false; } - if (remain != null) { - list.add(remain); + if (keySpec.startsWith(KeyboardCodesSet.PREFIX_CODE, labelEnd + 1)) { + return true; } - return list.toArray(new String[list.size()]); - } - - private static boolean hasIcon(final String moreKeySpec) { - return moreKeySpec.startsWith(PREFIX_ICON); - } - - private static boolean hasCode(final String moreKeySpec) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (end > 0 && end + 1 < moreKeySpec.length() && moreKeySpec.startsWith( - PREFIX_CODE, end + 1)) { + // This is a workaround to have a key that has a supplementary code point. We can't put a + // string in resource as a XML entity of a supplementary code point or a surrogate pair. + if (keySpec.startsWith(PREFIX_HEX, labelEnd + 1)) { return true; } return false; @@ -151,17 +91,21 @@ public final class KeySpecParser { return sb.toString(); } - private static int indexOfLabelEnd(final String moreKeySpec, final int start) { - if (moreKeySpec.indexOf(BACKSLASH, start) < 0) { - final int end = moreKeySpec.indexOf(VERTICAL_BAR, start); - if (end == 0) { - throw new KeySpecParserError(VERTICAL_BAR + " at " + start + ": " + moreKeySpec); + private static int indexOfLabelEnd(final String keySpec) { + final int length = keySpec.length(); + if (keySpec.indexOf(BACKSLASH) < 0) { + final int labelEnd = keySpec.indexOf(VERTICAL_BAR); + if (labelEnd == 0) { + if (length == 1) { + // Treat a sole vertical bar as a special case of key label. + return -1; + } + throw new KeySpecParserError("Empty label"); } - return end; + return labelEnd; } - final int length = moreKeySpec.length(); - for (int pos = start; pos < length; pos++) { - final char c = moreKeySpec.charAt(pos); + for (int pos = 0; pos < length; pos++) { + final char c = keySpec.charAt(pos); if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; @@ -172,63 +116,85 @@ public final class KeySpecParser { return -1; } - public static String getLabel(final String moreKeySpec) { - if (hasIcon(moreKeySpec)) { + private static String getBeforeLabelEnd(final String keySpec, final int labelEnd) { + return (labelEnd < 0) ? keySpec : keySpec.substring(0, labelEnd); + } + + private static String getAfterLabelEnd(final String keySpec, final int labelEnd) { + return keySpec.substring(labelEnd + /* VERTICAL_BAR */1); + } + + private static void checkDoubleLabelEnd(final String keySpec, final int labelEnd) { + if (indexOfLabelEnd(getAfterLabelEnd(keySpec, labelEnd)) < 0) { + return; + } + throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + keySpec); + } + + public static String getLabel(final String keySpec) { + if (keySpec == null) { + // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. + return null; + } + if (hasIcon(keySpec)) { 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); + final int labelEnd = indexOfLabelEnd(keySpec); + final String label = parseEscape(getBeforeLabelEnd(keySpec, labelEnd)); + if (label.isEmpty()) { + throw new KeySpecParserError("Empty label: " + keySpec); } return label; } - private static String getOutputTextInternal(final String moreKeySpec) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (end <= 0) { + private static String getOutputTextInternal(final String keySpec, final int labelEnd) { + if (labelEnd <= 0) { return null; } - if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { - throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); - } - return parseEscape(moreKeySpec.substring(end + /* VERTICAL_BAR */1)); + checkDoubleLabelEnd(keySpec, labelEnd); + return parseEscape(getAfterLabelEnd(keySpec, labelEnd)); } - static String getOutputText(final String moreKeySpec) { - if (hasCode(moreKeySpec)) { + public static String getOutputText(final String keySpec) { + if (keySpec == null) { + // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. + return null; + } + final int labelEnd = indexOfLabelEnd(keySpec); + if (hasCode(keySpec, labelEnd)) { return null; } - final String outputText = getOutputTextInternal(moreKeySpec); + final String outputText = getOutputTextInternal(keySpec, labelEnd); if (outputText != null) { if (StringUtils.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; + if (outputText.isEmpty()) { + throw new KeySpecParserError("Empty outputText: " + keySpec); } - throw new KeySpecParserError("Empty outputText: " + moreKeySpec); + return outputText; } - final String label = getLabel(moreKeySpec); + final String label = getLabel(keySpec); if (label == null) { - throw new KeySpecParserError("Empty label: " + moreKeySpec); + throw new KeySpecParserError("Empty label: " + keySpec); } // Code is automatically generated for one letter label. See {@link getCode()}. return (StringUtils.codePointCount(label) == 1) ? null : label; } - static int getCode(final String moreKeySpec, final KeyboardCodesSet codesSet) { - if (hasCode(moreKeySpec)) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { - throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); - } - return parseCode(moreKeySpec.substring(end + 1), codesSet, CODE_UNSPECIFIED); + public static int getCode(final String keySpec) { + if (keySpec == null) { + // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. + return CODE_UNSPECIFIED; + } + final int labelEnd = indexOfLabelEnd(keySpec); + if (hasCode(keySpec, labelEnd)) { + checkDoubleLabelEnd(keySpec, labelEnd); + return parseCode(getAfterLabelEnd(keySpec, labelEnd), CODE_UNSPECIFIED); } - final String outputText = getOutputTextInternal(moreKeySpec); + final String outputText = getOutputTextInternal(keySpec, labelEnd); if (outputText != null) { // If output text is one code point, it should be treated as a code. // See {@link #getOutputText(String)}. @@ -237,138 +203,41 @@ public final class KeySpecParser { } return CODE_OUTPUT_TEXT; } - final String label = getLabel(moreKeySpec); - // Code is automatically generated for one letter label. - if (StringUtils.codePointCount(label) == 1) { - return label.codePointAt(0); - } - return CODE_OUTPUT_TEXT; - } - - public static int parseCode(final String text, final KeyboardCodesSet codesSet, - final int defCode) { - if (text == null) return defCode; - if (text.startsWith(PREFIX_CODE)) { - return codesSet.getCode(text.substring(PREFIX_CODE.length())); - } else if (text.startsWith(PREFIX_HEX)) { - return Integer.parseInt(text.substring(PREFIX_HEX.length()), 16); - } else { - return Integer.parseInt(text); - } - } - - public static int getIconId(final String moreKeySpec) { - if (moreKeySpec != null && hasIcon(moreKeySpec)) { - final int end = moreKeySpec.indexOf(VERTICAL_BAR, PREFIX_ICON.length()); - final String name = (end < 0) ? moreKeySpec.substring(PREFIX_ICON.length()) - : moreKeySpec.substring(PREFIX_ICON.length(), end); - return KeyboardIconsSet.getIconId(name); - } - return KeyboardIconsSet.ICON_UNDEFINED; - } - - private static <T> ArrayList<T> arrayAsList(final T[] array, final int start, final int end) { - if (array == null) { - throw new NullPointerException(); - } - if (start < 0 || start > end || end > array.length) { - throw new IllegalArgumentException(); - } - - final ArrayList<T> list = CollectionUtils.newArrayList(end - start); - for (int i = start; i < end; i++) { - list.add(array[i]); + final String label = getLabel(keySpec); + if (label == null) { + throw new KeySpecParserError("Empty label: " + keySpec); } - return list; + // Code is automatically generated for one letter label. + return (StringUtils.codePointCount(label) == 1) ? label.codePointAt(0) : CODE_OUTPUT_TEXT; } - private static final String[] EMPTY_STRING_ARRAY = new String[0]; - - private static String[] filterOutEmptyString(final String[] array) { - if (array == null) { - return EMPTY_STRING_ARRAY; + public static int parseCode(final String text, final int defaultCode) { + if (text == null) { + return defaultCode; } - ArrayList<String> out = null; - for (int i = 0; i < array.length; i++) { - final String entry = array[i]; - if (TextUtils.isEmpty(entry)) { - if (out == null) { - out = arrayAsList(array, 0, i); - } - } else if (out != null) { - out.add(entry); - } + if (text.startsWith(KeyboardCodesSet.PREFIX_CODE)) { + return KeyboardCodesSet.getCode(text.substring(KeyboardCodesSet.PREFIX_CODE.length())); } - if (out == null) { - return array; + // This is a workaround to have a key that has a supplementary code point. We can't put a + // string in resource as a XML entity of a supplementary code point or a surrogate pair. + if (text.startsWith(PREFIX_HEX)) { + return Integer.parseInt(text.substring(PREFIX_HEX.length()), 16); } - return out.toArray(new String[out.size()]); + return defaultCode; } - public static String[] insertAdditionalMoreKeys(final String[] moreKeySpecs, - final String[] additionalMoreKeySpecs) { - final String[] moreKeys = filterOutEmptyString(moreKeySpecs); - final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs); - final int moreKeysCount = moreKeys.length; - final int additionalCount = additionalMoreKeys.length; - 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 = arrayAsList(moreKeys, 0, moreKeyIndex); - } - } - } else { - if (out != null) { - out.add(moreKeySpec); - } - } + public static int getIconId(final String keySpec) { + if (keySpec == null) { + // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. + return KeyboardIconsSet.ICON_UNDEFINED; } - 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 = arrayAsList(additionalMoreKeys, additionalIndex, additionalCount); - 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 = arrayAsList(moreKeys, 0, moreKeysCount); - for (int i = additionalIndex; i < additionalCount; i++) { - out.add(additionalMoreKeys[additionalIndex]); - } - } - if (out == null && moreKeysCount > 0) { - return moreKeys; - } else if (out != null && out.size() > 0) { - return out.toArray(new String[out.size()]); - } else { - return null; + if (!hasIcon(keySpec)) { + return KeyboardIconsSet.ICON_UNDEFINED; } + final int labelEnd = indexOfLabelEnd(keySpec); + final String iconName = getBeforeLabelEnd(keySpec, labelEnd) + .substring(KeyboardIconsSet.PREFIX_ICON.length()); + return KeyboardIconsSet.getIconId(iconName); } @SuppressWarnings("serial") @@ -377,122 +246,4 @@ public final class KeySpecParser { super(message); } } - - public static String resolveTextReference(final String rawText, - final KeyboardTextsSet textsSet) { - 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 prefixLen = PREFIX_TEXT.length(); - final int size = text.length(); - if (size < prefixLen) { - return text; - } - - sb = null; - for (int pos = 0; pos < size; pos++) { - final char c = text.charAt(pos); - if (text.startsWith(PREFIX_TEXT, pos) && textsSet != null) { - if (sb == null) { - sb = new StringBuilder(text.substring(0, pos)); - } - final int end = searchTextNameEnd(text, pos + prefixLen); - final String name = text.substring(pos + prefixLen, end); - sb.append(textsSet.getText(name)); - pos = end - 1; - } else if (c == BACKSLASH) { - 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 searchTextNameEnd(final String text, final int start) { - final int size = text.length(); - for (int pos = start; pos < size; pos++) { - final char c = text.charAt(pos); - // Label name should be consisted of [a-zA-Z_0-9]. - if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) { - continue; - } - return pos; - } - return size; - } - - public static int getIntValue(final String[] moreKeys, final String key, - final int defaultValue) { - if (moreKeys == null) { - return defaultValue; - } - final int keyLen = key.length(); - boolean foundValue = false; - int value = defaultValue; - for (int i = 0; i < moreKeys.length; i++) { - final String moreKeySpec = moreKeys[i]; - if (moreKeySpec == null || !moreKeySpec.startsWith(key)) { - continue; - } - moreKeys[i] = null; - try { - if (!foundValue) { - value = Integer.parseInt(moreKeySpec.substring(keyLen)); - foundValue = true; - } - } catch (NumberFormatException e) { - throw new RuntimeException( - "integer should follow after " + key + ": " + moreKeySpec); - } - } - return value; - } - - public static boolean getBooleanValue(final String[] moreKeys, final String key) { - if (moreKeys == null) { - return false; - } - boolean value = false; - for (int i = 0; i < moreKeys.length; i++) { - final String moreKeySpec = moreKeys[i]; - if (moreKeySpec == null || !moreKeySpec.equals(key)) { - continue; - } - moreKeys[i] = null; - value = true; - } - return value; - } - - public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase, - final Locale locale) { - if (!Constants.isLetterCode(code) || !needsToUpperCase) return code; - final String text = new String(new int[] { code } , 0, 1); - final String casedText = KeySpecParser.toUpperCaseOfStringForLocale( - text, needsToUpperCase, locale); - return StringUtils.codePointCount(casedText) == 1 - ? casedText.codePointAt(0) : CODE_UNSPECIFIED; - } - - public static String toUpperCaseOfStringForLocale(final String text, - final boolean needsToUpperCase, final Locale locale) { - if (text == null || !needsToUpperCase) return text; - return text.toUpperCase(locale); - } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java index e6a674334..7941ddd41 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java @@ -32,15 +32,15 @@ public abstract class KeyStyle { protected String parseString(final TypedArray a, final int index) { if (a.hasValue(index)) { - return KeySpecParser.resolveTextReference(a.getString(index), mTextsSet); + return mTextsSet.resolveTextReference(a.getString(index)); } return null; } protected String[] parseStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { - final String text = KeySpecParser.resolveTextReference(a.getString(index), mTextsSet); - return KeySpecParser.splitKeySpecs(text); + final String text = mTextsSet.resolveTextReference(a.getString(index)); + return MoreKeySpec.splitKeySpecs(text); } return null; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java index 05d855e31..700c9b07c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java @@ -27,6 +27,7 @@ import com.android.inputmethod.latin.utils.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.util.Arrays; import java.util.HashMap; public final class KeyStylesSet { @@ -90,7 +91,8 @@ public final class KeyStylesSet { } final Object value = mStyleAttributes.get(index); if (value != null) { - return (String[])value; + final String[] array = (String[])value; + return Arrays.copyOf(array, array.length); } final KeyStyle parentStyle = mStyles.get(mParentStyleName); return parentStyle.getStringArray(a, index); @@ -133,15 +135,12 @@ public final class KeyStylesSet { public void readKeyAttributes(final TypedArray keyAttr) { // TODO: Currently not all Key attributes can be declared as style. - readString(keyAttr, R.styleable.Keyboard_Key_code); readString(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_keySpec); readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); readStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys); readFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags); - readString(keyAttr, R.styleable.Keyboard_Key_keyIcon); readString(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled); readString(keyAttr, R.styleable.Keyboard_Key_keyIconPreview); readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java index 8bdad364c..df386fce4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java @@ -16,7 +16,6 @@ package com.android.inputmethod.keyboard.internal; -import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Typeface; import android.util.SparseIntArray; @@ -38,7 +37,7 @@ public final class KeyVisualAttributes { public final float mHintLabelRatio; public final float mPreviewTextRatio; - public final ColorStateList mTextColorStateList; + public final int mTextColor; public final int mTextInactivatedColor; public final int mTextShadowColor; public final int mHintLetterColor; @@ -47,6 +46,8 @@ public final class KeyVisualAttributes { public final int mShiftedLetterHintActivatedColor; public final int mPreviewTextColor; + public final float mHintLabelVerticalAdjustment; + private static final int[] VISUAL_ATTRIBUTE_IDS = { R.styleable.Keyboard_Key_keyTypeface, R.styleable.Keyboard_Key_keyLetterSize, @@ -65,6 +66,7 @@ public final class KeyVisualAttributes { R.styleable.Keyboard_Key_keyShiftedLetterHintInactivatedColor, R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, R.styleable.Keyboard_Key_keyPreviewTextColor, + R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, }; private static final SparseIntArray sVisualAttributeIds = new SparseIntArray(); private static final int ATTR_DEFINED = 1; @@ -116,7 +118,7 @@ public final class KeyVisualAttributes { mPreviewTextRatio = ResourceUtils.getFraction(keyAttr, R.styleable.Keyboard_Key_keyPreviewTextRatio); - mTextColorStateList = keyAttr.getColorStateList(R.styleable.Keyboard_Key_keyTextColor); + mTextColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextColor, 0); mTextInactivatedColor = keyAttr.getColor( R.styleable.Keyboard_Key_keyTextInactivatedColor, 0); mTextShadowColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextShadowColor, 0); @@ -127,5 +129,8 @@ public final class KeyVisualAttributes { mShiftedLetterHintActivatedColor = keyAttr.getColor( R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, 0); mPreviewTextColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyPreviewTextColor, 0); + + mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr, + R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, 0.0f); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index c1ae65695..dfe0df04c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Build; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -33,17 +34,16 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; -import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.XmlParseUtils; +import com.android.inputmethod.latin.utils.XmlParseUtils.ParseException; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Arrays; -import java.util.Locale; /** * Keyboard Building helper. @@ -276,20 +276,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> { params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0); params.mIconsSet.loadIcons(keyboardAttr); - final String language = params.mId.mLocale.getLanguage(); - params.mCodesSet.setLanguage(language); - params.mTextsSet.setLanguage(language); - final RunInLocale<Void> job = new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - params.mTextsSet.loadStringResources(mContext); - return null; - } - }; - // Null means the current system locale. - final Locale locale = SubtypeLocaleUtils.isNoLanguage(params.mId.mSubtype) - ? null : params.mId.mLocale; - job.runInLocale(mResources, locale); + params.mTextsSet.setLocale(params.mId.mLocale, mContext); final int resourceId = keyboardAttr.getResourceId( R.styleable.Keyboard_touchPositionCorrectionData, 0); @@ -456,11 +443,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> { if (Build.VERSION.SDK_INT < supportedMinSdkVersion) { continue; } + final int labelFlags = row.getDefaultKeyLabelFlags(); + final int backgroundType = row.getDefaultBackgroundType(); final int x = (int)row.getKeyX(null); final int y = row.getKeyY(); - final Key key = new Key(mParams, label, null /* hintLabel */, 0 /* iconId */, - code, outputText, x, y, (int)keyWidth, (int)row.getRowHeight(), - row.getDefaultKeyLabelFlags(), row.getDefaultBackgroundType()); + final int width = (int)keyWidth; + final int height = row.getRowHeight(); + final Key key = new Key(label, KeyboardIconsSet.ICON_UNDEFINED, code, outputText, + null /* hintLabel */, labelFlags, backgroundType, x, y, width, height, + mParams.mHorizontalGap, mParams.mVerticalGap); endKey(key); row.advanceXPos(keyWidth); } @@ -477,7 +468,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> { if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); return; } - final Key key = new Key(mResources, mParams, row, parser); + final TypedArray keyAttr = mResources.obtainAttributes( + Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); + final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser); + final String keySpec = keyStyle.getString(keyAttr, R.styleable.Keyboard_Key_keySpec); + if (TextUtils.isEmpty(keySpec)) { + throw new ParseException("Empty keySpec", parser); + } + final Key key = new Key(keySpec, keyAttr, keyStyle, mParams, row); + keyAttr.recycle(); if (DEBUG) { startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, (key.isEnabled() ? "" : " disabled"), key, Arrays.toString(key.getMoreKeys())); @@ -493,7 +492,11 @@ public class KeyboardBuilder<KP extends KeyboardParams> { if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER); return; } - final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser); + final TypedArray keyAttr = mResources.obtainAttributes( + Xml.asAttributeSet(parser), R.styleable.Keyboard_Key); + final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser); + final Key spacer = new Key.Spacer(keyAttr, keyStyle, mParams, row); + keyAttr.recycle(); if (DEBUG) startEndTag("<%s />", TAG_SPACER); XmlParseUtils.checkEndTag(TAG_SPACER, parser); endKey(spacer); @@ -649,10 +652,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> { R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); final boolean clobberSettingsKeyMatched = matchBoolean(caseAttr, R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); - final boolean shortcutKeyEnabledMatched = matchBoolean(caseAttr, - R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); - final boolean shortcutKeyOnSymbolsMatched = matchBoolean(caseAttr, - R.styleable.Keyboard_Case_shortcutKeyOnSymbols, id.mShortcutKeyOnSymbols); + final boolean supportsSwitchingToShortcutImeMatched = matchBoolean(caseAttr, + R.styleable.Keyboard_Case_supportsSwitchingToShortcutIme, + id.mSupportsSwitchingToShortcutIme); final boolean hasShortcutKeyMatched = matchBoolean(caseAttr, R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); final boolean languageSwitchKeyEnabledMatched = matchBoolean(caseAttr, @@ -671,13 +673,12 @@ public class KeyboardBuilder<KP extends KeyboardParams> { final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched && modeMatched && navigateNextMatched && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched - && shortcutKeyEnabledMatched && shortcutKeyOnSymbolsMatched - && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched - && isMultiLineMatched && imeActionMatched && localeCodeMatched - && languageCodeMatched && countryCodeMatched; + && supportsSwitchingToShortcutImeMatched && hasShortcutKeyMatched + && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched + && localeCodeMatched && languageCodeMatched && countryCodeMatched; if (DEBUG) { - startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, + startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, textAttr(caseAttr.getString( R.styleable.Keyboard_Case_keyboardLayoutSet), "keyboardLayoutSet"), textAttr(caseAttr.getString( @@ -694,10 +695,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> { "clobberSettingsKey"), booleanAttr(caseAttr, R.styleable.Keyboard_Case_passwordInput, "passwordInput"), - booleanAttr(caseAttr, R.styleable.Keyboard_Case_shortcutKeyEnabled, - "shortcutKeyEnabled"), - booleanAttr(caseAttr, R.styleable.Keyboard_Case_shortcutKeyOnSymbols, - "shortcutKeyOnSymbols"), + booleanAttr( + caseAttr, R.styleable.Keyboard_Case_supportsSwitchingToShortcutIme, + "supportsSwitchingToShortcutIme"), booleanAttr(caseAttr, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), booleanAttr(caseAttr, R.styleable.Keyboard_Case_languageSwitchKeyEnabled, diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java index dc815e57d..06da5719b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java @@ -22,20 +22,18 @@ import com.android.inputmethod.latin.utils.CollectionUtils; import java.util.HashMap; public final class KeyboardCodesSet { - private static final HashMap<String, int[]> sLanguageToCodesMap = CollectionUtils.newHashMap(); - private static final HashMap<String, Integer> sNameToIdMap = CollectionUtils.newHashMap(); + public static final String PREFIX_CODE = "!code/"; - private int[] mCodes = DEFAULT; + private static final HashMap<String, Integer> sNameToIdMap = CollectionUtils.newHashMap(); - public void setLanguage(final String language) { - final int[] codes = sLanguageToCodesMap.get(language); - mCodes = (codes != null) ? codes : DEFAULT; + private KeyboardCodesSet() { + // This utility class is not publicly instantiable. } - public int getCode(final String name) { + public static int getCode(final String name) { Integer id = sNameToIdMap.get(name); if (id == null) throw new RuntimeException("Unknown key code: " + name); - return mCodes[id]; + return DEFAULT[id]; } private static final String[] ID_TO_NAME = { @@ -54,27 +52,10 @@ public final class KeyboardCodesSet { "key_shift_enter", "key_language_switch", "key_emoji", + "key_alpha_from_emoji", "key_unspecified", - "key_left_parenthesis", - "key_right_parenthesis", - "key_less_than", - "key_greater_than", - "key_left_square_bracket", - "key_right_square_bracket", - "key_left_curly_bracket", - "key_right_curly_bracket", }; - private static final int CODE_LEFT_PARENTHESIS = '('; - private static final int CODE_RIGHT_PARENTHESIS = ')'; - private static final int CODE_LESS_THAN_SIGN = '<'; - private static final int CODE_GREATER_THAN_SIGN = '>'; - private static final int CODE_LEFT_SQUARE_BRACKET = '['; - private static final int CODE_RIGHT_SQUARE_BRACKET = ']'; - private static final int CODE_LEFT_CURLY_BRACKET = '{'; - private static final int CODE_RIGHT_CURLY_BRACKET = '}'; - - // This array should be aligned with the array RTL below. private static final int[] DEFAULT = { Constants.CODE_TAB, Constants.CODE_ENTER, @@ -91,68 +72,13 @@ public final class KeyboardCodesSet { Constants.CODE_SHIFT_ENTER, Constants.CODE_LANGUAGE_SWITCH, Constants.CODE_EMOJI, + Constants.CODE_ALPHA_FROM_EMOJI, Constants.CODE_UNSPECIFIED, - CODE_LEFT_PARENTHESIS, - CODE_RIGHT_PARENTHESIS, - CODE_LESS_THAN_SIGN, - CODE_GREATER_THAN_SIGN, - CODE_LEFT_SQUARE_BRACKET, - CODE_RIGHT_SQUARE_BRACKET, - CODE_LEFT_CURLY_BRACKET, - CODE_RIGHT_CURLY_BRACKET, - }; - - private static final int[] RTL = { - DEFAULT[0], - DEFAULT[1], - DEFAULT[2], - DEFAULT[3], - DEFAULT[4], - DEFAULT[5], - DEFAULT[6], - DEFAULT[7], - DEFAULT[8], - DEFAULT[9], - DEFAULT[10], - DEFAULT[11], - DEFAULT[12], - DEFAULT[13], - DEFAULT[14], - DEFAULT[15], - CODE_RIGHT_PARENTHESIS, - CODE_LEFT_PARENTHESIS, - CODE_GREATER_THAN_SIGN, - CODE_LESS_THAN_SIGN, - CODE_RIGHT_SQUARE_BRACKET, - CODE_LEFT_SQUARE_BRACKET, - CODE_RIGHT_CURLY_BRACKET, - CODE_LEFT_CURLY_BRACKET, - }; - - private static final String LANGUAGE_DEFAULT = "DEFAULT"; - private static final String LANGUAGE_ARABIC = "ar"; - private static final String LANGUAGE_PERSIAN = "fa"; - private static final String LANGUAGE_HEBREW = "iw"; - - private static final Object[] LANGUAGE_AND_CODES = { - LANGUAGE_DEFAULT, DEFAULT, - LANGUAGE_ARABIC, RTL, - LANGUAGE_PERSIAN, RTL, - LANGUAGE_HEBREW, RTL, }; static { - if (DEFAULT.length != RTL.length || DEFAULT.length != ID_TO_NAME.length) { - throw new RuntimeException("Internal inconsistency"); - } for (int i = 0; i < ID_TO_NAME.length; i++) { sNameToIdMap.put(ID_TO_NAME[i], i); } - - for (int i = 0; i < LANGUAGE_AND_CODES.length; i += 2) { - final String language = (String)LANGUAGE_AND_CODES[i]; - final int[] codes = (int[])LANGUAGE_AND_CODES[i + 1]; - sLanguageToCodesMap.put(language, codes); - } } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 336db186e..6c9b5adc3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -30,33 +30,51 @@ import java.util.HashMap; public final class KeyboardIconsSet { private static final String TAG = KeyboardIconsSet.class.getSimpleName(); + public static final String PREFIX_ICON = "!icon/"; public static final int ICON_UNDEFINED = 0; private static final int ATTR_UNDEFINED = 0; + private static final String NAME_UNDEFINED = "undefined"; + public static final String NAME_SHIFT_KEY = "shift_key"; + public static final String NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted"; + public static final String NAME_DELETE_KEY = "delete_key"; + public static final String NAME_SETTINGS_KEY = "settings_key"; + public static final String NAME_SPACE_KEY = "space_key"; + public static final String NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout"; + public static final String NAME_ENTER_KEY = "enter_key"; + public static final String NAME_SEARCH_KEY = "search_key"; + public static final String NAME_TAB_KEY = "tab_key"; + public static final String NANE_TAB_KEY_PREVIEW = "tab_key_preview"; + public static final String NAME_SHORTCUT_KEY = "shortcut_key"; + public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled"; + public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key"; + public static final String NAME_ZWNJ_KEY = "zwnj_key"; + public static final String NAME_ZWJ_KEY = "zwj_key"; + public static final String NAME_EMOJI_KEY = "emoji_key"; + private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray(); // Icon name to icon id map. private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap(); private static final Object[] NAMES_AND_ATTR_IDS = { - "undefined", ATTR_UNDEFINED, - "shift_key", R.styleable.Keyboard_iconShiftKey, - "delete_key", R.styleable.Keyboard_iconDeleteKey, - "settings_key", R.styleable.Keyboard_iconSettingsKey, - "space_key", R.styleable.Keyboard_iconSpaceKey, - "enter_key", R.styleable.Keyboard_iconEnterKey, - "search_key", R.styleable.Keyboard_iconSearchKey, - "tab_key", R.styleable.Keyboard_iconTabKey, - "shortcut_key", R.styleable.Keyboard_iconShortcutKey, - "shortcut_for_label", R.styleable.Keyboard_iconShortcutForLabel, - "space_key_for_number_layout", R.styleable.Keyboard_iconSpaceKeyForNumberLayout, - "shift_key_shifted", R.styleable.Keyboard_iconShiftKeyShifted, - "shortcut_key_disabled", R.styleable.Keyboard_iconShortcutKeyDisabled, - "tab_key_preview", R.styleable.Keyboard_iconTabKeyPreview, - "language_switch_key", R.styleable.Keyboard_iconLanguageSwitchKey, - "zwnj_key", R.styleable.Keyboard_iconZwnjKey, - "zwj_key", R.styleable.Keyboard_iconZwjKey, - "emoji_key", R.styleable.Keyboard_iconEmojiKey, + NAME_UNDEFINED, ATTR_UNDEFINED, + NAME_SHIFT_KEY, R.styleable.Keyboard_iconShiftKey, + NAME_DELETE_KEY, R.styleable.Keyboard_iconDeleteKey, + NAME_SETTINGS_KEY, R.styleable.Keyboard_iconSettingsKey, + NAME_SPACE_KEY, R.styleable.Keyboard_iconSpaceKey, + NAME_ENTER_KEY, R.styleable.Keyboard_iconEnterKey, + NAME_SEARCH_KEY, R.styleable.Keyboard_iconSearchKey, + NAME_TAB_KEY, R.styleable.Keyboard_iconTabKey, + NAME_SHORTCUT_KEY, R.styleable.Keyboard_iconShortcutKey, + NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout, + NAME_SHIFT_KEY_SHIFTED, R.styleable.Keyboard_iconShiftKeyShifted, + NAME_SHORTCUT_KEY_DISABLED, R.styleable.Keyboard_iconShortcutKeyDisabled, + NANE_TAB_KEY_PREVIEW, R.styleable.Keyboard_iconTabKeyPreview, + NAME_LANGUAGE_SWITCH_KEY, R.styleable.Keyboard_iconLanguageSwitchKey, + NAME_ZWNJ_KEY, R.styleable.Keyboard_iconZwnjKey, + NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey, + NAME_EMOJI_KEY, R.styleable.Keyboard_iconEmojiKey, }; private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2; @@ -102,7 +120,7 @@ public final class KeyboardIconsSet { return isValidIconId(iconId) ? ICON_NAMES[iconId] : "unknown<" + iconId + ">"; } - static int getIconId(final String name) { + public static int getIconId(final String name) { Integer iconId = sNameToIdsMap.get(name); if (iconId != null) { return iconId; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java index d32bb7581..a61a79b85 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java @@ -24,6 +24,8 @@ import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.utils.CollectionUtils; import java.util.ArrayList; +import java.util.Comparator; +import java.util.SortedSet; import java.util.TreeSet; public class KeyboardParams { @@ -58,11 +60,11 @@ public class KeyboardParams { public int GRID_WIDTH; public int GRID_HEIGHT; - public final TreeSet<Key> mKeys = CollectionUtils.newTreeSet(); // ordered set + // Keys are sorted from top-left to bottom-right order. + public final SortedSet<Key> mSortedKeys = new TreeSet<Key>(ROW_COLUMN_COMPARATOR); public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList(); public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - public final KeyboardCodesSet mCodesSet = new KeyboardCodesSet(); public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); public final KeyStylesSet mKeyStyles = new KeyStylesSet(mTextsSet); @@ -76,8 +78,20 @@ public class KeyboardParams { public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection(); + // Comparator to sort {@link Key}s from top-left to bottom-right order. + private static final Comparator<Key> ROW_COLUMN_COMPARATOR = new Comparator<Key>() { + @Override + public int compare(final Key lhs, final Key rhs) { + if (lhs.getY() < rhs.getY()) return -1; + if (lhs.getY() > rhs.getY()) return 1; + if (lhs.getX() < rhs.getX()) return -1; + if (lhs.getX() > rhs.getX()) return 1; + return 0; + } + }; + protected void clearKeys() { - mKeys.clear(); + mSortedKeys.clear(); mShiftKeys.clear(); clearHistogram(); } @@ -89,7 +103,7 @@ public class KeyboardParams { // Ignore zero width {@link Spacer}. return; } - mKeys.add(key); + mSortedKeys.add(key); if (isSpacer) { return; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index dd98c1703..b98ced97c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -27,10 +27,10 @@ import com.android.inputmethod.latin.utils.RecapitalizeStatus; * * This class contains all keyboard state transition logic. * - * The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()}, - * {@link #onPressKey(int,boolean,int)}, {@link #onReleaseKey(int,boolean)}, - * {@link #onCodeInput(int,int)}, {@link #onFinishSlidingInput()}, - * {@link #onUpdateShiftState(int,int)}, {@link #onResetKeyboardStateToAlphabet()}. + * The input events are {@link #onLoadKeyboard(int, int)}, {@link #onSaveKeyboardState()}, + * {@link #onPressKey(int,boolean,int,int)}, {@link #onReleaseKey(int,boolean,int,int)}, + * {@link #onCodeInput(int,int,int)}, {@link #onFinishSlidingInput(int,int)}, + * {@link #onUpdateShiftState(int,int)}, {@link #onResetKeyboardStateToAlphabet(int,int)}. * * The actions are {@link SwitchActions}'s methods. */ @@ -52,7 +52,8 @@ public final class KeyboardState { /** * Request to call back {@link KeyboardState#onUpdateShiftState(int, int)}. */ - public void requestUpdatingShiftState(); + public void requestUpdatingShiftState(final int currentAutoCapsState, + final int currentRecapitalizeState); public void startDoubleTapShiftKeyTimer(); public boolean isInDoubleTapShiftKeyTimeout(); @@ -117,7 +118,8 @@ public final class KeyboardState { mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; } - public void onLoadKeyboard() { + public void onLoadKeyboard(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_EVENT) { Log.d(TAG, "onLoadKeyboard: " + this); } @@ -127,7 +129,7 @@ public final class KeyboardState { mPrevSymbolsKeyboardWasShifted = false; mShiftKeyState.onRelease(); mSymbolKeyState.onRelease(); - onRestoreKeyboardState(); + onRestoreKeyboardState(currentAutoCapsState, currentRecapitalizeState); } private static final int UNSHIFT = 0; @@ -153,13 +155,14 @@ public final class KeyboardState { } } - private void onRestoreKeyboardState() { + private void onRestoreKeyboardState(final int currentAutoCapsState, + final int currentRecapitalizeState) { final SavedKeyboardState state = mSavedKeyboardState; if (DEBUG_EVENT) { Log.d(TAG, "onRestoreKeyboardState: saved=" + state + " " + this); } if (!state.mIsValid || state.mIsAlphabetMode) { - setAlphabetKeyboard(); + setAlphabetKeyboard(currentAutoCapsState, currentRecapitalizeState); } else if (state.mIsEmojiMode) { setEmojiKeyboard(); } else { @@ -237,7 +240,8 @@ public final class KeyboardState { mAlphabetShiftState.setShiftLocked(shiftLocked); } - private void toggleAlphabetAndSymbols() { + private void toggleAlphabetAndSymbols(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_ACTION) { Log.d(TAG, "toggleAlphabetAndSymbols: " + this); } @@ -251,7 +255,7 @@ public final class KeyboardState { mPrevSymbolsKeyboardWasShifted = false; } else { mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted; - setAlphabetKeyboard(); + setAlphabetKeyboard(currentAutoCapsState, currentRecapitalizeState); if (mPrevMainKeyboardWasShiftLocked) { setShiftLocked(true); } @@ -261,14 +265,15 @@ public final class KeyboardState { // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). - private void resetKeyboardStateToAlphabet() { + private void resetKeyboardStateToAlphabet(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_ACTION) { Log.d(TAG, "resetKeyboardStateToAlphabet: " + this); } if (mIsAlphabetMode) return; mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted; - setAlphabetKeyboard(); + setAlphabetKeyboard(currentAutoCapsState, currentRecapitalizeState); if (mPrevMainKeyboardWasShiftLocked) { setShiftLocked(true); } @@ -283,7 +288,8 @@ public final class KeyboardState { } } - private void setAlphabetKeyboard() { + private void setAlphabetKeyboard(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_ACTION) { Log.d(TAG, "setAlphabetKeyboard"); } @@ -294,7 +300,7 @@ public final class KeyboardState { mIsSymbolShifted = false; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mSwitchState = SWITCH_STATE_ALPHA; - mSwitchActions.requestUpdatingShiftState(); + mSwitchActions.requestUpdatingShiftState(currentAutoCapsState, currentRecapitalizeState); } private void setSymbolsKeyboard() { @@ -304,6 +310,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = false; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -316,6 +323,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsShiftedKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -327,16 +335,18 @@ public final class KeyboardState { } mIsAlphabetMode = false; mIsEmojiMode = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Remember caps lock mode and reset alphabet shift state. mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); mAlphabetShiftState.setShiftLocked(false); mSwitchActions.setEmojiKeyboard(); } - public void onPressKey(final int code, final boolean isSinglePointer, final int autoCaps) { + public void onPressKey(final int code, final boolean isSinglePointer, + final int currentAutoCapsState, final int currentRecapitalizeState) { if (DEBUG_EVENT) { - Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code) - + " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this); + Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code) + " single=" + + isSinglePointer + " autoCaps=" + currentAutoCapsState + " " + this); } if (code != Constants.CODE_SHIFT) { // Because the double tap shift key timer is to detect two consecutive shift key press, @@ -348,7 +358,7 @@ public final class KeyboardState { } else if (code == Constants.CODE_CAPSLOCK) { // Nothing to do here. See {@link #onReleaseKey(int,boolean)}. } else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) { - onPressSymbol(); + onPressSymbol(currentAutoCapsState, currentRecapitalizeState); } else { mShiftKeyState.onOtherKeyPressed(); mSymbolKeyState.onOtherKeyPressed(); @@ -360,7 +370,8 @@ public final class KeyboardState { // As for #3, please note that it's required to check even when the auto caps mode is // off because, for example, we may be in the #1 state within the manual temporary // shifted mode. - if (!isSinglePointer && mIsAlphabetMode && autoCaps != TextUtils.CAP_MODE_CHARACTERS) { + if (!isSinglePointer && mIsAlphabetMode + && currentAutoCapsState != TextUtils.CAP_MODE_CHARACTERS) { final boolean needsToResetAutoCaps = mAlphabetShiftState.isAutomaticShifted() || (mAlphabetShiftState.isManualShifted() && mShiftKeyState.isReleasing()); if (needsToResetAutoCaps) { @@ -370,31 +381,34 @@ public final class KeyboardState { } } - public void onReleaseKey(final int code, final boolean withSliding) { + public void onReleaseKey(final int code, final boolean withSliding, + final int currentAutoCapsState, final int currentRecapitalizeState) { if (DEBUG_EVENT) { Log.d(TAG, "onReleaseKey: code=" + Constants.printableCode(code) + " sliding=" + withSliding + " " + this); } if (code == Constants.CODE_SHIFT) { - onReleaseShift(withSliding); + onReleaseShift(withSliding, currentAutoCapsState, currentRecapitalizeState); } else if (code == Constants.CODE_CAPSLOCK) { setShiftLocked(!mAlphabetShiftState.isShiftLocked()); } else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) { - onReleaseSymbol(withSliding); + onReleaseSymbol(withSliding, currentAutoCapsState, currentRecapitalizeState); } } - private void onPressSymbol() { - toggleAlphabetAndSymbols(); + private void onPressSymbol(final int currentAutoCapsState, + final int currentRecapitalizeState) { + toggleAlphabetAndSymbols(currentAutoCapsState, currentRecapitalizeState); mSymbolKeyState.onPress(); mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } - private void onReleaseSymbol(final boolean withSliding) { + private void onReleaseSymbol(final boolean withSliding, final int currentAutoCapsState, + final int currentRecapitalizeState) { 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(); + toggleAlphabetAndSymbols(currentAutoCapsState, currentRecapitalizeState); } 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 @@ -415,11 +429,12 @@ public final class KeyboardState { // TODO: Remove this method. Come up with a more comprehensive way to reset the keyboard layout // when a keyboard layout set doesn't get reloaded in LatinIME.onStartInputViewInternal(). - public void onResetKeyboardStateToAlphabet() { + public void onResetKeyboardStateToAlphabet(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_EVENT) { Log.d(TAG, "onResetKeyboardStateToAlphabet: " + this); } - resetKeyboardStateToAlphabet(); + resetKeyboardStateToAlphabet(currentAutoCapsState, currentRecapitalizeState); } private void updateShiftStateForRecapitalize(final int recapitalizeMode) { @@ -510,7 +525,8 @@ public final class KeyboardState { } } - private void onReleaseShift(final boolean withSliding) { + private void onReleaseShift(final boolean withSliding, final int currentAutoCapsState, + final int currentRecapitalizeState) { if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) { // We are recapitalizing. We should match the keyboard state to the recapitalize // state in priority. @@ -533,7 +549,8 @@ public final class KeyboardState { // After chording input, automatic shift state may have been changed depending on // what characters were input. mShiftKeyState.onRelease(); - mSwitchActions.requestUpdatingShiftState(); + mSwitchActions.requestUpdatingShiftState(currentAutoCapsState, + currentRecapitalizeState); return; } else if (mAlphabetShiftState.isShiftLockShifted() && withSliding) { // In shift locked state, shift has been pressed and slid out to other key. @@ -570,20 +587,21 @@ public final class KeyboardState { mShiftKeyState.onRelease(); } - public void onFinishSlidingInput() { + public void onFinishSlidingInput(final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_EVENT) { Log.d(TAG, "onFinishSlidingInput: " + this); } // Switch back to the previous keyboard mode if the user cancels sliding input. switch (mSwitchState) { case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: - toggleAlphabetAndSymbols(); + toggleAlphabetAndSymbols(currentAutoCapsState, currentRecapitalizeState); break; case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: toggleShiftInSymbols(); break; case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT: - setAlphabetKeyboard(); + setAlphabetKeyboard(currentAutoCapsState, currentRecapitalizeState); break; } } @@ -592,10 +610,11 @@ public final class KeyboardState { return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER; } - public void onCodeInput(final int code, final int autoCaps) { + public void onCodeInput(final int code, final int currentAutoCapsState, + final int currentRecapitalizeState) { if (DEBUG_EVENT) { Log.d(TAG, "onCodeInput: code=" + Constants.printableCode(code) - + " autoCaps=" + autoCaps + " " + this); + + " autoCaps=" + currentAutoCapsState + " " + this); } switch (mSwitchState) { @@ -631,7 +650,7 @@ public final class KeyboardState { // Switch back to alpha keyboard mode if user types one or more non-space/enter // characters followed by a space/enter. if (isSpaceOrEnter(code)) { - toggleAlphabetAndSymbols(); + toggleAlphabetAndSymbols(currentAutoCapsState, currentRecapitalizeState); mPrevSymbolsKeyboardWasShifted = false; } break; @@ -639,9 +658,11 @@ public final class KeyboardState { // If the code is a letter, update keyboard shift state. if (Constants.isLetterCode(code)) { - updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); + updateAlphabetShiftState(currentAutoCapsState, currentRecapitalizeState); } else if (code == Constants.CODE_EMOJI) { setEmojiKeyboard(); + } else if (code == Constants.CODE_ALPHA_FROM_EMOJI) { + setAlphabetKeyboard(currentAutoCapsState, currentRecapitalizeState); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index c2a01b5e8..0047aa4a1 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -18,80 +18,126 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; import android.content.res.Resources; +import android.text.TextUtils; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.RunInLocale; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.HashMap; +import java.util.Locale; -/** - * !!!!! DO NOT EDIT THIS FILE !!!!! - * - * This file is generated by tools/make-keyboard-text. The base template file is - * tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl - * - * This file must be updated when any text resources in keyboard layout files have been changed. - * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, - * and should be defined in - * tools/make-keyboard-text/res/values-<locale>/donottranslate-more-keys.xml - * - * To update this file, please run the following commands. - * $ cd $ANDROID_BUILD_TOP - * $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text - * $ make-keyboard-text -java packages/inputmethods/LatinIME/java/src - * - * The updated source file will be generated to the following path (this file). - * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ - * KeyboardTextsSet.java - */ public final class KeyboardTextsSet { - // Language to texts map. - private static final HashMap<String, String[]> sLocaleToTextsMap = CollectionUtils.newHashMap(); - private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap(); + public static final String PREFIX_TEXT = "!text/"; + public static final String SWITCH_TO_ALPHA_KEY_LABEL = "keylabel_to_alpha"; - private String[] mTexts; + private static final char BACKSLASH = Constants.CODE_BACKSLASH; + private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; + + private String[] mTextsTable; // Resource name to text map. private HashMap<String, String> mResourceNameToTextsMap = CollectionUtils.newHashMap(); - public void setLanguage(final String language) { - mTexts = sLocaleToTextsMap.get(language); - if (mTexts == null) { - mTexts = LANGUAGE_DEFAULT; - } - } - - public void loadStringResources(final Context context) { + public void setLocale(final Locale locale, final Context context) { + mTextsTable = KeyboardTextsTable.getTextsTable(locale); + final Resources res = context.getResources(); final int referenceId = context.getApplicationInfo().labelRes; - loadStringResourcesInternal(context, RESOURCE_NAMES, referenceId); + final String resourcePackageName = res.getResourcePackageName(referenceId); + final RunInLocale<Void> job = new RunInLocale<Void>() { + @Override + protected Void job(final Resources resource) { + loadStringResourcesInternal(res, RESOURCE_NAMES, resourcePackageName); + return null; + } + }; + // Null means the current system locale. + job.runInLocale(res, + SubtypeLocaleUtils.NO_LANGUAGE.equals(locale.toString()) ? null : locale); } @UsedForTesting - void loadStringResourcesInternal(final Context context, final String[] resourceNames, - final int referenceId) { - final Resources res = context.getResources(); - final String packageName = res.getResourcePackageName(referenceId); + void loadStringResourcesInternal(final Resources res, final String[] resourceNames, + final String resourcePackageName) { for (final String resName : resourceNames) { - final int resId = res.getIdentifier(resName, "string", packageName); + final int resId = res.getIdentifier(resName, "string", resourcePackageName); mResourceNameToTextsMap.put(resName, res.getString(resId)); } } public String getText(final String name) { - String text = mResourceNameToTextsMap.get(name); - if (text != null) { - return text; + final String text = mResourceNameToTextsMap.get(name); + return (text != null) ? text : KeyboardTextsTable.getText(name, mTextsTable); + } + + private static int searchTextNameEnd(final String text, final int start) { + final int size = text.length(); + for (int pos = start; pos < size; pos++) { + final char c = text.charAt(pos); + // Label name should be consisted of [a-zA-Z_0-9]. + if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) { + continue; + } + return pos; } - final Integer id = sNameToIdsMap.get(name); - if (id == null) throw new RuntimeException("Unknown label: " + name); - text = (id < mTexts.length) ? mTexts[id] : null; - return (text == null) ? LANGUAGE_DEFAULT[id] : text; + return size; } - private static final String[] RESOURCE_NAMES = { - // These texts' name should be aligned with the @string/<name> in values/strings.xml. + // TODO: Resolve text reference when creating {@link KeyboardTextsTable} class. + public String resolveTextReference(final String rawText) { + if (TextUtils.isEmpty(rawText)) { + return null; + } + int level = 0; + String text = rawText; + StringBuilder sb; + do { + level++; + if (level >= MAX_STRING_REFERENCE_INDIRECTION) { + throw new RuntimeException("Too many " + PREFIX_TEXT + "name indirection: " + text); + } + + final int prefixLen = PREFIX_TEXT.length(); + final int size = text.length(); + if (size < prefixLen) { + break; + } + + sb = null; + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (text.startsWith(PREFIX_TEXT, pos)) { + if (sb == null) { + sb = new StringBuilder(text.substring(0, pos)); + } + final int end = searchTextNameEnd(text, pos + prefixLen); + final String name = text.substring(pos + prefixLen, end); + sb.append(getText(name)); + pos = end - 1; + } else if (c == BACKSLASH) { + 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 TextUtils.isEmpty(text) ? null : text; + } + + // These texts' name should be aligned with the @string/<name> in + // values*/strings-action-keys.xml. + static final String[] RESOURCE_NAMES = { // Labels for action. "label_go_key", - // "label_search_key", "label_send_key", "label_next_key", "label_done_key", @@ -100,3422 +146,4 @@ public final class KeyboardTextsSet { "label_pause_key", "label_wait_key", }; - - private static final String[] NAMES = { - /* 0 */ "more_keys_for_a", - /* 1 */ "more_keys_for_e", - /* 2 */ "more_keys_for_i", - /* 3 */ "more_keys_for_o", - /* 4 */ "more_keys_for_u", - /* 5 */ "more_keys_for_s", - /* 6 */ "more_keys_for_n", - /* 7 */ "more_keys_for_c", - /* 8 */ "more_keys_for_y", - /* 9 */ "more_keys_for_d", - /* 10 */ "more_keys_for_r", - /* 11 */ "more_keys_for_t", - /* 12 */ "more_keys_for_z", - /* 13 */ "more_keys_for_k", - /* 14 */ "more_keys_for_l", - /* 15 */ "more_keys_for_g", - /* 16 */ "more_keys_for_v", - /* 17 */ "more_keys_for_h", - /* 18 */ "more_keys_for_j", - /* 19 */ "more_keys_for_w", - /* 20 */ "keylabel_for_nordic_row1_11", - /* 21 */ "keylabel_for_nordic_row2_10", - /* 22 */ "keylabel_for_nordic_row2_11", - /* 23 */ "more_keys_for_nordic_row2_10", - /* 24 */ "more_keys_for_nordic_row2_11", - /* 25 */ "keylabel_for_east_slavic_row1_9", - /* 26 */ "keylabel_for_east_slavic_row1_12", - /* 27 */ "keylabel_for_east_slavic_row2_1", - /* 28 */ "keylabel_for_east_slavic_row2_11", - /* 29 */ "keylabel_for_east_slavic_row3_5", - /* 30 */ "more_keys_for_cyrillic_u", - /* 31 */ "more_keys_for_cyrillic_ka", - /* 32 */ "more_keys_for_cyrillic_en", - /* 33 */ "more_keys_for_cyrillic_ghe", - /* 34 */ "more_keys_for_east_slavic_row2_1", - /* 35 */ "more_keys_for_cyrillic_a", - /* 36 */ "more_keys_for_cyrillic_o", - /* 37 */ "more_keys_for_cyrillic_soft_sign", - /* 38 */ "more_keys_for_east_slavic_row2_11", - /* 39 */ "keylabel_for_south_slavic_row1_6", - /* 40 */ "keylabel_for_south_slavic_row2_11", - /* 41 */ "keylabel_for_south_slavic_row3_1", - /* 42 */ "keylabel_for_south_slavic_row3_8", - /* 43 */ "more_keys_for_cyrillic_ie", - /* 44 */ "more_keys_for_cyrillic_i", - /* 45 */ "label_to_alpha_key", - /* 46 */ "single_quotes", - /* 47 */ "double_quotes", - /* 48 */ "single_angle_quotes", - /* 49 */ "double_angle_quotes", - /* 50 */ "more_keys_for_currency_dollar", - /* 51 */ "keylabel_for_currency", - /* 52 */ "more_keys_for_currency", - /* 53 */ "more_keys_for_punctuation", - /* 54 */ "more_keys_for_star", - /* 55 */ "more_keys_for_bullet", - /* 56 */ "more_keys_for_plus", - /* 57 */ "more_keys_for_left_parenthesis", - /* 58 */ "more_keys_for_right_parenthesis", - /* 59 */ "more_keys_for_less_than", - /* 60 */ "more_keys_for_greater_than", - /* 61 */ "more_keys_for_arabic_diacritics", - /* 62 */ "keyhintlabel_for_arabic_diacritics", - /* 63 */ "keylabel_for_symbols_1", - /* 64 */ "keylabel_for_symbols_2", - /* 65 */ "keylabel_for_symbols_3", - /* 66 */ "keylabel_for_symbols_4", - /* 67 */ "keylabel_for_symbols_5", - /* 68 */ "keylabel_for_symbols_6", - /* 69 */ "keylabel_for_symbols_7", - /* 70 */ "keylabel_for_symbols_8", - /* 71 */ "keylabel_for_symbols_9", - /* 72 */ "keylabel_for_symbols_0", - /* 73 */ "label_to_symbol_key", - /* 74 */ "label_to_symbol_with_microphone_key", - /* 75 */ "additional_more_keys_for_symbols_1", - /* 76 */ "additional_more_keys_for_symbols_2", - /* 77 */ "additional_more_keys_for_symbols_3", - /* 78 */ "additional_more_keys_for_symbols_4", - /* 79 */ "additional_more_keys_for_symbols_5", - /* 80 */ "additional_more_keys_for_symbols_6", - /* 81 */ "additional_more_keys_for_symbols_7", - /* 82 */ "additional_more_keys_for_symbols_8", - /* 83 */ "additional_more_keys_for_symbols_9", - /* 84 */ "additional_more_keys_for_symbols_0", - /* 85 */ "more_keys_for_symbols_1", - /* 86 */ "more_keys_for_symbols_2", - /* 87 */ "more_keys_for_symbols_3", - /* 88 */ "more_keys_for_symbols_4", - /* 89 */ "more_keys_for_symbols_5", - /* 90 */ "more_keys_for_symbols_6", - /* 91 */ "more_keys_for_symbols_7", - /* 92 */ "more_keys_for_symbols_8", - /* 93 */ "more_keys_for_symbols_9", - /* 94 */ "more_keys_for_symbols_0", - /* 95 */ "keylabel_for_comma", - /* 96 */ "more_keys_for_comma", - /* 97 */ "keylabel_for_symbols_question", - /* 98 */ "keylabel_for_symbols_semicolon", - /* 99 */ "keylabel_for_symbols_percent", - /* 100 */ "more_keys_for_symbols_exclamation", - /* 101 */ "more_keys_for_symbols_question", - /* 102 */ "more_keys_for_symbols_semicolon", - /* 103 */ "more_keys_for_symbols_percent", - /* 104 */ "keylabel_for_tablet_comma", - /* 105 */ "keyhintlabel_for_tablet_comma", - /* 106 */ "more_keys_for_tablet_comma", - /* 107 */ "keyhintlabel_for_period", - /* 108 */ "more_keys_for_period", - /* 109 */ "keylabel_for_apostrophe", - /* 110 */ "keyhintlabel_for_apostrophe", - /* 111 */ "more_keys_for_apostrophe", - /* 112 */ "more_keys_for_q", - /* 113 */ "more_keys_for_x", - /* 114 */ "keylabel_for_q", - /* 115 */ "keylabel_for_w", - /* 116 */ "keylabel_for_y", - /* 117 */ "keylabel_for_x", - /* 118 */ "keylabel_for_spanish_row2_10", - /* 119 */ "more_keys_for_am_pm", - /* 120 */ "settings_as_more_key", - /* 121 */ "shortcut_as_more_key", - /* 122 */ "action_next_as_more_key", - /* 123 */ "action_previous_as_more_key", - /* 124 */ "label_to_more_symbol_key", - /* 125 */ "label_to_more_symbol_for_tablet_key", - /* 126 */ "label_tab_key", - /* 127 */ "label_to_phone_numeric_key", - /* 128 */ "label_to_phone_symbols_key", - /* 129 */ "label_time_am", - /* 130 */ "label_time_pm", - /* 131 */ "keylabel_for_popular_domain", - /* 132 */ "more_keys_for_popular_domain", - /* 133 */ "more_keys_for_smiley", - /* 134 */ "single_laqm_raqm", - /* 135 */ "single_laqm_raqm_rtl", - /* 136 */ "single_raqm_laqm", - /* 137 */ "double_laqm_raqm", - /* 138 */ "double_laqm_raqm_rtl", - /* 139 */ "double_raqm_laqm", - /* 140 */ "single_lqm_rqm", - /* 141 */ "single_9qm_lqm", - /* 142 */ "single_9qm_rqm", - /* 143 */ "double_lqm_rqm", - /* 144 */ "double_9qm_lqm", - /* 145 */ "double_9qm_rqm", - /* 146 */ "more_keys_for_single_quote", - /* 147 */ "more_keys_for_double_quote", - /* 148 */ "more_keys_for_tablet_double_quote", - /* 149 */ "emoji_key_as_more_key", - }; - - private static final String EMPTY = ""; - - /* Default texts */ - private static final String[] LANGUAGE_DEFAULT = { - /* 0~ */ - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - /* ~44 */ - // Label for "switch to alphabetic" key. - /* 45 */ "ABC", - /* 46 */ "!text/single_lqm_rqm", - /* 47 */ "!text/double_lqm_rqm", - /* 48 */ "!text/single_laqm_raqm", - /* 49 */ "!text/double_laqm_raqm", - // U+00A2: "¢" CENT SIGN - // U+00A3: "£" POUND SIGN - // U+20AC: "€" EURO SIGN - // U+00A5: "¥" YEN SIGN - // U+20B1: "₱" PESO SIGN - /* 50 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", - /* 51 */ "$", - /* 52 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1", - /* 53 */ "!fixedColumnOrder!8,;,/,(,),#,!,\\,,?,&,\\%,+,\",-,:,',@", - // U+2020: "†" DAGGER - // U+2021: "‡" DOUBLE DAGGER - // U+2605: "★" BLACK STAR - /* 54 */ "\u2020,\u2021,\u2605", - // U+266A: "♪" EIGHTH NOTE - // U+2665: "♥" BLACK HEART SUIT - // U+2660: "♠" BLACK SPADE SUIT - // U+2666: "♦" BLACK DIAMOND SUIT - // U+2663: "♣" BLACK CLUB SUIT - /* 55 */ "\u266A,\u2665,\u2660,\u2666,\u2663", - // U+00B1: "±" PLUS-MINUS SIGN - /* 56 */ "\u00B1", - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 57 */ "!fixedColumnOrder!3,<,{,[", - /* 58 */ "!fixedColumnOrder!3,>,},]", - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - /* 59 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB", - /* 60 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB", - /* 61 */ EMPTY, - /* 62 */ EMPTY, - /* 63 */ "1", - /* 64 */ "2", - /* 65 */ "3", - /* 66 */ "4", - /* 67 */ "5", - /* 68 */ "6", - /* 69 */ "7", - /* 70 */ "8", - /* 71 */ "9", - /* 72 */ "0", - // Label for "switch to symbols" key. - /* 73 */ "?123", - // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - // part because it'll be appended by the code. - /* 74 */ "123", - /* 75~ */ - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, - /* ~84 */ - // U+00B9: "¹" SUPERSCRIPT ONE - // U+00BD: "½" VULGAR FRACTION ONE HALF - // U+2153: "⅓" VULGAR FRACTION ONE THIRD - // U+00BC: "¼" VULGAR FRACTION ONE QUARTER - // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH - /* 85 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", - // U+00B2: "²" SUPERSCRIPT TWO - // U+2154: "⅔" VULGAR FRACTION TWO THIRDS - /* 86 */ "\u00B2,\u2154", - // U+00B3: "³" SUPERSCRIPT THREE - // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS - // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS - /* 87 */ "\u00B3,\u00BE,\u215C", - // U+2074: "⁴" SUPERSCRIPT FOUR - /* 88 */ "\u2074", - // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS - /* 89 */ "\u215D", - /* 90 */ EMPTY, - // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS - /* 91 */ "\u215E", - /* 92 */ EMPTY, - /* 93 */ EMPTY, - // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N - // U+2205: "∅" EMPTY SET - /* 94 */ "\u207F,\u2205", - /* 95 */ ",", - /* 96 */ EMPTY, - /* 97 */ "?", - /* 98 */ ";", - /* 99 */ "%", - // U+00A1: "¡" INVERTED EXCLAMATION MARK - /* 100 */ "\u00A1", - // U+00BF: "¿" INVERTED QUESTION MARK - /* 101 */ "\u00BF", - /* 102 */ EMPTY, - // U+2030: "‰" PER MILLE SIGN - /* 103 */ "\u2030", - /* 104 */ ",", - /* 105~ */ - EMPTY, EMPTY, EMPTY, - /* ~107 */ - // U+2026: "…" HORIZONTAL ELLIPSIS - /* 108 */ "\u2026", - /* 109 */ "\'", - /* 110 */ "\"", - /* 111 */ "\"", - /* 112 */ EMPTY, - /* 113 */ EMPTY, - /* 114 */ "q", - /* 115 */ "w", - /* 116 */ "y", - /* 117 */ "x", - /* 118 */ EMPTY, - /* 119 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm", - /* 120 */ "!icon/settings_key|!code/key_settings", - /* 121 */ "!icon/shortcut_key|!code/key_shortcut", - /* 122 */ "!hasLabels!,!text/label_next_key|!code/key_action_next", - /* 123 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous", - // Label for "switch to more symbol" modifier key. Must be short to fit on key! - /* 124 */ "= \\ <", - // Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! - /* 125 */ "~ [ <", - // Label for "Tab" key. Must be short to fit on key! - /* 126 */ "Tab", - // Label for "switch to phone numeric" key. Must be short to fit on key! - /* 127 */ "123", - // Label for "switch to phone symbols" key. Must be short to fit on key! - // U+FF0A: "*" FULLWIDTH ASTERISK - // U+FF03: "#" FULLWIDTH NUMBER SIGN - /* 128 */ "\uFF0A\uFF03", - // Key label for "ante meridiem" - /* 129 */ "AM", - // Key label for "post meridiem" - /* 130 */ "PM", - /* 131 */ ".com", - // popular web domains for the locale - most popular, displayed on the keyboard - /* 132 */ "!hasLabels!,.net,.org,.gov,.edu", - /* 133 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ", - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // The following characters don't need BIDI mirroring. - // U+2018: "‘" LEFT SINGLE QUOTATION MARK - // U+2019: "’" RIGHT SINGLE QUOTATION MARK - // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - // U+201C: "“" LEFT DOUBLE QUOTATION MARK - // U+201D: "”" RIGHT DOUBLE QUOTATION MARK - // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - // Abbreviations are: - // laqm: LEFT-POINTING ANGLE QUOTATION MARK - // raqm: RIGHT-POINTING ANGLE QUOTATION MARK - // rtl: Right-To-Left script order - // lqm: LEFT QUOTATION MARK - // rqm: RIGHT QUOTATION MARK - // 9qm: LOW-9 QUOTATION MARK - // The following each quotation mark pair consist of - // <opening quotation mark>, <closing quotation mark> - // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. - /* 134 */ "\u2039,\u203A", - /* 135 */ "\u2039|\u203A,\u203A|\u2039", - /* 136 */ "\u203A,\u2039", - /* 137 */ "\u00AB,\u00BB", - /* 138 */ "\u00AB|\u00BB,\u00BB|\u00AB", - /* 139 */ "\u00BB,\u00AB", - // The following each quotation mark triplet consists of - // <another quotation mark>, <opening quotation mark>, <closing quotation mark> - // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. - /* 140 */ "\u201A,\u2018,\u2019", - /* 141 */ "\u2019,\u201A,\u2018", - /* 142 */ "\u2018,\u201A,\u2019", - /* 143 */ "\u201E,\u201C,\u201D", - /* 144 */ "\u201D,\u201E,\u201C", - /* 145 */ "\u201C,\u201E,\u201D", - /* 146 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes", - /* 147 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes", - /* 148 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes", - /* 149 */ "!icon/emoji_key|!code/key_emoji", - }; - - /* Language af: Afrikaans */ - private static final String[] LANGUAGE_af = { - // This is the same as Dutch except more keys of y and demoting vowels with diaeresis. - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E2,\u00E4,\u00E0,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 2 */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F4,\u00F6,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B", - /* 5 */ null, - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - /* 7 */ null, - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 8 */ "\u00FD,\u0133", - }; - - /* Language ar: Arabic */ - private static final String[] LANGUAGE_ar = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0623: "ا" ARABIC LETTER ALEF - // U+200C: ZERO WIDTH NON-JOINER - // U+0628: "ب" ARABIC LETTER BEH - // U+062C: "پ" ARABIC LETTER PEH - /* 45 */ "\u0623\u200C\u0628\u200C\u062C", - /* 46 */ null, - /* 47 */ null, - /* 48 */ "!text/single_laqm_raqm_rtl", - /* 49 */ "!text/double_laqm_raqm_rtl", - /* 50~ */ - null, null, null, - /* ~52 */ - // U+061F: "؟" ARABIC QUESTION MARK - // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON - /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(", - // U+2605: "★" BLACK STAR - // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 54 */ "\u2605,\u066D", - // U+266A: "♪" EIGHTH NOTE - /* 55 */ "\u266A", - /* 56 */ null, - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS - // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS - /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", - // U+0655: "ٕ" ARABIC HAMZA BELOW - // U+0654: "ٔ" ARABIC HAMZA ABOVE - // U+0652: "ْ" ARABIC SUKUN - // U+064D: "ٍ" ARABIC KASRATAN - // U+064C: "ٌ" ARABIC DAMMATAN - // U+064B: "ً" ARABIC FATHATAN - // U+0651: "ّ" ARABIC SHADDA - // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF - // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF - // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+0650: "ِ" ARABIC KASRA - // U+064F: "ُ" ARABIC DAMMA - // U+064E: "َ" ARABIC FATHA - // U+0640: "ـ" ARABIC TATWEEL - // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. - /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640", - /* 62 */ "\u0651", - // U+0661: "١" ARABIC-INDIC DIGIT ONE - /* 63 */ "\u0661", - // U+0662: "٢" ARABIC-INDIC DIGIT TWO - /* 64 */ "\u0662", - // U+0663: "٣" ARABIC-INDIC DIGIT THREE - /* 65 */ "\u0663", - // U+0664: "٤" ARABIC-INDIC DIGIT FOUR - /* 66 */ "\u0664", - // U+0665: "٥" ARABIC-INDIC DIGIT FIVE - /* 67 */ "\u0665", - // U+0666: "٦" ARABIC-INDIC DIGIT SIX - /* 68 */ "\u0666", - // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN - /* 69 */ "\u0667", - // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT - /* 70 */ "\u0668", - // U+0669: "٩" ARABIC-INDIC DIGIT NINE - /* 71 */ "\u0669", - // U+0660: "٠" ARABIC-INDIC DIGIT ZERO - /* 72 */ "\u0660", - // Label for "switch to symbols" key. - // U+061F: "؟" ARABIC QUESTION MARK - /* 73 */ "\u0663\u0662\u0661\u061F", - // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - // part because it'll be appended by the code. - /* 74 */ "\u0663\u0662\u0661", - /* 75 */ "1", - /* 76 */ "2", - /* 77 */ "3", - /* 78 */ "4", - /* 79 */ "5", - /* 80 */ "6", - /* 81 */ "7", - /* 82 */ "8", - /* 83 */ "9", - // U+066B: "٫" ARABIC DECIMAL SEPARATOR - // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 84 */ "0,\u066B,\u066C", - /* 85~ */ - null, null, null, null, null, null, null, null, null, null, - /* ~94 */ - // U+060C: "،" ARABIC COMMA - /* 95 */ "\u060C", - /* 96 */ "\\,", - /* 97 */ "\u061F", - /* 98 */ "\u061B", - // U+066A: "٪" ARABIC PERCENT SIGN - /* 99 */ "\u066A", - /* 100 */ null, - /* 101 */ "?", - /* 102 */ ";", - // U+2030: "‰" PER MILLE SIGN - /* 103 */ "\\%,\u2030", - /* 104~ */ - null, null, null, null, null, - /* ~108 */ - // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON - // U+061F: "؟" ARABIC QUESTION MARK - /* 109 */ "\u060C", - /* 110 */ "\u061F", - /* 111 */ "\u061F,\u061B,!,:,-,/,\',\"", - }; - - /* Language az: Azerbaijani */ - private static final String[] LANGUAGE_az = { - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - /* 0 */ "\u00E2", - // U+0259: "ə" LATIN SMALL LETTER SCHWA - /* 1 */ "\u0259", - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u015F,\u00DF,\u015B,\u0161", - /* 6 */ null, - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - /* 8~ */ - null, null, null, null, null, null, null, - /* ~14 */ - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u011F", - }; - - /* Language be: Belarusian */ - private static final String[] LANGUAGE_be = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~24 */ - // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U - /* 25 */ "\u045E", - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 26 */ "\u0451", - // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 27 */ "\u044B", - // U+044D: "э" CYRILLIC SMALL LETTER E - /* 28 */ "\u044D", - // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* 29 */ "\u0456", - /* 30~ */ - null, null, null, null, null, null, null, - /* ~36 */ - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 37 */ "\u044A", - /* 38~ */ - null, null, null, null, null, - /* ~42 */ - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 43 */ "\u0451", - /* 44 */ null, - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language bg: Bulgarian */ - private static final String[] LANGUAGE_bg = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ null, - // single_quotes of Bulgarian is default single_quotes_right_left. - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language ca: Catalan */ - private static final String[] LANGUAGE_ca = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E0,\u00E1,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EB,\u00EA,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", - /* 5 */ null, - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - /* 8~ */ - null, null, null, null, null, null, - /* ~13 */ - // U+00B7: "·" MIDDLE DOT - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "l\u00B7l,\u0142", - /* 15~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - /* ~52 */ - // U+00B7: "·" MIDDLE DOT - /* 53 */ "!fixedColumnOrder!9,;,/,(,),#,\u00B7,!,\\,,?,&,\\%,+,\",-,:,',@", - /* 54~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, - /* ~107 */ - /* 108 */ "?,\u00B7", - /* 109~ */ - null, null, null, null, null, null, null, null, null, - /* ~117 */ - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - /* 118 */ "\u00E7", - }; - - /* Language cs: Czech */ - private static final String[] LANGUAGE_cs = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u011B,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - /* 5 */ "\u0161,\u00DF,\u015B", - // U+0148: "ň" LATIN SMALL LETTER N WITH CARON - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u0148,\u00F1,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u00E7,\u0107", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u010F", - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - /* 10 */ "\u0159", - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - /* 11 */ "\u0165", - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - /* 12 */ "\u017E,\u017A,\u017C", - /* 13~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language da: Danish */ - private static final String[] LANGUAGE_da = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E4,\u00E0,\u00E2,\u00E3,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - /* 1 */ "\u00E9,\u00EB", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - /* 2 */ "\u00ED,\u00EF", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F4,\u00F2,\u00F5,\u0153,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u00DF,\u015B,\u0161", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - /* 7 */ null, - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+00F0: "ð" LATIN SMALL LETTER ETH - /* 9 */ "\u00F0", - /* 10~ */ - null, null, null, null, - /* ~13 */ - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u0142", - /* 15~ */ - null, null, null, null, null, - /* ~19 */ - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - /* 20 */ "\u00E5", - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 21 */ "\u00E6", - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 22 */ "\u00F8", - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - /* 23 */ "\u00E4", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - /* 24 */ "\u00F6", - /* 25~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language de: German */ - private static final String[] LANGUAGE_de = { - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E4,\u00E2,\u00E0,\u00E1,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0117", - /* 2 */ null, - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F6,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u00F8,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u00DF,\u015B,\u0161", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - /* 7~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language el: Greek */ - private static final String[] LANGUAGE_el = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0391: "Α" GREEK CAPITAL LETTER ALPHA - // U+0392: "Β" GREEK CAPITAL LETTER BETA - // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA - /* 45 */ "\u0391\u0392\u0393", - }; - - /* Language en: English */ - private static final String[] LANGUAGE_en = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - /* 5 */ "\u00DF", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 6 */ "\u00F1", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - /* 7 */ "\u00E7", - }; - - /* Language eo: Esperanto */ - private static final String[] LANGUAGE_eo = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101,\u0103,\u0105,\u00AA", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u011B,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 2 */ "\u00ED,\u00EE,\u00EF,\u0129,\u00EC,\u012F,\u012B,\u0131,\u0133", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D,\u0151,\u00BA", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - // U+00B5: "µ" MICRO SIGN - /* 4 */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B,\u0169,\u0171,\u0173,\u00B5", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - /* 5 */ "\u00DF,\u0161,\u015B,\u0219,\u015F", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+0148: "ň" LATIN SMALL LETTER N WITH CARON - // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - // U+014B: "ŋ" LATIN SMALL LETTER ENG - /* 6 */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B", - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE - /* 7 */ "\u0107,\u010D,\u00E7,\u010B", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - // U+00FE: "þ" LATIN SMALL LETTER THORN - /* 8 */ "y,\u00FD,\u0177,\u00FF,\u00FE", - // U+00F0: "ð" LATIN SMALL LETTER ETH - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE - /* 9 */ "\u00F0,\u010F,\u0111", - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - /* 10 */ "\u0159,\u0155,\u0157", - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE - /* 11 */ "\u0165,\u021B,\u0163,\u0167", - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - /* 12 */ "\u017A,\u017C,\u017E", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - // U+0138: "ĸ" LATIN SMALL LETTER KRA - /* 13 */ "\u0137,\u0138", - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u013A,\u013C,\u013E,\u0140,\u0142", - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - /* 15 */ "\u011F,\u0121,\u0123", - // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX - /* 16 */ "w,\u0175", - // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX - // U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE - /* 17 */ "\u0125,\u0127", - /* 18 */ null, - // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX - /* 19 */ "w,\u0175", - /* 20~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, - /* ~111 */ - /* 112 */ "q", - /* 113 */ "x", - // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX - /* 114 */ "\u015D", - // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX - /* 115 */ "\u011D", - // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE - /* 116 */ "\u016D", - // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX - /* 117 */ "\u0109", - // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX - /* 118 */ "\u0135", - }; - - /* Language es: Spanish */ - private static final String[] LANGUAGE_es = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", - /* 5 */ null, - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - /* 8~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~52 */ - // U+00A1: "¡" INVERTED EXCLAMATION MARK - // U+00BF: "¿" INVERTED QUESTION MARK - /* 53 */ "!fixedColumnOrder!4,;,!,\\,,?,:,\u00A1,@,\u00BF", - /* 54~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, - /* ~105 */ - // U+00A1: "¡" INVERTED EXCLAMATION MARK - /* 106 */ "!,\u00A1", - /* 107 */ null, - // U+00BF: "¿" INVERTED QUESTION MARK - /* 108 */ "?,\u00BF", - /* 109 */ "\"", - /* 110 */ "\'", - /* 111 */ "\'", - /* 112~ */ - null, null, null, null, null, null, - /* ~117 */ - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 118 */ "\u00F1", - }; - - /* Language et: Estonian */ - private static final String[] LANGUAGE_et = { - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - /* 0 */ "\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6,\u0105", - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - /* 1 */ "\u0113,\u00E8,\u0117,\u00E9,\u00EA,\u00EB,\u0119,\u011B", - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - /* 2 */ "\u012B,\u00EC,\u012F,\u00ED,\u00EE,\u00EF,\u0131", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 3 */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - /* 4 */ "\u00FC,\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u016F,\u0171", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - /* 5 */ "\u0161,\u00DF,\u015B,\u015F", - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u0146,\u00F1,\u0144,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u00E7,\u0107", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u010F", - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - /* 10 */ "\u0157,\u0159,\u0155", - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - /* 11 */ "\u0163,\u0165", - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - /* 12 */ "\u017E,\u017C,\u017A", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - /* 13 */ "\u0137", - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - /* 14 */ "\u013C,\u0142,\u013A,\u013E", - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u0123,\u011F", - /* 16~ */ - null, null, null, null, - /* ~19 */ - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - /* 20 */ "\u00FC", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - /* 21 */ "\u00F6", - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - /* 22 */ "\u00E4", - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - /* 23 */ "\u00F5", - /* 24~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language fa: Persian */ - private static final String[] LANGUAGE_fa = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0627: "ا" ARABIC LETTER ALEF - // U+200C: ZERO WIDTH NON-JOINER - // U+0628: "ب" ARABIC LETTER BEH - // U+067E: "پ" ARABIC LETTER PEH - /* 45 */ "\u0627\u200C\u0628\u200C\u067E", - /* 46 */ null, - /* 47 */ null, - /* 48 */ "!text/single_laqm_raqm_rtl", - /* 49 */ "!text/double_laqm_raqm_rtl", - /* 50 */ null, - // U+FDFC: "﷼" RIAL SIGN - /* 51 */ "\uFDFC", - /* 52 */ null, - // U+061F: "؟" ARABIC QUESTION MARK - // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON - /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(", - // U+2605: "★" BLACK STAR - // U+066D: "٭" ARABIC FIVE POINTED STAR - /* 54 */ "\u2605,\u066D", - // U+266A: "♪" EIGHTH NOTE - /* 55 */ "\u266A", - /* 56 */ null, - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS - // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS - /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]", - /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[", - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>", - /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<", - // U+0655: "ٕ" ARABIC HAMZA BELOW - // U+0652: "ْ" ARABIC SUKUN - // U+0651: "ّ" ARABIC SHADDA - // U+064C: "ٌ" ARABIC DAMMATAN - // U+064D: "ٍ" ARABIC KASRATAN - // U+064B: "ً" ARABIC FATHATAN - // U+0654: "ٔ" ARABIC HAMZA ABOVE - // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF - // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF - // U+0653: "ٓ" ARABIC MADDAH ABOVE - // U+064F: "ُ" ARABIC DAMMA - // U+0650: "ِ" ARABIC KASRA - // U+064E: "َ" ARABIC FATHA - // U+0640: "ـ" ARABIC TATWEEL - // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. - // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. - /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640", - /* 62 */ "\u064B", - // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE - /* 63 */ "\u06F1", - // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO - /* 64 */ "\u06F2", - // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE - /* 65 */ "\u06F3", - // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR - /* 66 */ "\u06F4", - // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE - /* 67 */ "\u06F5", - // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX - /* 68 */ "\u06F6", - // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN - /* 69 */ "\u06F7", - // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT - /* 70 */ "\u06F8", - // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE - /* 71 */ "\u06F9", - // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO - /* 72 */ "\u06F0", - // Label for "switch to symbols" key. - // U+061F: "؟" ARABIC QUESTION MARK - /* 73 */ "\u06F3\u06F2\u06F1\u061F", - // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - // part because it'll be appended by the code. - /* 74 */ "\u06F3\u06F2\u06F1", - /* 75 */ "1", - /* 76 */ "2", - /* 77 */ "3", - /* 78 */ "4", - /* 79 */ "5", - /* 80 */ "6", - /* 81 */ "7", - /* 82 */ "8", - /* 83 */ "9", - // U+066B: "٫" ARABIC DECIMAL SEPARATOR - // U+066C: "٬" ARABIC THOUSANDS SEPARATOR - /* 84 */ "0,\u066B,\u066C", - /* 85~ */ - null, null, null, null, null, null, null, null, null, null, - /* ~94 */ - // U+060C: "،" ARABIC COMMA - /* 95 */ "\u060C", - /* 96 */ "\\,", - /* 97 */ "\u061F", - /* 98 */ "\u061B", - // U+066A: "٪" ARABIC PERCENT SIGN - /* 99 */ "\u066A", - /* 100 */ null, - /* 101 */ "?", - /* 102 */ ";", - // U+2030: "‰" PER MILLE SIGN - /* 103 */ "\\%,\u2030", - // U+060C: "،" ARABIC COMMA - // U+061B: "؛" ARABIC SEMICOLON - // U+061F: "؟" ARABIC QUESTION MARK - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - /* 104 */ "\u060C", - /* 105 */ "!", - /* 106 */ "!,\\,", - /* 107 */ "\u061F", - /* 108 */ "\u061F,?", - /* 109 */ "\u060C", - /* 110 */ "\u061F", - /* 111 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB", - }; - - /* Language fi: Finnish */ - private static final String[] LANGUAGE_fi = { - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E6,\u00E0,\u00E1,\u00E2,\u00E3,\u0101", - /* 1 */ null, - /* 2 */ null, - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - /* 4 */ "\u00FC", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - /* 5 */ "\u0161,\u00DF,\u015B", - /* 6~ */ - null, null, null, null, null, null, - /* ~11 */ - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - /* 12 */ "\u017E,\u017A,\u017C", - /* 13~ */ - null, null, null, null, null, null, null, - /* ~19 */ - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - /* 20 */ "\u00E5", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - /* 21 */ "\u00F6", - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - /* 22 */ "\u00E4", - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 23 */ "\u00F8", - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 24 */ "\u00E6", - }; - - /* Language fr: French */ - private static final String[] LANGUAGE_fr = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E0,\u00E2,%,\u00E6,\u00E1,\u00E4,\u00E3,\u00E5,\u0101,\u00AA", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,%,\u0119,\u0117,\u0113", - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00EE,%,\u00EF,\u00EC,\u00ED,\u012F,\u012B", - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F4,\u0153,%,\u00F6,\u00F2,\u00F3,\u00F5,\u00F8,\u014D,\u00BA", - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00F9,\u00FB,%,\u00FC,\u00FA,\u016B", - /* 5 */ null, - /* 6 */ null, - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "%,\u00FF", - }; - - /* Language hi: Hindi */ - private static final String[] LANGUAGE_hi = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0915: "क" DEVANAGARI LETTER KA - // U+0916: "ख" DEVANAGARI LETTER KHA - // U+0917: "ग" DEVANAGARI LETTER GA - /* 45 */ "\u0915\u0916\u0917", - /* 46~ */ - null, null, null, null, null, - /* ~50 */ - // U+20B9: "₹" INDIAN RUPEE SIGN - /* 51 */ "\u20B9", - /* 52~ */ - null, null, null, null, null, null, null, null, null, null, null, - /* ~62 */ - // U+0967: "१" DEVANAGARI DIGIT ONE - /* 63 */ "\u0967", - // U+0968: "२" DEVANAGARI DIGIT TWO - /* 64 */ "\u0968", - // U+0969: "३" DEVANAGARI DIGIT THREE - /* 65 */ "\u0969", - // U+096A: "४" DEVANAGARI DIGIT FOUR - /* 66 */ "\u096A", - // U+096B: "५" DEVANAGARI DIGIT FIVE - /* 67 */ "\u096B", - // U+096C: "६" DEVANAGARI DIGIT SIX - /* 68 */ "\u096C", - // U+096D: "७" DEVANAGARI DIGIT SEVEN - /* 69 */ "\u096D", - // U+096E: "८" DEVANAGARI DIGIT EIGHT - /* 70 */ "\u096E", - // U+096F: "९" DEVANAGARI DIGIT NINE - /* 71 */ "\u096F", - // U+0966: "०" DEVANAGARI DIGIT ZERO - /* 72 */ "\u0966", - // Label for "switch to symbols" key. - /* 73 */ "?\u0967\u0968\u0969", - // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - // part because it'll be appended by the code. - /* 74 */ "\u0967\u0968\u0969", - /* 75 */ "1", - /* 76 */ "2", - /* 77 */ "3", - /* 78 */ "4", - /* 79 */ "5", - /* 80 */ "6", - /* 81 */ "7", - /* 82 */ "8", - /* 83 */ "9", - /* 84 */ "0", - }; - - /* Language hr: Croatian */ - private static final String[] LANGUAGE_hr = { - /* 0~ */ - null, null, null, null, null, - /* ~4 */ - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - /* 5 */ "\u0161,\u015B,\u00DF", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - /* 7 */ "\u010D,\u0107,\u00E7", - /* 8 */ null, - // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE - /* 9 */ "\u0111", - /* 10 */ null, - /* 11 */ null, - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - /* 12 */ "\u017E,\u017A,\u017C", - /* 13~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language hu: Hungarian */ - private static final String[] LANGUAGE_hu = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F6,\u0151,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u0171,\u00FB,\u00F9,\u016B", - /* 5~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language hy: Armenian */ - private static final String[] LANGUAGE_hy = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - /* ~52 */ - // U+058A: "֊" ARMENIAN HYPHEN - // U+055C: "՜" ARMENIAN EXCLAMATION MARK - // U+055D: "՝" ARMENIAN COMMA - // U+055E: "՞" ARMENIAN QUESTION MARK - // U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING - // U+055A: "՚" ARMENIAN APOSTROPHE - // U+055B: "՛" ARMENIAN EMPHASIS MARK - // U+055F: "՟" ARMENIAN ABBREVIATION MARK - /* 53 */ "!fixedColumnOrder!8,!,?,\\,,.,\u058A,\u055C,\u055D,\u055E,:,;,@,\u0559,\u055A,\u055B,\u055F", - /* 54~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, - /* ~99 */ - // U+055C: "՜" ARMENIAN EXCLAMATION MARK - // U+00A1: "¡" INVERTED EXCLAMATION MARK - /* 100 */ "\u055C,\u00A1", - // U+055E: "՞" ARMENIAN QUESTION MARK - // U+00BF: "¿" INVERTED QUESTION MARK - /* 101 */ "\u055E,\u00BF", - }; - - /* Language is: Icelandic */ - private static final String[] LANGUAGE_is = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E4,\u00E6,\u00E5,\u00E0,\u00E2,\u00E3,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00EB,\u00E8,\u00EA,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", - /* 5~ */ - null, null, null, - /* ~7 */ - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+00F0: "ð" LATIN SMALL LETTER ETH - /* 9 */ "\u00F0", - /* 10 */ null, - // U+00FE: "þ" LATIN SMALL LETTER THORN - /* 11 */ "\u00FE", - /* 12~ */ - null, null, null, null, null, null, null, null, - /* ~19 */ - // U+00F0: "ð" LATIN SMALL LETTER ETH - /* 20 */ "\u00F0", - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 21 */ "\u00E6", - // U+00FE: "þ" LATIN SMALL LETTER THORN - /* 22 */ "\u00FE", - /* 23~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language it: Italian */ - private static final String[] LANGUAGE_it = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101,\u00AA", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u0117,\u0113", - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00EC,\u00ED,\u00EE,\u00EF,\u012F,\u012B", - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F6,\u00F5,\u0153,\u00F8,\u014D,\u00BA", - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00F9,\u00FA,\u00FB,\u00FC,\u016B", - }; - - /* Language iw: Hebrew */ - private static final String[] LANGUAGE_iw = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+05D0: "א" HEBREW LETTER ALEF - // U+05D1: "ב" HEBREW LETTER BET - // U+05D2: "ג" HEBREW LETTER GIMEL - /* 45 */ "\u05D0\u05D1\u05D2", - // The following characters don't need BIDI mirroring. - // U+2018: "‘" LEFT SINGLE QUOTATION MARK - // U+2019: "’" RIGHT SINGLE QUOTATION MARK - // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - // U+201C: "“" LEFT DOUBLE QUOTATION MARK - // U+201D: "”" RIGHT DOUBLE QUOTATION MARK - // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK - /* 46 */ "\u2018,\u2019,\u201A", - /* 47 */ "\u201C,\u201D,\u201E", - /* 48 */ "!text/single_laqm_raqm_rtl", - /* 49 */ "!text/double_laqm_raqm_rtl", - /* 50 */ null, - // U+20AA: "₪" NEW SHEQEL SIGN - /* 51 */ "\u20AA", - /* 52 */ null, - /* 53 */ "!fixedColumnOrder!8,;,/,(|),)|(,#,!,\\,,?,&,\\%,+,\",-,:,',@", - // U+2605: "★" BLACK STAR - /* 54 */ "\u2605", - /* 55 */ null, - // U+00B1: "±" PLUS-MINUS SIGN - // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN - /* 56 */ "\u00B1,\uFB29", - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt - /* 57 */ "!fixedColumnOrder!3,<|>,{|},[|]", - /* 58 */ "!fixedColumnOrder!3,>|<,}|{,]|[", - // U+2264: "≤" LESS-THAN OR EQUAL TO - // U+2265: "≥" GREATER-THAN EQUAL TO - // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB", - /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB", - /* 61~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~104 */ - /* 105 */ "!", - /* 106 */ "!", - /* 107 */ "?", - /* 108 */ "?", - }; - - /* Language ka: Georgian */ - private static final String[] LANGUAGE_ka = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+10D0: "ა" GEORGIAN LETTER AN - // U+10D1: "ბ" GEORGIAN LETTER BAN - // U+10D2: "გ" GEORGIAN LETTER GAN - /* 45 */ "\u10D0\u10D1\u10D2", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language kk: Kazakh */ - private static final String[] LANGUAGE_kk = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~24 */ - // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA - /* 25 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 26 */ "\u044A", - // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 27 */ "\u044B", - // U+044D: "э" CYRILLIC SMALL LETTER E - /* 28 */ "\u044D", - // U+0438: "и" CYRILLIC SMALL LETTER I - /* 29 */ "\u0438", - // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U - // U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE - /* 30 */ "\u04AF,\u04B1", - // U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER - /* 31 */ "\u049B", - // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER - /* 32 */ "\u04A3", - // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE - /* 33 */ "\u0493", - // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* 34 */ "\u0456", - // U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA - /* 35 */ "\u04D9", - // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O - /* 36 */ "\u04E9", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 37 */ "\u044A", - // U+04BB: "һ" CYRILLIC SMALL LETTER SHHA - /* 38 */ "\u04BB", - /* 39~ */ - null, null, null, null, - /* ~42 */ - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 43 */ "\u0451", - /* 44 */ null, - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - }; - - /* Language km: Khmer */ - private static final String[] LANGUAGE_km = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+1780: "ក" KHMER LETTER KA - // U+1781: "ខ" KHMER LETTER KHA - // U+1782: "គ" KHMER LETTER KO - /* 45 */ "\u1780\u1781\u1782", - /* 46~ */ - null, null, null, null, - /* ~49 */ - // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL - /* 50 */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", - }; - - /* Language ky: Kirghiz */ - private static final String[] LANGUAGE_ky = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~24 */ - // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA - /* 25 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 26 */ "\u044A", - // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 27 */ "\u044B", - // U+044D: "э" CYRILLIC SMALL LETTER E - /* 28 */ "\u044D", - // U+0438: "и" CYRILLIC SMALL LETTER I - /* 29 */ "\u0438", - // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U - /* 30 */ "\u04AF", - /* 31 */ null, - // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER - /* 32 */ "\u04A3", - /* 33~ */ - null, null, null, - /* ~35 */ - // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O - /* 36 */ "\u04E9", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 37 */ "\u044A", - /* 38~ */ - null, null, null, null, null, - /* ~42 */ - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 43 */ "\u0451", - /* 44 */ null, - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - }; - - /* Language lo: Lao */ - private static final String[] LANGUAGE_lo = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0E81: "ກ" LAO LETTER KO - // U+0E82: "ຂ" LAO LETTER KHO SUNG - // U+0E84: "ຄ" LAO LETTER KHO TAM - /* 45 */ "\u0E81\u0E82\u0E84", - /* 46~ */ - null, null, null, null, null, - /* ~50 */ - // U+20AD: "₭" KIP SIGN - /* 51 */ "\u20AD", - }; - - /* Language lt: Lithuanian */ - private static final String[] LANGUAGE_lt = { - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 0 */ "\u0105,\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6", - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - /* 1 */ "\u0117,\u0119,\u0113,\u00E8,\u00E9,\u00EA,\u00EB,\u011B", - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - /* 2 */ "\u012F,\u012B,\u00EC,\u00ED,\u00EE,\u00EF,\u0131", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 3 */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8", - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - /* 4 */ "\u016B,\u0173,\u00FC,\u016B,\u00F9,\u00FA,\u00FB,\u016F,\u0171", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - /* 5 */ "\u0161,\u00DF,\u015B,\u015F", - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u0146,\u00F1,\u0144,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u00E7,\u0107", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u010F", - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - /* 10 */ "\u0157,\u0159,\u0155", - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - /* 11 */ "\u0163,\u0165", - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - /* 12 */ "\u017E,\u017C,\u017A", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - /* 13 */ "\u0137", - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - /* 14 */ "\u013C,\u0142,\u013A,\u013E", - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u0123,\u011F", - /* 16~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language lv: Latvian */ - private static final String[] LANGUAGE_lv = { - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - /* 0 */ "\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u0105", - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - /* 1 */ "\u0113,\u0117,\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u011B", - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - /* 2 */ "\u012B,\u012F,\u00EC,\u00ED,\u00EE,\u00EF,\u0131", - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u0153,\u0151,\u00F8", - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - /* 4 */ "\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u00FC,\u016F,\u0171", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - /* 5 */ "\u0161,\u00DF,\u015B,\u015F", - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u0146,\u00F1,\u0144,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u00E7,\u0107", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u010F", - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - /* 10 */ "\u0157,\u0159,\u0155", - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - /* 11 */ "\u0163,\u0165", - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - /* 12 */ "\u017E,\u017C,\u017A", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - /* 13 */ "\u0137", - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - /* 14 */ "\u013C,\u0142,\u013A,\u013E", - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u0123,\u011F", - /* 16~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language mk: Macedonian */ - private static final String[] LANGUAGE_mk = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, - /* ~38 */ - // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE - /* 39 */ "\u0455", - // U+045C: "ќ" CYRILLIC SMALL LETTER KJE - /* 40 */ "\u045C", - // U+0437: "з" CYRILLIC SMALL LETTER ZE - /* 41 */ "\u0437", - // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE - /* 42 */ "\u0453", - // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE - /* 43 */ "\u0450", - // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE - /* 44 */ "\u045D", - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language mn: Mongolian */ - private static final String[] LANGUAGE_mn = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46~ */ - null, null, null, null, null, - /* ~50 */ - // U+20AE: "₮" TUGRIK SIGN - /* 51 */ "\u20AE", - }; - - /* Language nb: Norwegian Bokmål */ - private static final String[] LANGUAGE_nb = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E0,\u00E4,\u00E1,\u00E2,\u00E3,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", - /* 2 */ null, - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F4,\u00F2,\u00F3,\u00F6,\u00F5,\u0153,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", - /* 5~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~19 */ - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - /* 20 */ "\u00E5", - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 21 */ "\u00F8", - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 22 */ "\u00E6", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - /* 23 */ "\u00F6", - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - /* 24 */ "\u00E4", - /* 25~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - }; - - /* Language ne: Nepali */ - private static final String[] LANGUAGE_ne = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0915: "क" DEVANAGARI LETTER KA - // U+0916: "ख" DEVANAGARI LETTER KHA - // U+0917: "ग" DEVANAGARI LETTER GA - /* 45 */ "\u0915\u0916\u0917", - /* 46~ */ - null, null, null, null, null, - /* ~50 */ - // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN - /* 51 */ "\u0930\u0941.", - /* 52~ */ - null, null, null, null, null, null, null, null, null, null, null, - /* ~62 */ - // U+0967: "१" DEVANAGARI DIGIT ONE - /* 63 */ "\u0967", - // U+0968: "२" DEVANAGARI DIGIT TWO - /* 64 */ "\u0968", - // U+0969: "३" DEVANAGARI DIGIT THREE - /* 65 */ "\u0969", - // U+096A: "४" DEVANAGARI DIGIT FOUR - /* 66 */ "\u096A", - // U+096B: "५" DEVANAGARI DIGIT FIVE - /* 67 */ "\u096B", - // U+096C: "६" DEVANAGARI DIGIT SIX - /* 68 */ "\u096C", - // U+096D: "७" DEVANAGARI DIGIT SEVEN - /* 69 */ "\u096D", - // U+096E: "८" DEVANAGARI DIGIT EIGHT - /* 70 */ "\u096E", - // U+096F: "९" DEVANAGARI DIGIT NINE - /* 71 */ "\u096F", - // U+0966: "०" DEVANAGARI DIGIT ZERO - /* 72 */ "\u0966", - // Label for "switch to symbols" key. - /* 73 */ "?\u0967\u0968\u0969", - // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - // part because it'll be appended by the code. - /* 74 */ "\u0967\u0968\u0969", - /* 75 */ "1", - /* 76 */ "2", - /* 77 */ "3", - /* 78 */ "4", - /* 79 */ "5", - /* 80 */ "6", - /* 81 */ "7", - /* 82 */ "8", - /* 83 */ "9", - /* 84 */ "0", - }; - - /* Language nl: Dutch */ - private static final String[] LANGUAGE_nl = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E1,\u00E4,\u00E2,\u00E0,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00EB,\u00EA,\u00E8,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", - /* 5 */ null, - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - /* 7 */ null, - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 8 */ "\u0133", - /* 9~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - }; - - /* Language pl: Polish */ - private static final String[] LANGUAGE_pl = { - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u0105,\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u0119,\u00E8,\u00E9,\u00EA,\u00EB,\u0117,\u0113", - /* 2 */ null, - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", - /* 4 */ null, - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u015B,\u00DF,\u0161", - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 6 */ "\u0144,\u00F1", - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u0107,\u00E7,\u010D", - /* 8~ */ - null, null, null, null, - /* ~11 */ - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - /* 12 */ "\u017C,\u017A,\u017E", - /* 13 */ null, - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u0142", - /* 15~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - }; - - /* Language pt: Portuguese */ - private static final String[] LANGUAGE_pt = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E1,\u00E3,\u00E0,\u00E2,\u00E4,\u00E5,\u00E6,\u00AA", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - /* 1 */ "\u00E9,\u00EA,\u00E8,\u0119,\u0117,\u0113,\u00EB", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EE,\u00EC,\u00EF,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F3,\u00F5,\u00F4,\u00F2,\u00F6,\u0153,\u00F8,\u014D,\u00BA", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", - /* 5 */ null, - /* 6 */ null, - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u00E7,\u010D,\u0107", - }; - - /* Language rm: Raeto-Romance */ - private static final String[] LANGUAGE_rm = { - /* 0~ */ - null, null, null, - /* ~2 */ - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 3 */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u0153,\u00F8", - }; - - /* Language ro: Romanian */ - private static final String[] LANGUAGE_ro = { - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101", - /* 1 */ null, - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", - /* 3 */ null, - /* 4 */ null, - // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u0219,\u00DF,\u015B,\u0161", - /* 6~ */ - null, null, null, null, null, - /* ~10 */ - // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW - /* 11 */ "\u021B", - /* 12~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_rqm", - /* 47 */ "!text/double_9qm_rqm", - }; - - /* Language ru: Russian */ - private static final String[] LANGUAGE_ru = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~24 */ - // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA - /* 25 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 26 */ "\u044A", - // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* 27 */ "\u044B", - // U+044D: "э" CYRILLIC SMALL LETTER E - /* 28 */ "\u044D", - // U+0438: "и" CYRILLIC SMALL LETTER I - /* 29 */ "\u0438", - /* 30~ */ - null, null, null, null, null, null, null, - /* ~36 */ - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 37 */ "\u044A", - /* 38~ */ - null, null, null, null, null, - /* ~42 */ - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* 43 */ "\u0451", - /* 44 */ null, - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - }; - - /* Language sk: Slovak */ - private static final String[] LANGUAGE_sk = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - /* 0 */ "\u00E1,\u00E4,\u0101,\u00E0,\u00E2,\u00E3,\u00E5,\u00E6,\u0105", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - /* 1 */ "\u00E9,\u011B,\u0113,\u0117,\u00E8,\u00EA,\u00EB,\u0119", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - /* 2 */ "\u00ED,\u012B,\u012F,\u00EC,\u00EE,\u00EF,\u0131", - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - /* 3 */ "\u00F4,\u00F3,\u00F6,\u00F2,\u00F5,\u0153,\u0151,\u00F8", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - /* 4 */ "\u00FA,\u016F,\u00FC,\u016B,\u0173,\u00F9,\u00FB,\u0171", - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - /* 5 */ "\u0161,\u00DF,\u015B,\u015F", - // U+0148: "ň" LATIN SMALL LETTER N WITH CARON - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u0148,\u0146,\u00F1,\u0144,\u0144", - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u00E7,\u0107", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u010F", - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - /* 10 */ "\u0155,\u0159,\u0157", - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - /* 11 */ "\u0165,\u0163", - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - /* 12 */ "\u017E,\u017C,\u017A", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - /* 13 */ "\u0137", - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u013E,\u013A,\u013C,\u0142", - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u0123,\u011F", - /* 16~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language sl: Slovenian */ - private static final String[] LANGUAGE_sl = { - /* 0~ */ - null, null, null, null, null, - /* ~4 */ - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u0161", - /* 6 */ null, - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - /* 7 */ "\u010D,\u0107", - /* 8 */ null, - // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE - /* 9 */ "\u0111", - /* 10 */ null, - /* 11 */ null, - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - /* 12 */ "\u017E", - /* 13~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, - /* ~45 */ - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language sr: Serbian */ - private static final String[] LANGUAGE_sr = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, - /* ~38 */ - // TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified. - // BEGIN: More keys definitions for Serbian (Latin) - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // <string name="more_keys_for_s">š,ß,ś</string> - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // <string name="more_keys_for_c">č,ç,ć</string> - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - // <string name="more_keys_for_d">ď</string> - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // <string name="more_keys_for_z">ž,ź,ż</string> - // END: More keys definitions for Serbian (Latin) - // BEGIN: More keys definitions for Serbian (Cyrillic) - // U+0437: "з" CYRILLIC SMALL LETTER ZE - /* 39 */ "\u0437", - // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE - /* 40 */ "\u045B", - // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE - /* 41 */ "\u0455", - // U+0452: "ђ" CYRILLIC SMALL LETTER DJE - /* 42 */ "\u0452", - // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE - /* 43 */ "\u0450", - // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE - /* 44 */ "\u045D", - // END: More keys definitions for Serbian (Cyrillic) - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language sv: Swedish */ - private static final String[] LANGUAGE_sv = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - /* 0 */ "\u00E1,\u00E0,\u00E2,\u0105,\u00E3", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - /* 2 */ "\u00ED,\u00EC,\u00EE,\u00EF", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F3,\u00F2,\u00F4,\u00F5,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FC,\u00FA,\u00F9,\u00FB,\u016B", - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - /* 5 */ "\u015B,\u0161,\u015F,\u00DF", - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0148: "ň" LATIN SMALL LETTER N WITH CARON - /* 6 */ "\u0144,\u00F1,\u0148", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - /* 8 */ "\u00FD,\u00FF,\u00FC", - // U+00F0: "ð" LATIN SMALL LETTER ETH - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - /* 9 */ "\u00F0,\u010F", - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - /* 10 */ "\u0159", - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - // U+00FE: "þ" LATIN SMALL LETTER THORN - /* 11 */ "\u0165,\u00FE", - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - /* 12 */ "\u017A,\u017E,\u017C", - /* 13 */ null, - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u0142", - /* 15~ */ - null, null, null, null, null, - /* ~19 */ - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - /* 20 */ "\u00E5", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - /* 21 */ "\u00F6", - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - /* 22 */ "\u00E4", - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+0153: "œ" LATIN SMALL LIGATURE OE - /* 23 */ "\u00F8,\u0153", - // U+00E6: "æ" LATIN SMALL LETTER AE - /* 24 */ "\u00E6", - /* 25~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - /* ~47 */ - /* 48 */ "!text/single_raqm_laqm", - /* 49 */ "!text/double_raqm_laqm", - }; - - /* Language sw: Swahili */ - private static final String[] LANGUAGE_sw = { - // This is the same as English except more_keys_for_g. - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - /* 5 */ "\u00DF", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 6 */ "\u00F1", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - /* 7 */ "\u00E7", - /* 8~ */ - null, null, null, null, null, null, null, - /* ~14 */ - /* 15 */ "g\'", - }; - - /* Language th: Thai */ - private static final String[] LANGUAGE_th = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0E01: "ก" THAI CHARACTER KO KAI - // U+0E02: "ข" THAI CHARACTER KHO KHAI - // U+0E04: "ค" THAI CHARACTER KHO KHWAI - /* 45 */ "\u0E01\u0E02\u0E04", - /* 46~ */ - null, null, null, null, null, - /* ~50 */ - // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT - /* 51 */ "\u0E3F", - }; - - /* Language tl: Tagalog */ - private static final String[] LANGUAGE_tl = { - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", - /* 5 */ null, - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - /* 6 */ "\u00F1,\u0144", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - }; - - /* Language tr: Turkish */ - private static final String[] LANGUAGE_tr = { - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - /* 0 */ "\u00E2", - /* 1 */ null, - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - /* 2 */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - /* 3 */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D", - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - /* 5 */ "\u015F,\u00DF,\u015B,\u0161", - /* 6 */ null, - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u010D", - /* 8~ */ - null, null, null, null, null, null, null, - /* ~14 */ - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - /* 15 */ "\u011F", - }; - - /* Language uk: Ukrainian */ - private static final String[] LANGUAGE_uk = { - /* 0~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, - /* ~24 */ - // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA - /* 25 */ "\u0449", - // U+0457: "ї" CYRILLIC SMALL LETTER YI - /* 26 */ "\u0457", - // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* 27 */ "\u0456", - // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE - /* 28 */ "\u0454", - // U+0438: "и" CYRILLIC SMALL LETTER I - /* 29 */ "\u0438", - /* 30~ */ - null, null, null, - /* ~32 */ - // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN - /* 33 */ "\u0491", - // U+0457: "ї" CYRILLIC SMALL LETTER YI - /* 34 */ "\u0457", - /* 35 */ null, - /* 36 */ null, - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* 37 */ "\u044A", - /* 38~ */ - null, null, null, null, null, null, null, - /* ~44 */ - // Label for "switch to alphabetic" key. - // U+0410: "А" CYRILLIC CAPITAL LETTER A - // U+0411: "Б" CYRILLIC CAPITAL LETTER BE - // U+0412: "В" CYRILLIC CAPITAL LETTER VE - /* 45 */ "\u0410\u0411\u0412", - /* 46 */ "!text/single_9qm_lqm", - /* 47 */ "!text/double_9qm_lqm", - /* 48~ */ - null, null, null, - /* ~50 */ - // U+20B4: "₴" HRYVNIA SIGN - /* 51 */ "\u20B4", - }; - - /* Language vi: Vietnamese */ - private static final String[] LANGUAGE_vi = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+1EA3: "ả" LATIN SMALL LETTER A WITH HOOK ABOVE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+1EA1: "ạ" LATIN SMALL LETTER A WITH DOT BELOW - // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE - // U+1EB1: "ằ" LATIN SMALL LETTER A WITH BREVE AND GRAVE - // U+1EAF: "ắ" LATIN SMALL LETTER A WITH BREVE AND ACUTE - // U+1EB3: "ẳ" LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE - // U+1EB5: "ẵ" LATIN SMALL LETTER A WITH BREVE AND TILDE - // U+1EB7: "ặ" LATIN SMALL LETTER A WITH BREVE AND DOT BELOW - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+1EA7: "ầ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE - // U+1EA5: "ấ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE - // U+1EA9: "ẩ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE - // U+1EAB: "ẫ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE - // U+1EAD: "ậ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW - /* 0 */ "\u00E0,\u00E1,\u1EA3,\u00E3,\u1EA1,\u0103,\u1EB1,\u1EAF,\u1EB3,\u1EB5,\u1EB7,\u00E2,\u1EA7,\u1EA5,\u1EA9,\u1EAB,\u1EAD", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE - // U+1EBD: "ẽ" LATIN SMALL LETTER E WITH TILDE - // U+1EB9: "ẹ" LATIN SMALL LETTER E WITH DOT BELOW - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+1EC1: "ề" LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE - // U+1EBF: "ế" LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE - // U+1EC3: "ể" LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE - // U+1EC5: "ễ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE - // U+1EC7: "ệ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW - /* 1 */ "\u00E8,\u00E9,\u1EBB,\u1EBD,\u1EB9,\u00EA,\u1EC1,\u1EBF,\u1EC3,\u1EC5,\u1EC7", - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+1EC9: "ỉ" LATIN SMALL LETTER I WITH HOOK ABOVE - // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE - // U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW - /* 2 */ "\u00EC,\u00ED,\u1EC9,\u0129,\u1ECB", - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+1ECF: "ỏ" LATIN SMALL LETTER O WITH HOOK ABOVE - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+1ECD: "ọ" LATIN SMALL LETTER O WITH DOT BELOW - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+1ED3: "ồ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE - // U+1ED1: "ố" LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE - // U+1ED5: "ổ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE - // U+1ED7: "ỗ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE - // U+1ED9: "ộ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW - // U+01A1: "ơ" LATIN SMALL LETTER O WITH HORN - // U+1EDD: "ờ" LATIN SMALL LETTER O WITH HORN AND GRAVE - // U+1EDB: "ớ" LATIN SMALL LETTER O WITH HORN AND ACUTE - // U+1EDF: "ở" LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE - // U+1EE1: "ỡ" LATIN SMALL LETTER O WITH HORN AND TILDE - // U+1EE3: "ợ" LATIN SMALL LETTER O WITH HORN AND DOT BELOW - /* 3 */ "\u00F2,\u00F3,\u1ECF,\u00F5,\u1ECD,\u00F4,\u1ED3,\u1ED1,\u1ED5,\u1ED7,\u1ED9,\u01A1,\u1EDD,\u1EDB,\u1EDF,\u1EE1,\u1EE3", - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+1EE7: "ủ" LATIN SMALL LETTER U WITH HOOK ABOVE - // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE - // U+1EE5: "ụ" LATIN SMALL LETTER U WITH DOT BELOW - // U+01B0: "ư" LATIN SMALL LETTER U WITH HORN - // U+1EEB: "ừ" LATIN SMALL LETTER U WITH HORN AND GRAVE - // U+1EE9: "ứ" LATIN SMALL LETTER U WITH HORN AND ACUTE - // U+1EED: "ử" LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE - // U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE - // U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW - /* 4 */ "\u00F9,\u00FA,\u1EE7,\u0169,\u1EE5,\u01B0,\u1EEB,\u1EE9,\u1EED,\u1EEF,\u1EF1", - /* 5~ */ - null, null, null, - /* ~7 */ - // U+1EF3: "ỳ" LATIN SMALL LETTER Y WITH GRAVE - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+1EF7: "ỷ" LATIN SMALL LETTER Y WITH HOOK ABOVE - // U+1EF9: "ỹ" LATIN SMALL LETTER Y WITH TILDE - // U+1EF5: "ỵ" LATIN SMALL LETTER Y WITH DOT BELOW - /* 8 */ "\u1EF3,\u00FD,\u1EF7,\u1EF9,\u1EF5", - // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE - /* 9 */ "\u0111", - /* 10~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, - /* ~50 */ - // U+20AB: "₫" DONG SIGN - /* 51 */ "\u20AB", - }; - - /* Language zu: Zulu */ - private static final String[] LANGUAGE_zu = { - // This is the same as English - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - /* 5 */ "\u00DF", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - /* 6 */ "\u00F1", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - /* 7 */ "\u00E7", - }; - - /* Language zz: Alphabet */ - private static final String[] LANGUAGE_zz = { - // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE - // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE - // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX - // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE - // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS - // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE - // U+00E6: "æ" LATIN SMALL LETTER AE - // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON - // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE - // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK - // U+00AA: "ª" FEMININE ORDINAL INDICATOR - /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u00E3,\u00E5,\u0101,\u0103,\u0105,\u00AA", - // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE - // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE - // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX - // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS - // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON - // U+0115: "ĕ" LATIN SMALL LETTER E WITH BREVE - // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE - // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK - // U+011B: "ě" LATIN SMALL LETTER E WITH CARON - /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113,\u0115,\u0117,\u0119,\u011B", - // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE - // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE - // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX - // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS - // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE - // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON - // U+012D: "ĭ" LATIN SMALL LETTER I WITH BREVE - // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK - // U+0131: "ı" LATIN SMALL LETTER DOTLESS I - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 2 */ "\u00EC,\u00ED,\u00EE,\u00EF,\u0129,\u012B,\u012D,\u012F,\u0131,\u0133", - // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE - // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE - // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX - // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE - // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS - // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE - // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON - // U+014F: "ŏ" LATIN SMALL LETTER O WITH BREVE - // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE - // U+0153: "œ" LATIN SMALL LIGATURE OE - // U+00BA: "º" MASCULINE ORDINAL INDICATOR - /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u00F8,\u014D,\u014F,\u0151,\u0153,\u00BA", - // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE - // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE - // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX - // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS - // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE - // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON - // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE - // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE - // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE - // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK - /* 4 */ "\u00F9,\u00FA,\u00FB,\u00FC,\u0169,\u016B,\u016D,\u016F,\u0171,\u0173", - // U+00DF: "ß" LATIN SMALL LETTER SHARP S - // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX - // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA - // U+0161: "š" LATIN SMALL LETTER S WITH CARON - // U+017F: "ſ" LATIN SMALL LETTER LONG S - /* 5 */ "\u00DF,\u015B,\u015D,\u015F,\u0161,\u017F", - // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE - // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA - // U+0148: "ň" LATIN SMALL LETTER N WITH CARON - // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - // U+014B: "ŋ" LATIN SMALL LETTER ENG - /* 6 */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B", - // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA - // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX - // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE - // U+010D: "č" LATIN SMALL LETTER C WITH CARON - /* 7 */ "\u00E7,\u0107,\u0109,\u010B,\u010D", - // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX - // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - // U+0133: "ij" LATIN SMALL LIGATURE IJ - /* 8 */ "\u00FD,\u0177,\u00FF,\u0133", - // U+010F: "ď" LATIN SMALL LETTER D WITH CARON - // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE - // U+00F0: "ð" LATIN SMALL LETTER ETH - /* 9 */ "\u010F,\u0111,\u00F0", - // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE - // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA - // U+0159: "ř" LATIN SMALL LETTER R WITH CARON - /* 10 */ "\u0155,\u0157,\u0159", - // U+00FE: "þ" LATIN SMALL LETTER THORN - // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA - // U+0165: "ť" LATIN SMALL LETTER T WITH CARON - // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE - /* 11 */ "\u00FE,\u0163,\u0165,\u0167", - // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE - // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON - /* 12 */ "\u017A,\u017C,\u017E", - // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA - // U+0138: "ĸ" LATIN SMALL LETTER KRA - /* 13 */ "\u0137,\u0138", - // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE - // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA - // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON - // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT - // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE - /* 14 */ "\u013A,\u013C,\u013E,\u0140,\u0142", - // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX - // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE - // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE - // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA - /* 15 */ "\u011D,\u011F,\u0121,\u0123", - /* 16 */ null, - // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX - /* 17 */ "\u0125", - // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX - /* 18 */ "\u0135", - // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX - /* 19 */ "\u0175", - }; - - private static final Object[] LANGUAGES_AND_TEXTS = { - "DEFAULT", LANGUAGE_DEFAULT, /* default */ - "af", LANGUAGE_af, /* Afrikaans */ - "ar", LANGUAGE_ar, /* Arabic */ - "az", LANGUAGE_az, /* Azerbaijani */ - "be", LANGUAGE_be, /* Belarusian */ - "bg", LANGUAGE_bg, /* Bulgarian */ - "ca", LANGUAGE_ca, /* Catalan */ - "cs", LANGUAGE_cs, /* Czech */ - "da", LANGUAGE_da, /* Danish */ - "de", LANGUAGE_de, /* German */ - "el", LANGUAGE_el, /* Greek */ - "en", LANGUAGE_en, /* English */ - "eo", LANGUAGE_eo, /* Esperanto */ - "es", LANGUAGE_es, /* Spanish */ - "et", LANGUAGE_et, /* Estonian */ - "fa", LANGUAGE_fa, /* Persian */ - "fi", LANGUAGE_fi, /* Finnish */ - "fr", LANGUAGE_fr, /* French */ - "hi", LANGUAGE_hi, /* Hindi */ - "hr", LANGUAGE_hr, /* Croatian */ - "hu", LANGUAGE_hu, /* Hungarian */ - "hy", LANGUAGE_hy, /* Armenian */ - "is", LANGUAGE_is, /* Icelandic */ - "it", LANGUAGE_it, /* Italian */ - "iw", LANGUAGE_iw, /* Hebrew */ - "ka", LANGUAGE_ka, /* Georgian */ - "kk", LANGUAGE_kk, /* Kazakh */ - "km", LANGUAGE_km, /* Khmer */ - "ky", LANGUAGE_ky, /* Kirghiz */ - "lo", LANGUAGE_lo, /* Lao */ - "lt", LANGUAGE_lt, /* Lithuanian */ - "lv", LANGUAGE_lv, /* Latvian */ - "mk", LANGUAGE_mk, /* Macedonian */ - "mn", LANGUAGE_mn, /* Mongolian */ - "nb", LANGUAGE_nb, /* Norwegian Bokmål */ - "ne", LANGUAGE_ne, /* Nepali */ - "nl", LANGUAGE_nl, /* Dutch */ - "pl", LANGUAGE_pl, /* Polish */ - "pt", LANGUAGE_pt, /* Portuguese */ - "rm", LANGUAGE_rm, /* Raeto-Romance */ - "ro", LANGUAGE_ro, /* Romanian */ - "ru", LANGUAGE_ru, /* Russian */ - "sk", LANGUAGE_sk, /* Slovak */ - "sl", LANGUAGE_sl, /* Slovenian */ - "sr", LANGUAGE_sr, /* Serbian */ - "sv", LANGUAGE_sv, /* Swedish */ - "sw", LANGUAGE_sw, /* Swahili */ - "th", LANGUAGE_th, /* Thai */ - "tl", LANGUAGE_tl, /* Tagalog */ - "tr", LANGUAGE_tr, /* Turkish */ - "uk", LANGUAGE_uk, /* Ukrainian */ - "vi", LANGUAGE_vi, /* Vietnamese */ - "zu", LANGUAGE_zu, /* Zulu */ - "zz", LANGUAGE_zz, /* Alphabet */ - }; - - static { - int id = 0; - for (final String name : NAMES) { - sNameToIdsMap.put(name, id++); - } - - for (int i = 0; i < LANGUAGES_AND_TEXTS.length; i += 2) { - final String language = (String)LANGUAGES_AND_TEXTS[i]; - final String[] texts = (String[])LANGUAGES_AND_TEXTS[i + 1]; - sLocaleToTextsMap.put(language, texts); - } - } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java new file mode 100644 index 000000000..14fa76744 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -0,0 +1,3782 @@ +/* + * Copyright (C) 2014 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.latin.utils.CollectionUtils; + +import java.util.HashMap; +import java.util.Locale; + +/** + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file is generated by tools/make-keyboard-text. The base template file is + * tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsTable.tmpl + * + * This file must be updated when any text resources in keyboard layout files have been changed. + * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, + * and should be defined in + * tools/make-keyboard-text/res/values-<locale>/donottranslate-more-keys.xml + * + * To update this file, please run the following commands. + * $ cd $ANDROID_BUILD_TOP + * $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text + * $ make-keyboard-text -java packages/inputmethods/LatinIME/java + * + * The updated source file will be generated to the following path (this file). + * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsTable.java + */ +public final class KeyboardTextsTable { + // Name to index map. + private static final HashMap<String, Integer> sNameToIndexesMap = CollectionUtils.newHashMap(); + // Locale to texts table map. + private static final HashMap<String, String[]> sLocaleToTextsTableMap = + CollectionUtils.newHashMap(); + // TODO: Remove this variable after debugging. + // Texts table to locale maps. + private static final HashMap<String[], String> sTextsTableToLocaleMap = + CollectionUtils.newHashMap(); + + public static String getText(final String name, final String[] textsTable) { + final Integer indexObj = sNameToIndexesMap.get(name); + if (indexObj == null) { + throw new RuntimeException("Unknown text name=" + name + " locale=" + + sTextsTableToLocaleMap.get(textsTable)); + } + final int index = indexObj; + final String text = (index < textsTable.length) ? textsTable[index] : null; + if (text != null) { + return text; + } + // Sanity check. + if (index >= 0 && index < TEXTS_DEFAULT.length) { + return TEXTS_DEFAULT[index]; + } + // Throw exception for debugging purpose. + throw new RuntimeException("Illegal index=" + index + " for name=" + name + + " locale=" + sTextsTableToLocaleMap.get(textsTable)); + } + + public static String[] getTextsTable(final Locale locale) { + final String localeKey = locale.toString(); + if (sLocaleToTextsTableMap.containsKey(localeKey)) { + return sLocaleToTextsTableMap.get(localeKey); + } + final String languageKey = locale.getLanguage(); + if (sLocaleToTextsTableMap.containsKey(languageKey)) { + return sLocaleToTextsTableMap.get(languageKey); + } + return TEXTS_DEFAULT; + } + + private static final String[] NAMES = { + // /* index:histogram */ "name", + /* 0:32 */ "morekeys_a", + /* 1:32 */ "morekeys_o", + /* 2:30 */ "morekeys_u", + /* 3:29 */ "morekeys_e", + /* 4:28 */ "morekeys_i", + /* 5:23 */ "morekeys_c", + /* 6:23 */ "double_quotes", + /* 7:22 */ "morekeys_n", + /* 8:22 */ "single_quotes", + /* 9:21 */ "keylabel_to_alpha", + /* 10:20 */ "morekeys_s", + /* 11:14 */ "morekeys_y", + /* 12:13 */ "morekeys_d", + /* 13:12 */ "morekeys_z", + /* 14:10 */ "morekeys_t", + /* 15:10 */ "morekeys_l", + /* 16: 9 */ "morekeys_g", + /* 17: 9 */ "single_angle_quotes", + /* 18: 9 */ "double_angle_quotes", + /* 19: 9 */ "keyspec_currency", + /* 20: 8 */ "morekeys_r", + /* 21: 6 */ "morekeys_k", + /* 22: 6 */ "morekeys_cyrillic_ie", + /* 23: 5 */ "keyspec_nordic_row1_11", + /* 24: 5 */ "keyspec_nordic_row2_10", + /* 25: 5 */ "keyspec_nordic_row2_11", + /* 26: 5 */ "morekeys_nordic_row2_10", + /* 27: 5 */ "keyspec_east_slavic_row1_9", + /* 28: 5 */ "keyspec_east_slavic_row2_2", + /* 29: 5 */ "keyspec_east_slavic_row2_11", + /* 30: 5 */ "keyspec_east_slavic_row3_5", + /* 31: 5 */ "morekeys_cyrillic_soft_sign", + /* 32: 4 */ "morekeys_nordic_row2_11", + /* 33: 4 */ "morekeys_punctuation", + /* 34: 4 */ "keyspec_symbols_1", + /* 35: 4 */ "keyspec_symbols_2", + /* 36: 4 */ "keyspec_symbols_3", + /* 37: 4 */ "keyspec_symbols_4", + /* 38: 4 */ "keyspec_symbols_5", + /* 39: 4 */ "keyspec_symbols_6", + /* 40: 4 */ "keyspec_symbols_7", + /* 41: 4 */ "keyspec_symbols_8", + /* 42: 4 */ "keyspec_symbols_9", + /* 43: 4 */ "keyspec_symbols_0", + /* 44: 4 */ "keylabel_to_symbol", + /* 45: 4 */ "additional_morekeys_symbols_1", + /* 46: 4 */ "additional_morekeys_symbols_2", + /* 47: 4 */ "additional_morekeys_symbols_3", + /* 48: 4 */ "additional_morekeys_symbols_4", + /* 49: 4 */ "additional_morekeys_symbols_5", + /* 50: 4 */ "additional_morekeys_symbols_6", + /* 51: 4 */ "additional_morekeys_symbols_7", + /* 52: 4 */ "additional_morekeys_symbols_8", + /* 53: 4 */ "additional_morekeys_symbols_9", + /* 54: 4 */ "additional_morekeys_symbols_0", + /* 55: 4 */ "keyspec_tablet_comma", + /* 56: 3 */ "keyspec_swiss_row1_11", + /* 57: 3 */ "keyspec_swiss_row2_10", + /* 58: 3 */ "keyspec_swiss_row2_11", + /* 59: 3 */ "morekeys_swiss_row1_11", + /* 60: 3 */ "morekeys_swiss_row2_10", + /* 61: 3 */ "morekeys_swiss_row2_11", + /* 62: 3 */ "morekeys_star", + /* 63: 3 */ "keyspec_left_parenthesis", + /* 64: 3 */ "keyspec_right_parenthesis", + /* 65: 3 */ "keyspec_left_square_bracket", + /* 66: 3 */ "keyspec_right_square_bracket", + /* 67: 3 */ "keyspec_left_curly_bracket", + /* 68: 3 */ "keyspec_right_curly_bracket", + /* 69: 3 */ "keyspec_less_than", + /* 70: 3 */ "keyspec_greater_than", + /* 71: 3 */ "keyspec_less_than_equal", + /* 72: 3 */ "keyspec_greater_than_equal", + /* 73: 3 */ "keyspec_left_double_angle_quote", + /* 74: 3 */ "keyspec_right_double_angle_quote", + /* 75: 3 */ "keyspec_left_single_angle_quote", + /* 76: 3 */ "keyspec_right_single_angle_quote", + /* 77: 3 */ "morekeys_tablet_comma", + /* 78: 3 */ "keyhintlabel_period", + /* 79: 3 */ "morekeys_tablet_period", + /* 80: 3 */ "morekeys_question", + /* 81: 2 */ "morekeys_h", + /* 82: 2 */ "morekeys_w", + /* 83: 2 */ "morekeys_east_slavic_row2_2", + /* 84: 2 */ "morekeys_cyrillic_u", + /* 85: 2 */ "morekeys_cyrillic_en", + /* 86: 2 */ "morekeys_cyrillic_ghe", + /* 87: 2 */ "morekeys_cyrillic_o", + /* 88: 2 */ "morekeys_cyrillic_i", + /* 89: 2 */ "keyspec_south_slavic_row1_6", + /* 90: 2 */ "keyspec_south_slavic_row2_11", + /* 91: 2 */ "keyspec_south_slavic_row3_1", + /* 92: 2 */ "keyspec_south_slavic_row3_8", + /* 93: 2 */ "morekeys_tablet_punctuation", + /* 94: 2 */ "keyspec_spanish_row2_10", + /* 95: 2 */ "morekeys_bullet", + /* 96: 2 */ "morekeys_left_parenthesis", + /* 97: 2 */ "morekeys_right_parenthesis", + /* 98: 2 */ "morekeys_arabic_diacritics", + /* 99: 2 */ "keyspec_comma", + /* 100: 2 */ "keyhintlabel_tablet_comma", + /* 101: 2 */ "keyspec_period", + /* 102: 2 */ "morekeys_period", + /* 103: 2 */ "keyspec_tablet_period", + /* 104: 2 */ "keyhintlabel_tablet_period", + /* 105: 2 */ "keyspec_symbols_question", + /* 106: 2 */ "keyspec_symbols_semicolon", + /* 107: 2 */ "keyspec_symbols_percent", + /* 108: 2 */ "morekeys_symbols_semicolon", + /* 109: 2 */ "morekeys_symbols_percent", + /* 110: 1 */ "morekeys_v", + /* 111: 1 */ "morekeys_j", + /* 112: 1 */ "morekeys_q", + /* 113: 1 */ "morekeys_x", + /* 114: 1 */ "keyspec_q", + /* 115: 1 */ "keyspec_w", + /* 116: 1 */ "keyspec_y", + /* 117: 1 */ "keyspec_x", + /* 118: 1 */ "morekeys_east_slavic_row2_11", + /* 119: 1 */ "morekeys_cyrillic_ka", + /* 120: 1 */ "morekeys_cyrillic_a", + /* 121: 1 */ "morekeys_currency_dollar", + /* 122: 1 */ "morekeys_plus", + /* 123: 1 */ "morekeys_less_than", + /* 124: 1 */ "morekeys_greater_than", + /* 125: 1 */ "morekeys_exclamation", + /* 126: 0 */ "morekeys_currency", + /* 127: 0 */ "morekeys_symbols_1", + /* 128: 0 */ "morekeys_symbols_2", + /* 129: 0 */ "morekeys_symbols_3", + /* 130: 0 */ "morekeys_symbols_4", + /* 131: 0 */ "morekeys_symbols_5", + /* 132: 0 */ "morekeys_symbols_6", + /* 133: 0 */ "morekeys_symbols_7", + /* 134: 0 */ "morekeys_symbols_8", + /* 135: 0 */ "morekeys_symbols_9", + /* 136: 0 */ "morekeys_symbols_0", + /* 137: 0 */ "morekeys_am_pm", + /* 138: 0 */ "keyspec_settings", + /* 139: 0 */ "keyspec_shortcut", + /* 140: 0 */ "keyspec_action_next", + /* 141: 0 */ "keyspec_action_previous", + /* 142: 0 */ "keylabel_to_more_symbol", + /* 143: 0 */ "keylabel_tablet_to_more_symbol", + /* 144: 0 */ "keylabel_to_phone_numeric", + /* 145: 0 */ "keylabel_to_phone_symbols", + /* 146: 0 */ "keylabel_time_am", + /* 147: 0 */ "keylabel_time_pm", + /* 148: 0 */ "keyspec_popular_domain", + /* 149: 0 */ "morekeys_popular_domain", + /* 150: 0 */ "keyspecs_left_parenthesis_more_keys", + /* 151: 0 */ "keyspecs_right_parenthesis_more_keys", + /* 152: 0 */ "single_laqm_raqm", + /* 153: 0 */ "single_raqm_laqm", + /* 154: 0 */ "double_laqm_raqm", + /* 155: 0 */ "double_raqm_laqm", + /* 156: 0 */ "single_lqm_rqm", + /* 157: 0 */ "single_9qm_lqm", + /* 158: 0 */ "single_9qm_rqm", + /* 159: 0 */ "single_rqm_9qm", + /* 160: 0 */ "double_lqm_rqm", + /* 161: 0 */ "double_9qm_lqm", + /* 162: 0 */ "double_9qm_rqm", + /* 163: 0 */ "double_rqm_9qm", + /* 164: 0 */ "morekeys_single_quote", + /* 165: 0 */ "morekeys_double_quote", + /* 166: 0 */ "morekeys_tablet_double_quote", + /* 167: 0 */ "keyspec_emoji_key", + }; + + private static final String EMPTY = ""; + + /* Default texts */ + private static final String[] TEXTS_DEFAULT = { + /* morekeys_a ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_lqm_rqm", + /* morekeys_n */ EMPTY, + /* single_quotes */ "!text/single_lqm_rqm", + // Label for "switch to alphabetic" key. + /* keylabel_to_alpha */ "ABC", + /* morekeys_s ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_laqm_raqm", + /* double_angle_quotes */ "!text/double_laqm_raqm", + /* keyspec_currency */ "$", + /* morekeys_r ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ morekeys_nordic_row2_11 */ + /* morekeys_punctuation */ "!autoColumnOrder!8,\\,,?,!,#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,',@,:,-,\",+,\\%,&", + /* keyspec_symbols_1 */ "1", + /* keyspec_symbols_2 */ "2", + /* keyspec_symbols_3 */ "3", + /* keyspec_symbols_4 */ "4", + /* keyspec_symbols_5 */ "5", + /* keyspec_symbols_6 */ "6", + /* keyspec_symbols_7 */ "7", + /* keyspec_symbols_8 */ "8", + /* keyspec_symbols_9 */ "9", + /* keyspec_symbols_0 */ "0", + // Label for "switch to symbols" key. + /* keylabel_to_symbol */ "?123", + /* additional_morekeys_symbols_1 ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ additional_morekeys_symbols_0 */ + /* keyspec_tablet_comma */ ",", + /* keyspec_swiss_row1_11 ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ morekeys_swiss_row2_11 */ + // U+2020: "†" DAGGER + // U+2021: "‡" DOUBLE DAGGER + // U+2605: "★" BLACK STAR + /* morekeys_star */ "\u2020,\u2021,\u2605", + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + /* keyspec_left_parenthesis */ "(", + /* keyspec_right_parenthesis */ ")", + /* keyspec_left_square_bracket */ "[", + /* keyspec_right_square_bracket */ "]", + /* keyspec_left_curly_bracket */ "{", + /* keyspec_right_curly_bracket */ "}", + /* keyspec_less_than */ "<", + /* keyspec_greater_than */ ">", + /* keyspec_less_than_equal */ "\u2264", + /* keyspec_greater_than_equal */ "\u2265", + /* keyspec_left_double_angle_quote */ "\u00AB", + /* keyspec_right_double_angle_quote */ "\u00BB", + /* keyspec_left_single_angle_quote */ "\u2039", + /* keyspec_right_single_angle_quote */ "\u203A", + /* morekeys_tablet_comma */ EMPTY, + /* keyhintlabel_period */ EMPTY, + /* morekeys_tablet_period */ "!text/morekeys_tablet_punctuation", + // U+00BF: "¿" INVERTED QUESTION MARK + /* morekeys_question */ "\u00BF", + /* morekeys_h ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ keyspec_south_slavic_row3_8 */ + /* morekeys_tablet_punctuation */ "!autoColumnOrder!7,\\,,',#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,@,:,-,\",+,\\%,&", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* keyspec_spanish_row2_10 */ "\u00F1", + // U+266A: "♪" EIGHTH NOTE + // U+2665: "♥" BLACK HEART SUIT + // U+2660: "♠" BLACK SPADE SUIT + // U+2666: "♦" BLACK DIAMOND SUIT + // U+2663: "♣" BLACK CLUB SUIT + /* morekeys_bullet */ "\u266A,\u2665,\u2660,\u2666,\u2663", + /* morekeys_left_parenthesis */ "!fixedColumnOrder!3,!text/keyspecs_left_parenthesis_more_keys", + /* morekeys_right_parenthesis */ "!fixedColumnOrder!3,!text/keyspecs_right_parenthesis_more_keys", + /* morekeys_arabic_diacritics */ EMPTY, + // Comma key + /* keyspec_comma */ ",", + /* keyhintlabel_tablet_comma */ EMPTY, + // Period key + /* keyspec_period */ ".", + /* morekeys_period */ "!text/morekeys_punctuation", + /* keyspec_tablet_period */ ".", + /* keyhintlabel_tablet_period */ EMPTY, + /* keyspec_symbols_question */ "?", + /* keyspec_symbols_semicolon */ ";", + /* keyspec_symbols_percent */ "%", + /* morekeys_symbols_semicolon */ EMPTY, + // U+2030: "‰" PER MILLE SIGN + /* morekeys_symbols_percent */ "\u2030", + /* morekeys_v ~ */ + EMPTY, EMPTY, EMPTY, EMPTY, + /* ~ morekeys_x */ + /* keyspec_q */ "q", + /* keyspec_w */ "w", + /* keyspec_y */ "y", + /* keyspec_x */ "x", + /* morekeys_east_slavic_row2_11 ~ */ + EMPTY, EMPTY, EMPTY, + /* ~ morekeys_cyrillic_a */ + // U+00A2: "¢" CENT SIGN + // U+00A3: "£" POUND SIGN + // U+20AC: "€" EURO SIGN + // U+00A5: "¥" YEN SIGN + // U+20B1: "₱" PESO SIGN + /* morekeys_currency_dollar */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", + // U+00B1: "±" PLUS-MINUS SIGN + /* morekeys_plus */ "\u00B1", + /* morekeys_less_than */ "!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote,!text/keyspec_less_than_equal,!text/keyspec_left_double_angle_quote", + /* morekeys_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_right_double_angle_quote", + // U+00A1: "¡" INVERTED EXCLAMATION MARK + /* morekeys_exclamation */ "\u00A1", + /* morekeys_currency */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1", + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + /* morekeys_symbols_1 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B", + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + /* morekeys_symbols_2 */ "\u00B2,\u2154", + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + /* morekeys_symbols_3 */ "\u00B3,\u00BE,\u215C", + // U+2074: "⁴" SUPERSCRIPT FOUR + /* morekeys_symbols_4 */ "\u2074", + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + /* morekeys_symbols_5 */ "\u215D", + /* morekeys_symbols_6 */ EMPTY, + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + /* morekeys_symbols_7 */ "\u215E", + /* morekeys_symbols_8 */ EMPTY, + /* morekeys_symbols_9 */ EMPTY, + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + /* morekeys_symbols_0 */ "\u207F,\u2205", + /* morekeys_am_pm */ "!fixedColumnOrder!2,!hasLabels!,!text/keylabel_time_am,!text/keylabel_time_pm", + /* keyspec_settings */ "!icon/settings_key|!code/key_settings", + /* keyspec_shortcut */ "!icon/shortcut_key|!code/key_shortcut", + /* keyspec_action_next */ "!hasLabels!,!text/label_next_key|!code/key_action_next", + /* keyspec_action_previous */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous", + // Label for "switch to more symbol" modifier key ("= \ <"). Must be short to fit on key! + /* keylabel_to_more_symbol */ "= \\\\ <", + // Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! + /* keylabel_tablet_to_more_symbol */ "~ [ <", + // Label for "switch to phone numeric" key. Must be short to fit on key! + /* keylabel_to_phone_numeric */ "123", + // Label for "switch to phone symbols" key. Must be short to fit on key! + // U+FF0A: "*" FULLWIDTH ASTERISK + // U+FF03: "#" FULLWIDTH NUMBER SIGN + /* keylabel_to_phone_symbols */ "\uFF0A\uFF03", + // Key label for "ante meridiem" + /* keylabel_time_am */ "AM", + // Key label for "post meridiem" + /* keylabel_time_pm */ "PM", + /* keyspec_popular_domain */ ".com", + // popular web domains for the locale - most popular, displayed on the keyboard + /* morekeys_popular_domain */ "!hasLabels!,.net,.org,.gov,.edu", + /* keyspecs_left_parenthesis_more_keys */ "!text/keyspec_less_than,!text/keyspec_left_curly_bracket,!text/keyspec_left_square_bracket", + /* keyspecs_right_parenthesis_more_keys */ "!text/keyspec_greater_than,!text/keyspec_right_curly_bracket,!text/keyspec_right_square_bracket", + // The following characters don't need BIDI mirroring. + // U+2018: "‘" LEFT SINGLE QUOTATION MARK + // U+2019: "’" RIGHT SINGLE QUOTATION MARK + // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK + // Abbreviations are: + // laqm: LEFT-POINTING ANGLE QUOTATION MARK + // raqm: RIGHT-POINTING ANGLE QUOTATION MARK + // lqm: LEFT QUOTATION MARK + // rqm: RIGHT QUOTATION MARK + // 9qm: LOW-9 QUOTATION MARK + // The following each quotation mark pair consist of + // <opening quotation mark>, <closing quotation mark> + // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. + /* single_laqm_raqm */ "!text/keyspec_left_single_angle_quote,!text/keyspec_right_single_angle_quote", + /* single_raqm_laqm */ "!text/keyspec_right_single_angle_quote,!text/keyspec_left_single_angle_quote", + /* double_laqm_raqm */ "!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote", + /* double_raqm_laqm */ "!text/keyspec_right_double_angle_quote,!text/keyspec_left_double_angle_quote", + // The following each quotation mark triplet consists of + // <another quotation mark>, <opening quotation mark>, <closing quotation mark> + // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. + /* single_lqm_rqm */ "\u201A,\u2018,\u2019", + /* single_9qm_lqm */ "\u2019,\u201A,\u2018", + /* single_9qm_rqm */ "\u2018,\u201A,\u2019", + /* single_rqm_9qm */ "\u2018,\u2019,\u201A", + /* double_lqm_rqm */ "\u201E,\u201C,\u201D", + /* double_9qm_lqm */ "\u201D,\u201E,\u201C", + /* double_9qm_rqm */ "\u201C,\u201E,\u201D", + /* double_rqm_9qm */ "\u201C,\u201D,\u201E", + /* morekeys_single_quote */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes", + /* morekeys_double_quote */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes", + /* morekeys_tablet_double_quote */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes", + /* keyspec_emoji_key */ "!icon/emoji_key|!code/key_emoji", + }; + + /* Locale af: Afrikaans */ + private static final String[] TEXTS_af = { + // This is the same as Dutch except more keys of y and demoting vowels with diaeresis. + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E2,\u00E4,\u00E0,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F4,\u00F6,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_i */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133", + /* morekeys_c */ null, + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes ~ */ + null, null, null, + /* ~ morekeys_s */ + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_y */ "\u00FD,\u0133", + }; + + /* Locale ar: Arabic */ + private static final String[] TEXTS_ar = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE + // U+200C: ZERO WIDTH NON-JOINER + // U+0628: "ب" ARABIC LETTER BEH + // U+062C: "ج" ARABIC LETTER JEEM + /* keylabel_to_alpha */ "\u0623\u200C\u0628\u200C\u062C", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, + /* ~ morekeys_punctuation */ + // U+0661: "١" ARABIC-INDIC DIGIT ONE + /* keyspec_symbols_1 */ "\u0661", + // U+0662: "٢" ARABIC-INDIC DIGIT TWO + /* keyspec_symbols_2 */ "\u0662", + // U+0663: "٣" ARABIC-INDIC DIGIT THREE + /* keyspec_symbols_3 */ "\u0663", + // U+0664: "٤" ARABIC-INDIC DIGIT FOUR + /* keyspec_symbols_4 */ "\u0664", + // U+0665: "٥" ARABIC-INDIC DIGIT FIVE + /* keyspec_symbols_5 */ "\u0665", + // U+0666: "٦" ARABIC-INDIC DIGIT SIX + /* keyspec_symbols_6 */ "\u0666", + // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN + /* keyspec_symbols_7 */ "\u0667", + // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT + /* keyspec_symbols_8 */ "\u0668", + // U+0669: "٩" ARABIC-INDIC DIGIT NINE + /* keyspec_symbols_9 */ "\u0669", + // U+0660: "٠" ARABIC-INDIC DIGIT ZERO + /* keyspec_symbols_0 */ "\u0660", + // Label for "switch to symbols" key. + // U+061F: "؟" ARABIC QUESTION MARK + /* keylabel_to_symbol */ "\u0663\u0662\u0661\u061F", + /* additional_morekeys_symbols_1 */ "1", + /* additional_morekeys_symbols_2 */ "2", + /* additional_morekeys_symbols_3 */ "3", + /* additional_morekeys_symbols_4 */ "4", + /* additional_morekeys_symbols_5 */ "5", + /* additional_morekeys_symbols_6 */ "6", + /* additional_morekeys_symbols_7 */ "7", + /* additional_morekeys_symbols_8 */ "8", + /* additional_morekeys_symbols_9 */ "9", + // U+066B: "٫" ARABIC DECIMAL SEPARATOR + // U+066C: "٬" ARABIC THOUSANDS SEPARATOR + /* additional_morekeys_symbols_0 */ "0,\u066B,\u066C", + // U+061F: "؟" ARABIC QUESTION MARK + // U+060C: "،" ARABIC COMMA + // U+061B: "؛" ARABIC SEMICOLON + /* keyspec_tablet_comma */ "\u060C", + /* keyspec_swiss_row1_11 ~ */ + null, null, null, null, null, null, + /* ~ morekeys_swiss_row2_11 */ + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + /* morekeys_star */ "\u2605,\u066D", + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + /* keyspec_left_parenthesis */ "(|)", + /* keyspec_right_parenthesis */ ")|(", + /* keyspec_left_square_bracket */ "[|]", + /* keyspec_right_square_bracket */ "]|[", + /* keyspec_left_curly_bracket */ "{|}", + /* keyspec_right_curly_bracket */ "}|{", + /* keyspec_less_than */ "<|>", + /* keyspec_greater_than */ ">|<", + /* keyspec_less_than_equal */ "\u2264|\u2265", + /* keyspec_greater_than_equal */ "\u2265|\u2264", + /* keyspec_left_double_angle_quote */ "\u00AB|\u00BB", + /* keyspec_right_double_angle_quote */ "\u00BB|\u00AB", + /* keyspec_left_single_angle_quote */ "\u2039|\u203A", + /* keyspec_right_single_angle_quote */ "\u203A|\u2039", + /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\",\'", + // U+0651: "ّ" ARABIC SHADDA + /* keyhintlabel_period */ "\u0651", + /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics", + // U+00BF: "¿" INVERTED QUESTION MARK + /* morekeys_question */ "?,\u00BF", + /* morekeys_h ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_spanish_row2_10 */ + // U+266A: "♪" EIGHTH NOTE + /* morekeys_bullet */ "\u266A", + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + /* morekeys_left_parenthesis */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,!text/keyspecs_left_parenthesis_more_keys", + /* morekeys_right_parenthesis */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,!text/keyspecs_right_parenthesis_more_keys", + // U+0655: "ٕ" ARABIC HAMZA BELOW + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+0652: "ْ" ARABIC SUKUN + // U+064D: "ٍ" ARABIC KASRATAN + // U+064C: "ٌ" ARABIC DAMMATAN + // U+064B: "ً" ARABIC FATHATAN + // U+0651: "ّ" ARABIC SHADDA + // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+0653: "ٓ" ARABIC MADDAH ABOVE + // U+0650: "ِ" ARABIC KASRA + // U+064F: "ُ" ARABIC DAMMA + // U+064E: "َ" ARABIC FATHA + // U+0640: "ـ" ARABIC TATWEEL + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. + /* morekeys_arabic_diacritics */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640", + // U+060C: "،" ARABIC COMMA + /* keyspec_comma */ "\u060C", + /* keyhintlabel_tablet_comma */ "\u061F", + /* keyspec_period */ null, + /* morekeys_period */ "!text/morekeys_arabic_diacritics", + /* keyspec_tablet_period */ null, + /* keyhintlabel_tablet_period */ "\u0651", + /* keyspec_symbols_question */ "\u061F", + /* keyspec_symbols_semicolon */ "\u061B", + // U+066A: "٪" ARABIC PERCENT SIGN + /* keyspec_symbols_percent */ "\u066A", + /* morekeys_symbols_semicolon */ ";", + // U+2030: "‰" PER MILLE SIGN + /* morekeys_symbols_percent */ "\\%,\u2030", + }; + + /* Locale az_AZ: Azerbaijani (Azerbaijan) */ + private static final String[] TEXTS_az_AZ = { + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + /* morekeys_a */ "\u00E2", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", + // U+0259: "ə" LATIN SMALL LETTER SCHWA + /* morekeys_e */ "\u0259", + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes ~ */ + null, null, null, null, + /* ~ keylabel_to_alpha */ + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u015F,\u00DF,\u015B,\u0161", + /* morekeys_y ~ */ + null, null, null, null, null, + /* ~ morekeys_l */ + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u011F", + }; + + /* Locale be_BY: Belarusian (Belarus) */ + private static final String[] TEXTS_be_BY = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_k */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* morekeys_cyrillic_ie */ "\u0451", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, + /* ~ morekeys_nordic_row2_10 */ + // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U + /* keyspec_east_slavic_row1_9 */ "\u045E", + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + /* keyspec_east_slavic_row2_2 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* keyspec_east_slavic_row2_11 */ "\u044D", + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + /* keyspec_east_slavic_row3_5 */ "\u0456", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* morekeys_cyrillic_soft_sign */ "\u044A", + }; + + /* Locale bg: Bulgarian */ + private static final String[] TEXTS_bg = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + // single_quotes of Bulgarian is default single_quotes_right_left. + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ null, + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + }; + + /* Locale ca: Catalan */ + private static final String[] TEXTS_ca = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E0,\u00E1,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E8,\u00E9,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes ~ */ + null, null, null, null, null, null, null, + /* ~ morekeys_t */ + // U+00B7: "·" MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "l\u00B7l,\u0142", + /* morekeys_g ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, + /* ~ morekeys_nordic_row2_11 */ + // U+00B7: "·" MIDDLE DOT + /* morekeys_punctuation */ "!autoColumnOrder!9,\\,,?,!,\u00B7,#,),(,/,;,',@,:,-,\",+,\\%,&", + /* keyspec_symbols_1 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_south_slavic_row3_8 */ + /* morekeys_tablet_punctuation */ "!autoColumnOrder!8,\\,,',\u00B7,#,),(,/,;,@,:,-,\",+,\\%,&", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* keyspec_spanish_row2_10 */ "\u00E7", + }; + + /* Locale cs: Czech */ + private static final String[] TEXTS_cs = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u011B,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B", + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u00E7,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u0148,\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + /* morekeys_s */ "\u0161,\u00DF,\u015B", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u010F", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + /* morekeys_z */ "\u017E,\u017A,\u017C", + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + /* morekeys_t */ "\u0165", + /* morekeys_l */ null, + /* morekeys_g */ null, + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency */ null, + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + /* morekeys_r */ "\u0159", + }; + + /* Locale da: Danish */ + private static final String[] TEXTS_da = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E4,\u00E0,\u00E2,\u00E3,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F4,\u00F2,\u00F5,\u0153,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + /* morekeys_e */ "\u00E9,\u00EB", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + /* morekeys_i */ "\u00ED,\u00EF", + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_lqm", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u00DF,\u015B,\u0161", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+00F0: "ð" LATIN SMALL LETTER ETH + /* morekeys_d */ "\u00F0", + /* morekeys_z */ null, + /* morekeys_t */ null, + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u0142", + /* morekeys_g */ null, + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency ~ */ + null, null, null, null, + /* ~ morekeys_cyrillic_ie */ + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + /* keyspec_nordic_row1_11 */ "\u00E5", + // U+00E6: "æ" LATIN SMALL LETTER AE + /* keyspec_nordic_row2_10 */ "\u00E6", + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* keyspec_nordic_row2_11 */ "\u00F8", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* morekeys_nordic_row2_10 */ "\u00E4", + /* keyspec_east_slavic_row1_9 ~ */ + null, null, null, null, null, + /* ~ morekeys_cyrillic_soft_sign */ + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* morekeys_nordic_row2_11 */ "\u00F6", + }; + + /* Locale de: German */ + private static final String[] TEXTS_de = { + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E4,%,\u00E2,\u00E0,\u00E1,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F6,%,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u00F8,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FC,%,\u00FB,\u00F9,\u00FA,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0117", + /* morekeys_i */ null, + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_lqm", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u00DF,\u015B,\u0161", + /* morekeys_y ~ */ + null, null, null, null, null, null, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, + /* ~ keyspec_tablet_comma */ + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + /* keyspec_swiss_row1_11 */ "\u00FC", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* keyspec_swiss_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* keyspec_swiss_row2_11 */ "\u00E4", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + /* morekeys_swiss_row1_11 */ "\u00E8", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + /* morekeys_swiss_row2_10 */ "\u00E9", + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + /* morekeys_swiss_row2_11 */ "\u00E0", + }; + + /* Locale el: Greek */ + private static final String[] TEXTS_el = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0391: "Α" GREEK CAPITAL LETTER ALPHA + // U+0392: "Β" GREEK CAPITAL LETTER BETA + // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA + /* keylabel_to_alpha */ "\u0391\u0392\u0393", + }; + + /* Locale en: English */ + private static final String[] TEXTS_en = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* morekeys_o */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + /* morekeys_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* morekeys_c */ "\u00E7", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* morekeys_n */ "\u00F1", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* morekeys_s */ "\u00DF", + }; + + /* Locale eo: Esperanto */ + private static final String[] TEXTS_eo = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101,\u0103,\u0105,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D,\u0151,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00B5: "µ" MICRO SIGN + /* morekeys_u */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B,\u0169,\u0171,\u0173,\u00B5", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u011B,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u0129,\u00EC,\u012F,\u012B,\u0131,\u0133", + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE + /* morekeys_c */ "\u0107,\u010D,\u00E7,\u010B", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + // U+014B: "ŋ" LATIN SMALL LETTER ENG + /* morekeys_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + /* morekeys_s */ "\u00DF,\u0161,\u015B,\u0219,\u015F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + // U+00FE: "þ" LATIN SMALL LETTER THORN + /* morekeys_y */ "y,\u00FD,\u0177,\u00FF,\u00FE", + // U+00F0: "ð" LATIN SMALL LETTER ETH + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + /* morekeys_d */ "\u00F0,\u010F,\u0111", + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + /* morekeys_z */ "\u017A,\u017C,\u017E", + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE + /* morekeys_t */ "\u0165,\u021B,\u0163,\u0167", + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u013A,\u013C,\u013E,\u0140,\u0142", + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + /* morekeys_g */ "\u011F,\u0121,\u0123", + /* single_angle_quotes ~ */ + null, null, null, + /* ~ keyspec_currency */ + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + /* morekeys_r */ "\u0159,\u0155,\u0157", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + // U+0138: "ĸ" LATIN SMALL LETTER KRA + /* morekeys_k */ "\u0137,\u0138", + /* morekeys_cyrillic_ie ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_question */ + // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX + // U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE + /* morekeys_h */ "\u0125,\u0127", + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + /* morekeys_w */ "w,\u0175", + /* morekeys_east_slavic_row2_2 ~ */ + null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_tablet_punctuation */ + // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX + /* keyspec_spanish_row2_10 */ "\u0135", + /* morekeys_bullet ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_symbols_percent */ + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + /* morekeys_v */ "w,\u0175", + /* morekeys_j */ null, + /* morekeys_q */ "q", + /* morekeys_x */ "x", + // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX + /* keyspec_q */ "\u015D", + // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX + /* keyspec_w */ "\u011D", + // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE + /* keyspec_y */ "\u016D", + // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX + /* keyspec_x */ "\u0109", + }; + + /* Locale es: Spanish */ + private static final String[] TEXTS_es = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_nordic_row2_11 */ + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + /* morekeys_punctuation */ "!autoColumnOrder!9,\\,,?,!,#,),(,/,;,\u00A1,',@,:,-,\",+,\\%,&,\u00BF", + }; + + /* Locale et_EE: Estonian (Estonia) */ + private static final String[] TEXTS_et_EE = { + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + /* morekeys_a */ "\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6,\u0105", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_o */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + /* morekeys_u */ "\u00FC,\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u016F,\u0171", + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + /* morekeys_e */ "\u0113,\u00E8,\u0117,\u00E9,\u00EA,\u00EB,\u0119,\u011B", + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + /* morekeys_i */ "\u012B,\u00EC,\u012F,\u00ED,\u00EE,\u00EF,\u0131", + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u00E7,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u0146,\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + /* morekeys_s */ "\u0161,\u00DF,\u015B,\u015F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u010F", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + /* morekeys_z */ "\u017E,\u017C,\u017A", + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + /* morekeys_t */ "\u0163,\u0165", + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + /* morekeys_l */ "\u013C,\u0142,\u013A,\u013E", + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u0123,\u011F", + /* single_angle_quotes ~ */ + null, null, null, + /* ~ keyspec_currency */ + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + /* morekeys_r */ "\u0157,\u0159,\u0155", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + /* morekeys_k */ "\u0137", + /* morekeys_cyrillic_ie */ null, + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + /* keyspec_nordic_row1_11 */ "\u00FC", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* keyspec_nordic_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* keyspec_nordic_row2_11 */ "\u00E4", + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* morekeys_nordic_row2_10 */ "\u00F5", + }; + + /* Locale eu_ES: Basque (Spain) */ + private static final String[] TEXTS_eu_ES = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + }; + + /* Locale fa: Persian */ + private static final String[] TEXTS_fa = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0627: "ا" ARABIC LETTER ALEF + // U+200C: ZERO WIDTH NON-JOINER + // U+0628: "ب" ARABIC LETTER BEH + // U+067E: "پ" ARABIC LETTER PEH + /* keylabel_to_alpha */ "\u0627\u200C\u0628\u200C\u067E", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+FDFC: "﷼" RIAL SIGN + /* keyspec_currency */ "\uFDFC", + /* morekeys_r ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_punctuation */ + // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE + /* keyspec_symbols_1 */ "\u06F1", + // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO + /* keyspec_symbols_2 */ "\u06F2", + // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE + /* keyspec_symbols_3 */ "\u06F3", + // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR + /* keyspec_symbols_4 */ "\u06F4", + // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE + /* keyspec_symbols_5 */ "\u06F5", + // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX + /* keyspec_symbols_6 */ "\u06F6", + // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN + /* keyspec_symbols_7 */ "\u06F7", + // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT + /* keyspec_symbols_8 */ "\u06F8", + // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE + /* keyspec_symbols_9 */ "\u06F9", + // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO + /* keyspec_symbols_0 */ "\u06F0", + // Label for "switch to symbols" key. + // U+061F: "؟" ARABIC QUESTION MARK + /* keylabel_to_symbol */ "\u06F3\u06F2\u06F1\u061F", + /* additional_morekeys_symbols_1 */ "1", + /* additional_morekeys_symbols_2 */ "2", + /* additional_morekeys_symbols_3 */ "3", + /* additional_morekeys_symbols_4 */ "4", + /* additional_morekeys_symbols_5 */ "5", + /* additional_morekeys_symbols_6 */ "6", + /* additional_morekeys_symbols_7 */ "7", + /* additional_morekeys_symbols_8 */ "8", + /* additional_morekeys_symbols_9 */ "9", + // U+066B: "٫" ARABIC DECIMAL SEPARATOR + // U+066C: "٬" ARABIC THOUSANDS SEPARATOR + /* additional_morekeys_symbols_0 */ "0,\u066B,\u066C", + // U+060C: "،" ARABIC COMMA + // U+061B: "؛" ARABIC SEMICOLON + // U+061F: "؟" ARABIC QUESTION MARK + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + /* keyspec_tablet_comma */ "\u060C", + /* keyspec_swiss_row1_11 ~ */ + null, null, null, null, null, null, + /* ~ morekeys_swiss_row2_11 */ + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + /* morekeys_star */ "\u2605,\u066D", + /* keyspec_left_parenthesis */ "(|)", + /* keyspec_right_parenthesis */ ")|(", + /* keyspec_left_square_bracket */ "[|]", + /* keyspec_right_square_bracket */ "]|[", + /* keyspec_left_curly_bracket */ "{|}", + /* keyspec_right_curly_bracket */ "}|{", + /* keyspec_less_than */ "<|>", + /* keyspec_greater_than */ ">|<", + /* keyspec_less_than_equal */ "\u2264|\u2265", + /* keyspec_greater_than_equal */ "\u2265|\u2264", + /* keyspec_left_double_angle_quote */ "\u00AB|\u00BB", + /* keyspec_right_double_angle_quote */ "\u00BB|\u00AB", + /* keyspec_left_single_angle_quote */ "\u2039|\u203A", + /* keyspec_right_single_angle_quote */ "\u203A|\u2039", + /* morekeys_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote", + // U+064B: "ً" ARABIC FATHATAN + /* keyhintlabel_period */ "\u064B", + /* morekeys_tablet_period */ "!text/morekeys_arabic_diacritics", + // U+00BF: "¿" INVERTED QUESTION MARK + /* morekeys_question */ "?,\u00BF", + /* morekeys_h ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_spanish_row2_10 */ + // U+266A: "♪" EIGHTH NOTE + /* morekeys_bullet */ "\u266A", + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + /* morekeys_left_parenthesis */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,!text/keyspecs_left_parenthesis_more_keys", + /* morekeys_right_parenthesis */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,!text/keyspecs_right_parenthesis_more_keys", + // U+0655: "ٕ" ARABIC HAMZA BELOW + // U+0652: "ْ" ARABIC SUKUN + // U+0651: "ّ" ARABIC SHADDA + // U+064C: "ٌ" ARABIC DAMMATAN + // U+064D: "ٍ" ARABIC KASRATAN + // U+064B: "ً" ARABIC FATHATAN + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+0653: "ٓ" ARABIC MADDAH ABOVE + // U+064F: "ُ" ARABIC DAMMA + // U+0650: "ِ" ARABIC KASRA + // U+064E: "َ" ARABIC FATHA + // U+0640: "ـ" ARABIC TATWEEL + // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. + // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. + /* morekeys_arabic_diacritics */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640", + // U+060C: "،" ARABIC COMMA + /* keyspec_comma */ "\u060C", + /* keyhintlabel_tablet_comma */ "\u061F", + /* keyspec_period */ null, + /* morekeys_period */ "!text/morekeys_arabic_diacritics", + /* keyspec_tablet_period */ null, + /* keyhintlabel_tablet_period */ "\u064B", + /* keyspec_symbols_question */ "\u061F", + /* keyspec_symbols_semicolon */ "\u061B", + // U+066A: "٪" ARABIC PERCENT SIGN + /* keyspec_symbols_percent */ "\u066A", + /* morekeys_symbols_semicolon */ ";", + // U+2030: "‰" PER MILLE SIGN + /* morekeys_symbols_percent */ "\\%,\u2030", + /* morekeys_v ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_plus */ + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + /* morekeys_less_than */ "!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote,!text/keyspec_less_than_equal,!text/keyspec_less_than", + /* morekeys_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_greater_than", + }; + + /* Locale fi: Finnish */ + private static final String[] TEXTS_fi = { + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E6,\u00E0,\u00E1,\u00E2,\u00E3,\u0101", + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + /* morekeys_u */ "\u00FC", + /* morekeys_e ~ */ + null, null, null, null, null, null, null, + /* ~ keylabel_to_alpha */ + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + /* morekeys_s */ "\u0161,\u00DF,\u015B", + /* morekeys_y */ null, + /* morekeys_d */ null, + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + /* morekeys_z */ "\u017E,\u017A,\u017C", + /* morekeys_t ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ morekeys_cyrillic_ie */ + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + /* keyspec_nordic_row1_11 */ "\u00E5", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* keyspec_nordic_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* keyspec_nordic_row2_11 */ "\u00E4", + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_nordic_row2_10 */ "\u00F8", + /* keyspec_east_slavic_row1_9 ~ */ + null, null, null, null, null, + /* ~ morekeys_cyrillic_soft_sign */ + // U+00E6: "æ" LATIN SMALL LETTER AE + /* morekeys_nordic_row2_11 */ "\u00E6", + }; + + /* Locale fr: French */ + private static final String[] TEXTS_fr = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E0,\u00E2,%,\u00E6,\u00E1,\u00E4,\u00E3,\u00E5,\u0101,\u00AA", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F4,\u0153,%,\u00F6,\u00F2,\u00F3,\u00F5,\u00F8,\u014D,\u00BA", + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00F9,\u00FB,%,\u00FC,\u00FA,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,%,\u0119,\u0117,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00EE,%,\u00EF,\u00EC,\u00ED,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,%,\u0107,\u010D", + /* double_quotes ~ */ + null, null, null, null, null, + /* ~ morekeys_s */ + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "%,\u00FF", + /* morekeys_d ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_tablet_comma */ + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + /* keyspec_swiss_row1_11 */ "\u00E8", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + /* keyspec_swiss_row2_10 */ "\u00E9", + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + /* keyspec_swiss_row2_11 */ "\u00E0", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + /* morekeys_swiss_row1_11 */ "\u00FC", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* morekeys_swiss_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* morekeys_swiss_row2_11 */ "\u00E4", + }; + + /* Locale gl_ES: Gallegan (Spain) */ + private static final String[] TEXTS_gl_ES = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + }; + + /* Locale hi: Hindi */ + private static final String[] TEXTS_hi = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0915: "क" DEVANAGARI LETTER KA + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0917: "ग" DEVANAGARI LETTER GA + /* keylabel_to_alpha */ "\u0915\u0916\u0917", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20B9: "₹" INDIAN RUPEE SIGN + /* keyspec_currency */ "\u20B9", + /* morekeys_r ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_punctuation */ + // U+0967: "१" DEVANAGARI DIGIT ONE + /* keyspec_symbols_1 */ "\u0967", + // U+0968: "२" DEVANAGARI DIGIT TWO + /* keyspec_symbols_2 */ "\u0968", + // U+0969: "३" DEVANAGARI DIGIT THREE + /* keyspec_symbols_3 */ "\u0969", + // U+096A: "४" DEVANAGARI DIGIT FOUR + /* keyspec_symbols_4 */ "\u096A", + // U+096B: "५" DEVANAGARI DIGIT FIVE + /* keyspec_symbols_5 */ "\u096B", + // U+096C: "६" DEVANAGARI DIGIT SIX + /* keyspec_symbols_6 */ "\u096C", + // U+096D: "७" DEVANAGARI DIGIT SEVEN + /* keyspec_symbols_7 */ "\u096D", + // U+096E: "८" DEVANAGARI DIGIT EIGHT + /* keyspec_symbols_8 */ "\u096E", + // U+096F: "९" DEVANAGARI DIGIT NINE + /* keyspec_symbols_9 */ "\u096F", + // U+0966: "०" DEVANAGARI DIGIT ZERO + /* keyspec_symbols_0 */ "\u0966", + // Label for "switch to symbols" key. + /* keylabel_to_symbol */ "?\u0967\u0968\u0969", + /* additional_morekeys_symbols_1 */ "1", + /* additional_morekeys_symbols_2 */ "2", + /* additional_morekeys_symbols_3 */ "3", + /* additional_morekeys_symbols_4 */ "4", + /* additional_morekeys_symbols_5 */ "5", + /* additional_morekeys_symbols_6 */ "6", + /* additional_morekeys_symbols_7 */ "7", + /* additional_morekeys_symbols_8 */ "8", + /* additional_morekeys_symbols_9 */ "9", + /* additional_morekeys_symbols_0 */ "0", + }; + + /* Locale hr: Croatian */ + private static final String[] TEXTS_hr = { + /* morekeys_a ~ */ + null, null, null, null, null, + /* ~ morekeys_i */ + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* morekeys_c */ "\u010D,\u0107,\u00E7", + /* double_quotes */ "!text/double_9qm_rqm", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* morekeys_s */ "\u0161,\u015B,\u00DF", + /* morekeys_y */ null, + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + /* morekeys_d */ "\u0111", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + /* morekeys_z */ "\u017E,\u017A,\u017C", + /* morekeys_t ~ */ + null, null, null, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + }; + + /* Locale hu: Hungarian */ + private static final String[] TEXTS_hu = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F6,\u0151,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u0171,\u00FB,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B", + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_rqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha ~ */ + null, null, null, null, null, null, null, null, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + }; + + /* Locale hy_AM: Armenian (Armenia) */ + private static final String[] TEXTS_hy_AM = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB + // U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN + // U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM + /* keylabel_to_alpha */ "\u0531\u0532\u0533", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, + /* ~ morekeys_nordic_row2_11 */ + // U+055E: "՞" ARMENIAN QUESTION MARK + // U+055C: "՜" ARMENIAN EXCLAMATION MARK + // U+055A: "՚" ARMENIAN APOSTROPHE + // U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING + // U+055D: "՝" ARMENIAN COMMA + // U+055B: "՛" ARMENIAN EMPHASIS MARK + // U+058A: "֊" ARMENIAN HYPHEN + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+055F: "՟" ARMENIAN ABBREVIATION MARK + /* morekeys_punctuation */ "!autoColumnOrder!8,\\,,\u055E,\u055C,.,\u055A,\u0559,?,!,\u055D,\u055B,\u058A,\u00BB,\u00AB,\u055F,;,:", + /* keyspec_symbols_1 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ additional_morekeys_symbols_0 */ + // U+058F: "֏" ARMENIAN DRAM SIGN + // TODO: Enable this when we have glyph for the following letter + // <string name="keyspec_currency">֏</string> + // + // U+055D: "՝" ARMENIAN COMMA + /* keyspec_tablet_comma */ "\u055D", + /* keyspec_swiss_row1_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, + /* ~ keyhintlabel_period */ + /* morekeys_tablet_period */ "!text/morekeys_punctuation", + // U+055E: "՞" ARMENIAN QUESTION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + /* morekeys_question */ "\u055E,\u00BF", + /* morekeys_h ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, + /* ~ keyhintlabel_tablet_comma */ + // U+0589: "։" ARMENIAN FULL STOP + /* keyspec_period */ "\u0589", + /* morekeys_period */ null, + /* keyspec_tablet_period */ "\u0589", + /* keyhintlabel_tablet_period ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ morekeys_greater_than */ + // U+055C: "՜" ARMENIAN EXCLAMATION MARK + // U+00A1: "¡" INVERTED EXCLAMATION MARK + /* morekeys_exclamation */ "\u055C,\u00A1", + }; + + /* Locale is: Icelandic */ + private static final String[] TEXTS_is = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E4,\u00E6,\u00E5,\u00E0,\u00E2,\u00E3,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00EB,\u00E8,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B", + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + /* morekeys_s */ null, + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+00F0: "ð" LATIN SMALL LETTER ETH + /* morekeys_d */ "\u00F0", + /* morekeys_z */ null, + // U+00FE: "þ" LATIN SMALL LETTER THORN + /* morekeys_t */ "\u00FE", + }; + + /* Locale it: Italian */ + private static final String[] TEXTS_it = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101,\u00AA", + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F2,\u00F3,\u00F4,\u00F6,\u00F5,\u0153,\u00F8,\u014D,\u00BA", + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00F9,\u00FA,\u00FB,\u00FC,\u016B", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u0117,\u0113", + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u012F,\u012B", + /* morekeys_c ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ keyspec_tablet_comma */ + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + /* keyspec_swiss_row1_11 */ "\u00FC", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* keyspec_swiss_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* keyspec_swiss_row2_11 */ "\u00E4", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + /* morekeys_swiss_row1_11 */ "\u00E8", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + /* morekeys_swiss_row2_10 */ "\u00E9", + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + /* morekeys_swiss_row2_11 */ "\u00E0", + }; + + /* Locale iw: Hebrew */ + private static final String[] TEXTS_iw = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_rqm_9qm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_rqm_9qm", + // Label for "switch to alphabetic" key. + // U+05D0: "א" HEBREW LETTER ALEF + // U+05D1: "ב" HEBREW LETTER BET + // U+05D2: "ג" HEBREW LETTER GIMEL + /* keylabel_to_alpha */ "\u05D0\u05D1\u05D2", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20AA: "₪" NEW SHEQEL SIGN + /* keyspec_currency */ "\u20AA", + /* morekeys_r ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_swiss_row2_11 */ + // U+2605: "★" BLACK STAR + /* morekeys_star */ "\u2605", + // The all letters need to be mirrored are found at + // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + /* keyspec_left_parenthesis */ "(|)", + /* keyspec_right_parenthesis */ ")|(", + /* keyspec_left_square_bracket */ "[|]", + /* keyspec_right_square_bracket */ "]|[", + /* keyspec_left_curly_bracket */ "{|}", + /* keyspec_right_curly_bracket */ "}|{", + /* keyspec_less_than */ "<|>", + /* keyspec_greater_than */ ">|<", + /* keyspec_less_than_equal */ "\u2264|\u2265", + /* keyspec_greater_than_equal */ "\u2265|\u2264", + /* keyspec_left_double_angle_quote */ "\u00AB|\u00BB", + /* keyspec_right_double_angle_quote */ "\u00BB|\u00AB", + /* keyspec_left_single_angle_quote */ "\u2039|\u203A", + /* keyspec_right_single_angle_quote */ "\u203A|\u2039", + /* morekeys_tablet_comma ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_currency_dollar */ + // U+00B1: "±" PLUS-MINUS SIGN + // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN + /* morekeys_plus */ "\u00B1,\uFB29", + }; + + /* Locale ka_GE: Georgian (Georgia) */ + private static final String[] TEXTS_ka_GE = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // Label for "switch to alphabetic" key. + // U+10D0: "ა" GEORGIAN LETTER AN + // U+10D1: "ბ" GEORGIAN LETTER BAN + // U+10D2: "გ" GEORGIAN LETTER GAN + /* keylabel_to_alpha */ "\u10D0\u10D1\u10D2", + }; + + /* Locale kk: Kazakh */ + private static final String[] TEXTS_kk = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_k */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* morekeys_cyrillic_ie */ "\u0451", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, + /* ~ morekeys_nordic_row2_10 */ + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + /* keyspec_east_slavic_row1_9 */ "\u0449", + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + /* keyspec_east_slavic_row2_2 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* keyspec_east_slavic_row2_11 */ "\u044D", + // U+0438: "и" CYRILLIC SMALL LETTER I + /* keyspec_east_slavic_row3_5 */ "\u0438", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* morekeys_cyrillic_soft_sign */ "\u044A", + /* morekeys_nordic_row2_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ morekeys_w */ + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + /* morekeys_east_slavic_row2_2 */ "\u0456", + // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U + // U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE + /* morekeys_cyrillic_u */ "\u04AF,\u04B1", + // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER + /* morekeys_cyrillic_en */ "\u04A3", + // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE + /* morekeys_cyrillic_ghe */ "\u0493", + // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O + /* morekeys_cyrillic_o */ "\u04E9", + /* morekeys_cyrillic_i ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_x */ + // U+04BB: "һ" CYRILLIC SMALL LETTER SHHA + /* morekeys_east_slavic_row2_11 */ "\u04BB", + // U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER + /* morekeys_cyrillic_ka */ "\u049B", + // U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA + /* morekeys_cyrillic_a */ "\u04D9", + }; + + /* Locale km_KH: Khmer (Cambodia) */ + private static final String[] TEXTS_km_KH = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+1780: "ក" KHMER LETTER KA + // U+1781: "ខ" KHMER LETTER KHA + // U+1782: "គ" KHMER LETTER KO + /* keylabel_to_alpha */ "\u1780\u1781\u1782", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ morekeys_cyrillic_a */ + // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL + /* morekeys_currency_dollar */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", + }; + + /* Locale ky: Kirghiz */ + private static final String[] TEXTS_ky = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_k */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* morekeys_cyrillic_ie */ "\u0451", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, + /* ~ morekeys_nordic_row2_10 */ + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + /* keyspec_east_slavic_row1_9 */ "\u0449", + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + /* keyspec_east_slavic_row2_2 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* keyspec_east_slavic_row2_11 */ "\u044D", + // U+0438: "и" CYRILLIC SMALL LETTER I + /* keyspec_east_slavic_row3_5 */ "\u0438", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* morekeys_cyrillic_soft_sign */ "\u044A", + /* morekeys_nordic_row2_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, + /* ~ morekeys_east_slavic_row2_2 */ + // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U + /* morekeys_cyrillic_u */ "\u04AF", + // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER + /* morekeys_cyrillic_en */ "\u04A3", + /* morekeys_cyrillic_ghe */ null, + // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O + /* morekeys_cyrillic_o */ "\u04E9", + }; + + /* Locale lo_LA: Lao (Laos) */ + private static final String[] TEXTS_lo_LA = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0E81: "ກ" LAO LETTER KO + // U+0E82: "ຂ" LAO LETTER KHO SUNG + // U+0E84: "ຄ" LAO LETTER KHO TAM + /* keylabel_to_alpha */ "\u0E81\u0E82\u0E84", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20AD: "₭" KIP SIGN + /* keyspec_currency */ "\u20AD", + }; + + /* Locale lt: Lithuanian */ + private static final String[] TEXTS_lt = { + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + /* morekeys_a */ "\u0105,\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_o */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8", + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + /* morekeys_u */ "\u016B,\u0173,\u00FC,\u016B,\u00F9,\u00FA,\u00FB,\u016F,\u0171", + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + /* morekeys_e */ "\u0117,\u0119,\u0113,\u00E8,\u00E9,\u00EA,\u00EB,\u011B", + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + /* morekeys_i */ "\u012F,\u012B,\u00EC,\u00ED,\u00EE,\u00EF,\u0131", + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u00E7,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u0146,\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + /* morekeys_s */ "\u0161,\u00DF,\u015B,\u015F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u010F", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + /* morekeys_z */ "\u017E,\u017C,\u017A", + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + /* morekeys_t */ "\u0163,\u0165", + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + /* morekeys_l */ "\u013C,\u0142,\u013A,\u013E", + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u0123,\u011F", + /* single_angle_quotes ~ */ + null, null, null, + /* ~ keyspec_currency */ + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + /* morekeys_r */ "\u0157,\u0159,\u0155", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + /* morekeys_k */ "\u0137", + }; + + /* Locale lv: Latvian */ + private static final String[] TEXTS_lv = { + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + /* morekeys_a */ "\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u0105", + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_o */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u0153,\u0151,\u00F8", + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + /* morekeys_u */ "\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u00FC,\u016F,\u0171", + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + /* morekeys_e */ "\u0113,\u0117,\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u011B", + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + /* morekeys_i */ "\u012B,\u012F,\u00EC,\u00ED,\u00EE,\u00EF,\u0131", + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u00E7,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u0146,\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + /* morekeys_s */ "\u0161,\u00DF,\u015B,\u015F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u010F", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + /* morekeys_z */ "\u017E,\u017C,\u017A", + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + /* morekeys_t */ "\u0163,\u0165", + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + /* morekeys_l */ "\u013C,\u0142,\u013A,\u013E", + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u0123,\u011F", + /* single_angle_quotes ~ */ + null, null, null, + /* ~ keyspec_currency */ + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + /* morekeys_r */ "\u0157,\u0159,\u0155", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + /* morekeys_k */ "\u0137", + }; + + /* Locale mk: Macedonian */ + private static final String[] TEXTS_mk = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_k */ + // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE + /* morekeys_cyrillic_ie */ "\u0450", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, + /* ~ morekeys_cyrillic_o */ + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + /* morekeys_cyrillic_i */ "\u045D", + // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE + /* keyspec_south_slavic_row1_6 */ "\u0455", + // U+045C: "ќ" CYRILLIC SMALL LETTER KJE + /* keyspec_south_slavic_row2_11 */ "\u045C", + // U+0437: "з" CYRILLIC SMALL LETTER ZE + /* keyspec_south_slavic_row3_1 */ "\u0437", + // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE + /* keyspec_south_slavic_row3_8 */ "\u0453", + }; + + /* Locale mn_MN: Mongolian (Mongolia) */ + private static final String[] TEXTS_mn_MN = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20AE: "₮" TUGRIK SIGN + /* keyspec_currency */ "\u20AE", + }; + + /* Locale my_MM: Burmese (Myanmar) */ + private static final String[] TEXTS_my_MM = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+1000: "က" MYANMAR LETTER KA + // U+1001: "ခ" MYANMAR LETTER KHA + // U+1002: "ဂ" MYANMAR LETTER GA + /* keylabel_to_alpha */ "\u1000\u1001\u1002", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, + /* ~ morekeys_nordic_row2_11 */ + /* morekeys_punctuation */ "!autoColumnOrder!9,\u104A,.,?,!,#,),(,/,;,...,',@,:,-,\",+,\\%,&", + /* keyspec_symbols_1 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ additional_morekeys_symbols_0 */ + // U+104A: "၊" MYANMAR SIGN LITTLE SECTION + // U+104B: "။" MYANMAR SIGN SECTION + /* keyspec_tablet_comma */ "\u104A", + /* keyspec_swiss_row1_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ keyspec_right_single_angle_quote */ + /* morekeys_tablet_comma */ "\\,", + /* keyhintlabel_period */ "\u104A", + /* morekeys_tablet_period ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ keyspec_south_slavic_row3_8 */ + /* morekeys_tablet_punctuation */ "!autoColumnOrder!8,.,',#,),(,/,;,@,...,:,-,\",+,\\%,&", + /* keyspec_spanish_row2_10 ~ */ + null, null, null, null, null, null, null, + /* ~ keyhintlabel_tablet_comma */ + /* keyspec_period */ "\u104B", + /* morekeys_period */ null, + /* keyspec_tablet_period */ "\u104B", + }; + + /* Locale nb: Norwegian Bokmål */ + private static final String[] TEXTS_nb = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E0,\u00E4,\u00E1,\u00E2,\u00E3,\u0101", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F4,\u00F2,\u00F3,\u00F6,\u00F5,\u0153,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113", + /* morekeys_i */ null, + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_rqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_cyrillic_ie */ + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + /* keyspec_nordic_row1_11 */ "\u00E5", + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* keyspec_nordic_row2_10 */ "\u00F8", + // U+00E6: "æ" LATIN SMALL LETTER AE + /* keyspec_nordic_row2_11 */ "\u00E6", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* morekeys_nordic_row2_10 */ "\u00F6", + /* keyspec_east_slavic_row1_9 ~ */ + null, null, null, null, null, + /* ~ morekeys_cyrillic_soft_sign */ + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* morekeys_nordic_row2_11 */ "\u00E4", + }; + + /* Locale ne_NP: Nepali (Nepal) */ + private static final String[] TEXTS_ne_NP = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0915: "क" DEVANAGARI LETTER KA + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0917: "ग" DEVANAGARI LETTER GA + /* keylabel_to_alpha */ "\u0915\u0916\u0917", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN + /* keyspec_currency */ "\u0930\u0941.", + /* morekeys_r ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_punctuation */ + // U+0967: "१" DEVANAGARI DIGIT ONE + /* keyspec_symbols_1 */ "\u0967", + // U+0968: "२" DEVANAGARI DIGIT TWO + /* keyspec_symbols_2 */ "\u0968", + // U+0969: "३" DEVANAGARI DIGIT THREE + /* keyspec_symbols_3 */ "\u0969", + // U+096A: "४" DEVANAGARI DIGIT FOUR + /* keyspec_symbols_4 */ "\u096A", + // U+096B: "५" DEVANAGARI DIGIT FIVE + /* keyspec_symbols_5 */ "\u096B", + // U+096C: "६" DEVANAGARI DIGIT SIX + /* keyspec_symbols_6 */ "\u096C", + // U+096D: "७" DEVANAGARI DIGIT SEVEN + /* keyspec_symbols_7 */ "\u096D", + // U+096E: "८" DEVANAGARI DIGIT EIGHT + /* keyspec_symbols_8 */ "\u096E", + // U+096F: "९" DEVANAGARI DIGIT NINE + /* keyspec_symbols_9 */ "\u096F", + // U+0966: "०" DEVANAGARI DIGIT ZERO + /* keyspec_symbols_0 */ "\u0966", + // Label for "switch to symbols" key. + /* keylabel_to_symbol */ "?\u0967\u0968\u0969", + /* additional_morekeys_symbols_1 */ "1", + /* additional_morekeys_symbols_2 */ "2", + /* additional_morekeys_symbols_3 */ "3", + /* additional_morekeys_symbols_4 */ "4", + /* additional_morekeys_symbols_5 */ "5", + /* additional_morekeys_symbols_6 */ "6", + /* additional_morekeys_symbols_7 */ "7", + /* additional_morekeys_symbols_8 */ "8", + /* additional_morekeys_symbols_9 */ "9", + /* additional_morekeys_symbols_0 */ "0", + }; + + /* Locale nl: Dutch */ + private static final String[] TEXTS_nl = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E1,\u00E4,\u00E2,\u00E0,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00EB,\u00EA,\u00E8,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133", + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_rqm", + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha */ null, + /* morekeys_s */ null, + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_y */ "\u0133", + }; + + /* Locale pl: Polish */ + private static final String[] TEXTS_pl = { + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u0105,\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D", + /* morekeys_u */ null, + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u0119,\u00E8,\u00E9,\u00EA,\u00EB,\u0117,\u0113", + /* morekeys_i */ null, + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u0107,\u00E7,\u010D", + /* double_quotes */ "!text/double_9qm_rqm", + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* morekeys_n */ "\u0144,\u00F1", + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha */ null, + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u015B,\u00DF,\u0161", + /* morekeys_y */ null, + /* morekeys_d */ null, + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + /* morekeys_z */ "\u017C,\u017A,\u017E", + /* morekeys_t */ null, + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u0142", + }; + + /* Locale pt: Portuguese */ + private static final String[] TEXTS_pt = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E3,\u00E0,\u00E2,\u00E4,\u00E5,\u00E6,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F5,\u00F4,\u00F2,\u00F6,\u0153,\u00F8,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + /* morekeys_e */ "\u00E9,\u00EA,\u00E8,\u0119,\u0117,\u0113,\u00EB", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EE,\u00EC,\u00EF,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u00E7,\u010D,\u0107", + }; + + /* Locale rm: Raeto-Romance */ + private static final String[] TEXTS_rm = { + /* morekeys_a */ null, + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_o */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u0153,\u00F8", + }; + + /* Locale ro: Romanian */ + private static final String[] TEXTS_ro = { + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101", + /* morekeys_o ~ */ + null, null, null, + /* ~ morekeys_e */ + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", + /* morekeys_c */ null, + /* double_quotes */ "!text/double_9qm_rqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_rqm", + /* keylabel_to_alpha */ null, + // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u0219,\u00DF,\u015B,\u0161", + /* morekeys_y ~ */ + null, null, null, + /* ~ morekeys_z */ + // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW + /* morekeys_t */ "\u021B", + }; + + /* Locale ru: Russian */ + private static final String[] TEXTS_ru = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_k */ + // U+0451: "ё" CYRILLIC SMALL LETTER IO + /* morekeys_cyrillic_ie */ "\u0451", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, + /* ~ morekeys_nordic_row2_10 */ + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + /* keyspec_east_slavic_row1_9 */ "\u0449", + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + /* keyspec_east_slavic_row2_2 */ "\u044B", + // U+044D: "э" CYRILLIC SMALL LETTER E + /* keyspec_east_slavic_row2_11 */ "\u044D", + // U+0438: "и" CYRILLIC SMALL LETTER I + /* keyspec_east_slavic_row3_5 */ "\u0438", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* morekeys_cyrillic_soft_sign */ "\u044A", + }; + + /* Locale sk: Slovak */ + private static final String[] TEXTS_sk = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + /* morekeys_a */ "\u00E1,\u00E4,\u0101,\u00E0,\u00E2,\u00E3,\u00E5,\u00E6,\u0105", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + /* morekeys_o */ "\u00F4,\u00F3,\u00F6,\u00F2,\u00F5,\u0153,\u0151,\u00F8", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + /* morekeys_u */ "\u00FA,\u016F,\u00FC,\u016B,\u0173,\u00F9,\u00FB,\u0171", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + /* morekeys_e */ "\u00E9,\u011B,\u0113,\u0117,\u00E8,\u00EA,\u00EB,\u0119", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + /* morekeys_i */ "\u00ED,\u012B,\u012F,\u00EC,\u00EE,\u00EF,\u0131", + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u00E7,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u0148,\u0146,\u00F1,\u0144", + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + /* morekeys_s */ "\u0161,\u00DF,\u015B,\u015F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u010F", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + /* morekeys_z */ "\u017E,\u017C,\u017A", + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + /* morekeys_t */ "\u0165,\u0163", + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u013E,\u013A,\u013C,\u0142", + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u0123,\u011F", + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency */ null, + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + /* morekeys_r */ "\u0155,\u0159,\u0157", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + /* morekeys_k */ "\u0137", + }; + + /* Locale sl: Slovenian */ + private static final String[] TEXTS_sl = { + /* morekeys_a ~ */ + null, null, null, null, null, + /* ~ morekeys_i */ + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + /* morekeys_c */ "\u010D,\u0107", + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + /* keylabel_to_alpha */ null, + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u0161", + /* morekeys_y */ null, + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + /* morekeys_d */ "\u0111", + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + /* morekeys_z */ "\u017E", + /* morekeys_t ~ */ + null, null, null, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + }; + + /* Locale sr: Serbian */ + private static final String[] TEXTS_sr = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // END: More keys definitions for Serbian (Cyrillic) + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, + /* ~ morekeys_g */ + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency ~ */ + null, null, null, + /* ~ morekeys_k */ + // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE + /* morekeys_cyrillic_ie */ "\u0450", + /* keyspec_nordic_row1_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, + /* ~ morekeys_cyrillic_o */ + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + /* morekeys_cyrillic_i */ "\u045D", + // TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified. + // BEGIN: More keys definitions for Serbian (Latin) + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // <string name="morekeys_s">š,ß,ś</string> + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // <string name="morekeys_c">č,ç,ć</string> + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // <string name="morekeys_d">ď</string> + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // <string name="morekeys_z">ž,ź,ż</string> + // END: More keys definitions for Serbian (Latin) + // BEGIN: More keys definitions for Serbian (Cyrillic) + // U+0437: "з" CYRILLIC SMALL LETTER ZE + /* keyspec_south_slavic_row1_6 */ "\u0437", + // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE + /* keyspec_south_slavic_row2_11 */ "\u045B", + // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE + /* keyspec_south_slavic_row3_1 */ "\u0455", + // U+0452: "ђ" CYRILLIC SMALL LETTER DJE + /* keyspec_south_slavic_row3_8 */ "\u0452", + }; + + /* Locale sv: Swedish */ + private static final String[] TEXTS_sv = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + /* morekeys_a */ "\u00E1,\u00E0,\u00E2,\u0105,\u00E3", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F3,\u00F2,\u00F4,\u00F5,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FC,\u00FA,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + /* morekeys_i */ "\u00ED,\u00EC,\u00EE,\u00EF", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + /* morekeys_n */ "\u0144,\u00F1,\u0148", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* morekeys_s */ "\u015B,\u0161,\u015F,\u00DF", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + /* morekeys_y */ "\u00FD,\u00FF", + // U+00F0: "ð" LATIN SMALL LETTER ETH + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + /* morekeys_d */ "\u00F0,\u010F", + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + /* morekeys_z */ "\u017A,\u017E,\u017C", + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+00FE: "þ" LATIN SMALL LETTER THORN + /* morekeys_t */ "\u0165,\u00FE", + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u0142", + /* morekeys_g */ null, + /* single_angle_quotes */ "!text/single_raqm_laqm", + /* double_angle_quotes */ "!text/double_raqm_laqm", + /* keyspec_currency */ null, + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + /* morekeys_r */ "\u0159", + /* morekeys_k */ null, + /* morekeys_cyrillic_ie */ null, + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + /* keyspec_nordic_row1_11 */ "\u00E5", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + /* keyspec_nordic_row2_10 */ "\u00F6", + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + /* keyspec_nordic_row2_11 */ "\u00E4", + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + /* morekeys_nordic_row2_10 */ "\u00F8,\u0153", + /* keyspec_east_slavic_row1_9 ~ */ + null, null, null, null, null, + /* ~ morekeys_cyrillic_soft_sign */ + // U+00E6: "æ" LATIN SMALL LETTER AE + /* morekeys_nordic_row2_11 */ "\u00E6", + }; + + /* Locale sw: Swahili */ + private static final String[] TEXTS_sw = { + // This is the same as English except morekeys_g. + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* morekeys_o */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + /* morekeys_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* morekeys_c */ "\u00E7", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* morekeys_n */ "\u00F1", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* morekeys_s */ "\u00DF", + /* morekeys_y ~ */ + null, null, null, null, null, + /* ~ morekeys_l */ + /* morekeys_g */ "g\'", + }; + + /* Locale th: Thai */ + private static final String[] TEXTS_th = { + /* morekeys_a ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ single_quotes */ + // Label for "switch to alphabetic" key. + // U+0E01: "ก" THAI CHARACTER KO KAI + // U+0E02: "ข" THAI CHARACTER KHO KHAI + // U+0E04: "ค" THAI CHARACTER KHO KHWAI + /* keylabel_to_alpha */ "\u0E01\u0E02\u0E04", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT + /* keyspec_currency */ "\u0E3F", + }; + + /* Locale tl: Tagalog */ + private static final String[] TEXTS_tl = { + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA", + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA", + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B", + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113", + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + /* morekeys_n */ "\u00F1,\u0144", + }; + + /* Locale tr: Turkish */ + private static final String[] TEXTS_tr = { + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + /* morekeys_a */ "\u00E2", + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + /* morekeys_o */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D", + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B", + /* morekeys_e */ null, + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + /* morekeys_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u010D", + /* double_quotes ~ */ + null, null, null, null, + /* ~ keylabel_to_alpha */ + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + /* morekeys_s */ "\u015F,\u00DF,\u015B,\u0161", + /* morekeys_y ~ */ + null, null, null, null, null, + /* ~ morekeys_l */ + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + /* morekeys_g */ "\u011F", + }; + + /* Locale uk: Ukrainian */ + private static final String[] TEXTS_uk = { + /* morekeys_a ~ */ + null, null, null, null, null, null, + /* ~ morekeys_c */ + /* double_quotes */ "!text/double_9qm_lqm", + /* morekeys_n */ null, + /* single_quotes */ "!text/single_9qm_lqm", + // Label for "switch to alphabetic" key. + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + /* keylabel_to_alpha */ "\u0410\u0411\u0412", + /* morekeys_s ~ */ + null, null, null, null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20B4: "₴" HRYVNIA SIGN + /* keyspec_currency */ "\u20B4", + /* morekeys_r ~ */ + null, null, null, null, null, null, null, + /* ~ morekeys_nordic_row2_10 */ + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + /* keyspec_east_slavic_row1_9 */ "\u0449", + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + /* keyspec_east_slavic_row2_2 */ "\u0456", + // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE + /* keyspec_east_slavic_row2_11 */ "\u0454", + // U+0438: "и" CYRILLIC SMALL LETTER I + /* keyspec_east_slavic_row3_5 */ "\u0438", + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + /* morekeys_cyrillic_soft_sign */ "\u044A", + /* morekeys_nordic_row2_11 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, + /* ~ morekeys_w */ + // U+0457: "ї" CYRILLIC SMALL LETTER YI + /* morekeys_east_slavic_row2_2 */ "\u0457", + /* morekeys_cyrillic_u */ null, + /* morekeys_cyrillic_en */ null, + // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN + /* morekeys_cyrillic_ghe */ "\u0491", + }; + + /* Locale vi: Vietnamese */ + private static final String[] TEXTS_vi = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+1EA3: "ả" LATIN SMALL LETTER A WITH HOOK ABOVE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+1EA1: "ạ" LATIN SMALL LETTER A WITH DOT BELOW + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+1EB1: "ằ" LATIN SMALL LETTER A WITH BREVE AND GRAVE + // U+1EAF: "ắ" LATIN SMALL LETTER A WITH BREVE AND ACUTE + // U+1EB3: "ẳ" LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE + // U+1EB5: "ẵ" LATIN SMALL LETTER A WITH BREVE AND TILDE + // U+1EB7: "ặ" LATIN SMALL LETTER A WITH BREVE AND DOT BELOW + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+1EA7: "ầ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE + // U+1EA5: "ấ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE + // U+1EA9: "ẩ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE + // U+1EAB: "ẫ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE + // U+1EAD: "ậ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW + /* morekeys_a */ "\u00E0,\u00E1,\u1EA3,\u00E3,\u1EA1,\u0103,\u1EB1,\u1EAF,\u1EB3,\u1EB5,\u1EB7,\u00E2,\u1EA7,\u1EA5,\u1EA9,\u1EAB,\u1EAD", + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+1ECF: "ỏ" LATIN SMALL LETTER O WITH HOOK ABOVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+1ECD: "ọ" LATIN SMALL LETTER O WITH DOT BELOW + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+1ED3: "ồ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE + // U+1ED1: "ố" LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE + // U+1ED5: "ổ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE + // U+1ED7: "ỗ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE + // U+1ED9: "ộ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW + // U+01A1: "ơ" LATIN SMALL LETTER O WITH HORN + // U+1EDD: "ờ" LATIN SMALL LETTER O WITH HORN AND GRAVE + // U+1EDB: "ớ" LATIN SMALL LETTER O WITH HORN AND ACUTE + // U+1EDF: "ở" LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE + // U+1EE1: "ỡ" LATIN SMALL LETTER O WITH HORN AND TILDE + // U+1EE3: "ợ" LATIN SMALL LETTER O WITH HORN AND DOT BELOW + /* morekeys_o */ "\u00F2,\u00F3,\u1ECF,\u00F5,\u1ECD,\u00F4,\u1ED3,\u1ED1,\u1ED5,\u1ED7,\u1ED9,\u01A1,\u1EDD,\u1EDB,\u1EDF,\u1EE1,\u1EE3", + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+1EE7: "ủ" LATIN SMALL LETTER U WITH HOOK ABOVE + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+1EE5: "ụ" LATIN SMALL LETTER U WITH DOT BELOW + // U+01B0: "ư" LATIN SMALL LETTER U WITH HORN + // U+1EEB: "ừ" LATIN SMALL LETTER U WITH HORN AND GRAVE + // U+1EE9: "ứ" LATIN SMALL LETTER U WITH HORN AND ACUTE + // U+1EED: "ử" LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE + // U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE + // U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW + /* morekeys_u */ "\u00F9,\u00FA,\u1EE7,\u0169,\u1EE5,\u01B0,\u1EEB,\u1EE9,\u1EED,\u1EEF,\u1EF1", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE + // U+1EBD: "ẽ" LATIN SMALL LETTER E WITH TILDE + // U+1EB9: "ẹ" LATIN SMALL LETTER E WITH DOT BELOW + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+1EC1: "ề" LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE + // U+1EBF: "ế" LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE + // U+1EC3: "ể" LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE + // U+1EC5: "ễ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE + // U+1EC7: "ệ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW + /* morekeys_e */ "\u00E8,\u00E9,\u1EBB,\u1EBD,\u1EB9,\u00EA,\u1EC1,\u1EBF,\u1EC3,\u1EC5,\u1EC7", + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+1EC9: "ỉ" LATIN SMALL LETTER I WITH HOOK ABOVE + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW + /* morekeys_i */ "\u00EC,\u00ED,\u1EC9,\u0129,\u1ECB", + /* morekeys_c ~ */ + null, null, null, null, null, null, + /* ~ morekeys_s */ + // U+1EF3: "ỳ" LATIN SMALL LETTER Y WITH GRAVE + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+1EF7: "ỷ" LATIN SMALL LETTER Y WITH HOOK ABOVE + // U+1EF9: "ỹ" LATIN SMALL LETTER Y WITH TILDE + // U+1EF5: "ỵ" LATIN SMALL LETTER Y WITH DOT BELOW + /* morekeys_y */ "\u1EF3,\u00FD,\u1EF7,\u1EF9,\u1EF5", + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + /* morekeys_d */ "\u0111", + /* morekeys_z ~ */ + null, null, null, null, null, null, + /* ~ double_angle_quotes */ + // U+20AB: "₫" DONG SIGN + /* keyspec_currency */ "\u20AB", + }; + + /* Locale zu: Zulu */ + private static final String[] TEXTS_zu = { + // This is the same as English + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + /* morekeys_a */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101", + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + /* morekeys_o */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8,\u014D,\u00F5", + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + /* morekeys_u */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + /* morekeys_e */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113", + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + /* morekeys_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + /* morekeys_c */ "\u00E7", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + /* morekeys_n */ "\u00F1", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + /* morekeys_s */ "\u00DF", + }; + + /* Locale zz: Alphabet */ + private static final String[] TEXTS_zz = { + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + /* morekeys_a */ "\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u0101,\u0103,\u0105,\u00AA", + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+014F: "ŏ" LATIN SMALL LETTER O WITH BREVE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + /* morekeys_o */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u00F8,\u014D,\u014F,\u0151,\u0153,\u00BA", + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + /* morekeys_u */ "\u00F9,\u00FA,\u00FB,\u00FC,\u0169,\u016B,\u016D,\u016F,\u0171,\u0173", + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0115: "ĕ" LATIN SMALL LETTER E WITH BREVE + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + /* morekeys_e */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113,\u0115,\u0117,\u0119,\u011B", + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012D: "ĭ" LATIN SMALL LETTER I WITH BREVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u0129,\u012B,\u012D,\u012F,\u0131,\u0133", + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX + // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + /* morekeys_c */ "\u00E7,\u0107,\u0109,\u010B,\u010D", + /* double_quotes */ null, + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + // U+014B: "ŋ" LATIN SMALL LETTER ENG + /* morekeys_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B", + /* single_quotes */ null, + /* keylabel_to_alpha */ null, + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+017F: "ſ" LATIN SMALL LETTER LONG S + /* morekeys_s */ "\u00DF,\u015B,\u015D,\u015F,\u0161,\u017F", + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + // U+0133: "ij" LATIN SMALL LIGATURE IJ + /* morekeys_y */ "\u00FD,\u0177,\u00FF,\u0133", + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + // U+00F0: "ð" LATIN SMALL LETTER ETH + /* morekeys_d */ "\u010F,\u0111,\u00F0", + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + /* morekeys_z */ "\u017A,\u017C,\u017E", + // U+00FE: "þ" LATIN SMALL LETTER THORN + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE + /* morekeys_t */ "\u00FE,\u0163,\u0165,\u0167", + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + /* morekeys_l */ "\u013A,\u013C,\u013E,\u0140,\u0142", + // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + /* morekeys_g */ "\u011D,\u011F,\u0121,\u0123", + /* single_angle_quotes ~ */ + null, null, null, + /* ~ keyspec_currency */ + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + /* morekeys_r */ "\u0155,\u0157,\u0159", + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + // U+0138: "ĸ" LATIN SMALL LETTER KRA + /* morekeys_k */ "\u0137,\u0138", + /* morekeys_cyrillic_ie ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_question */ + // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX + /* morekeys_h */ "\u0125", + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + /* morekeys_w */ "\u0175", + /* morekeys_east_slavic_row2_2 ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, + /* ~ morekeys_v */ + // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX + /* morekeys_j */ "\u0135", + }; + + private static final Object[] LOCALES_AND_TEXTS = { + // "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */ + "DEFAULT", TEXTS_DEFAULT, /* 168/168 DEFAULT */ + "af" , TEXTS_af, /* 7/ 12 Afrikaans */ + "ar" , TEXTS_ar, /* 55/110 Arabic */ + "az_AZ" , TEXTS_az_AZ, /* 8/ 17 Azerbaijani (Azerbaijan) */ + "be_BY" , TEXTS_be_BY, /* 9/ 32 Belarusian (Belarus) */ + "bg" , TEXTS_bg, /* 2/ 10 Bulgarian */ + "ca" , TEXTS_ca, /* 11/ 95 Catalan */ + "cs" , TEXTS_cs, /* 17/ 21 Czech */ + "da" , TEXTS_da, /* 19/ 33 Danish */ + "de" , TEXTS_de, /* 16/ 62 German */ + "el" , TEXTS_el, /* 1/ 10 Greek */ + "en" , TEXTS_en, /* 8/ 11 English */ + "eo" , TEXTS_eo, /* 26/118 Esperanto */ + "es" , TEXTS_es, /* 8/ 34 Spanish */ + "et_EE" , TEXTS_et_EE, /* 22/ 27 Estonian (Estonia) */ + "eu_ES" , TEXTS_eu_ES, /* 7/ 8 Basque (Spain) */ + "fa" , TEXTS_fa, /* 58/125 Persian */ + "fi" , TEXTS_fi, /* 10/ 33 Finnish */ + "fr" , TEXTS_fr, /* 13/ 62 French */ + "gl_ES" , TEXTS_gl_ES, /* 7/ 8 Gallegan (Spain) */ + "hi" , TEXTS_hi, /* 23/ 55 Hindi */ + "hr" , TEXTS_hr, /* 9/ 19 Croatian */ + "hu" , TEXTS_hu, /* 9/ 19 Hungarian */ + "hy_AM" , TEXTS_hy_AM, /* 8/126 Armenian (Armenia) */ + "is" , TEXTS_is, /* 10/ 15 Icelandic */ + "it" , TEXTS_it, /* 11/ 62 Italian */ + "iw" , TEXTS_iw, /* 20/123 Hebrew */ + "ka_GE" , TEXTS_ka_GE, /* 3/ 10 Georgian (Georgia) */ + "kk" , TEXTS_kk, /* 15/121 Kazakh */ + "km_KH" , TEXTS_km_KH, /* 2/122 Khmer (Cambodia) */ + "ky" , TEXTS_ky, /* 10/ 88 Kirghiz */ + "lo_LA" , TEXTS_lo_LA, /* 2/ 20 Lao (Laos) */ + "lt" , TEXTS_lt, /* 18/ 22 Lithuanian */ + "lv" , TEXTS_lv, /* 18/ 22 Latvian */ + "mk" , TEXTS_mk, /* 9/ 93 Macedonian */ + "mn_MN" , TEXTS_mn_MN, /* 2/ 20 Mongolian (Mongolia) */ + "my_MM" , TEXTS_my_MM, /* 8/104 Burmese (Myanmar) */ + "nb" , TEXTS_nb, /* 11/ 33 Norwegian Bokmål */ + "ne_NP" , TEXTS_ne_NP, /* 23/ 55 Nepali (Nepal) */ + "nl" , TEXTS_nl, /* 9/ 12 Dutch */ + "pl" , TEXTS_pl, /* 10/ 16 Polish */ + "pt" , TEXTS_pt, /* 6/ 6 Portuguese */ + "rm" , TEXTS_rm, /* 1/ 2 Raeto-Romance */ + "ro" , TEXTS_ro, /* 6/ 15 Romanian */ + "ru" , TEXTS_ru, /* 9/ 32 Russian */ + "sk" , TEXTS_sk, /* 20/ 22 Slovak */ + "sl" , TEXTS_sl, /* 8/ 19 Slovenian */ + "sr" , TEXTS_sr, /* 11/ 93 Serbian */ + "sv" , TEXTS_sv, /* 21/ 33 Swedish */ + "sw" , TEXTS_sw, /* 9/ 17 Swahili */ + "th" , TEXTS_th, /* 2/ 20 Thai */ + "tl" , TEXTS_tl, /* 7/ 8 Tagalog */ + "tr" , TEXTS_tr, /* 7/ 17 Turkish */ + "uk" , TEXTS_uk, /* 11/ 87 Ukrainian */ + "vi" , TEXTS_vi, /* 8/ 20 Vietnamese */ + "zu" , TEXTS_zu, /* 8/ 11 Zulu */ + "zz" , TEXTS_zz, /* 19/112 Alphabet */ + }; + + static { + for (int index = 0; index < NAMES.length; index++) { + sNameToIndexesMap.put(NAMES[index], index); + } + + for (int i = 0; i < LOCALES_AND_TEXTS.length; i += 2) { + final String locale = (String)LOCALES_AND_TEXTS[i]; + final String[] textsTable = (String[])LOCALES_AND_TEXTS[i + 1]; + sLocaleToTextsTableMap.put(locale, textsTable); + sTextsTableToLocaleMap.put(textsTable, locale); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java new file mode 100644 index 000000000..6400a2440 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 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.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.Collections; +import java.util.List; + +/** + * This class determines that the language name on the spacebar should be displayed in what format. + */ +public final class LanguageOnSpacebarHelper { + public static final int FORMAT_TYPE_NONE = 0; + public static final int FORMAT_TYPE_LANGUAGE_ONLY = 1; + public static final int FORMAT_TYPE_FULL_LOCALE = 2; + + private List<InputMethodSubtype> mEnabledSubtypes = Collections.emptyList(); + private boolean mIsSystemLanguageSameAsInputLanguage; + + public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) { + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + return FORMAT_TYPE_FULL_LOCALE; + } + // Only this subtype is enabled and equals to the system locale. + if (mEnabledSubtypes.size() < 2 && mIsSystemLanguageSameAsInputLanguage) { + return FORMAT_TYPE_NONE; + } + final String keyboardLanguage = SubtypeLocaleUtils.getSubtypeLocale(subtype).getLanguage(); + final String keyboardLayout = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype); + int sameLanguageAndLayoutCount = 0; + for (final InputMethodSubtype ims : mEnabledSubtypes) { + final String language = SubtypeLocaleUtils.getSubtypeLocale(ims).getLanguage(); + if (keyboardLanguage.equals(language) && keyboardLayout.equals( + SubtypeLocaleUtils.getKeyboardLayoutSetName(ims))) { + sameLanguageAndLayoutCount++; + } + } + // Display full locale name only when there are multiple subtypes that have the same + // locale and keyboard layout. Otherwise displaying language name is enough. + return sameLanguageAndLayoutCount > 1 ? FORMAT_TYPE_FULL_LOCALE + : FORMAT_TYPE_LANGUAGE_ONLY; + } + + public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) { + mEnabledSubtypes = enabledSubtypes; + } + + public void updateIsSystemLanguageSameAsInputLanguage(final boolean isSame) { + mIsSystemLanguageSameAsInputLanguage = isSame; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java index 110936f8f..56ef4767f 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java @@ -18,23 +18,42 @@ package com.android.inputmethod.keyboard.internal; import android.text.TextUtils; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.StringUtils; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Locale; +/** + * The more key specification object. The more keys are an array of {@link MoreKeySpec}. + * + * The more keys specification is comma separated "key specification" each of which represents one + * "more key". + * The key specification might have label or string resource reference in it. These references are + * expanded before parsing comma. + * Special character, comma ',' backslash '\' can be escaped by '\' character. + * Note that the '\' is also parsed by XML parser and {@link MoreKeySpec#splitKeySpecs(String)} + * as well. + */ +// TODO: Should extend the key specification object. public final class MoreKeySpec { public final int mCode; public final String mLabel; public final String mOutputText; public final int mIconId; - public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, final Locale locale, - final KeyboardCodesSet codesSet) { - mLabel = KeySpecParser.toUpperCaseOfStringForLocale( + public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, final Locale locale) { + if (TextUtils.isEmpty(moreKeySpec)) { + throw new KeySpecParser.KeySpecParserError("Empty more key spec"); + } + mLabel = StringUtils.toUpperCaseOfStringForLocale( KeySpecParser.getLabel(moreKeySpec), needsToUpperCase, locale); - final int code = KeySpecParser.toUpperCaseOfCodeForLocale( - KeySpecParser.getCode(moreKeySpec, codesSet), needsToUpperCase, locale); + final int code = StringUtils.toUpperCaseOfCodeForLocale( + KeySpecParser.getCode(moreKeySpec), needsToUpperCase, locale); if (code == Constants.CODE_UNSPECIFIED) { // Some letter, for example German Eszett (U+00DF: "ß"), has multiple characters // upper case representation ("SS"). @@ -42,12 +61,19 @@ public final class MoreKeySpec { mOutputText = mLabel; } else { mCode = code; - mOutputText = KeySpecParser.toUpperCaseOfStringForLocale( + mOutputText = StringUtils.toUpperCaseOfStringForLocale( KeySpecParser.getOutputText(moreKeySpec), needsToUpperCase, locale); } mIconId = KeySpecParser.getIconId(moreKeySpec); } + public Key buildKey(final int x, final int y, final int labelFlags, + final KeyboardParams params) { + return new Key(mLabel, mIconId, mCode, mOutputText, null /* hintLabel */, labelFlags, + Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultKeyWidth, params.mDefaultRowHeight, + params.mHorizontalGap, params.mVerticalGap); + } + @Override public int hashCode() { int hashCode = 1; @@ -74,7 +100,7 @@ public final class MoreKeySpec { @Override public String toString() { final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel - : KeySpecParser.PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId)); + : KeyboardIconsSet.PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId)); final String output = (mCode == Constants.CODE_OUTPUT_TEXT ? mOutputText : Constants.printableCode(mCode)); if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) { @@ -83,4 +109,196 @@ public final class MoreKeySpec { return label + "|" + output; } } + + private static final boolean DEBUG = LatinImeLogger.sDBG; + // Constants for parsing. + private static final char COMMA = Constants.CODE_COMMA; + private static final char BACKSLASH = Constants.CODE_BACKSLASH; + private static final String ADDITIONAL_MORE_KEY_MARKER = + StringUtils.newSingleCodePointString(Constants.CODE_PERCENT); + + /** + * Split the text containing multiple key specifications separated by commas into an array of + * key specifications. + * A key specification can contain a character escaped by the backslash character, including a + * comma character. + * Note that an empty key specification will be eliminated from the result array. + * + * @param text the text containing multiple key specifications. + * @return an array of key specification text. Null if the specified <code>text</code> is empty + * or has no key specifications. + */ + public static String[] splitKeySpecs(final String text) { + if (TextUtils.isEmpty(text)) { + return null; + } + final int size = text.length(); + // Optimization for one-letter key specification. + if (size == 1) { + return text.charAt(0) == COMMA ? null : new String[] { text }; + } + + ArrayList<String> list = null; + int start = 0; + // The characters in question in this loop are COMMA and BACKSLASH. These characters never + // match any high or low surrogate character. So it is OK to iterate through with char + // index. + 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 = CollectionUtils.newArrayList(); + } + list.add(text.substring(start, pos)); + } + // Skip comma + start = pos + 1; + } else if (c == BACKSLASH) { + // 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; + } + if (remain != null) { + list.add(remain); + } + return list.toArray(new String[list.size()]); + } + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private static String[] filterOutEmptyString(final String[] array) { + if (array == null) { + return EMPTY_STRING_ARRAY; + } + ArrayList<String> out = null; + for (int i = 0; i < array.length; i++) { + final String entry = array[i]; + if (TextUtils.isEmpty(entry)) { + if (out == null) { + out = CollectionUtils.arrayAsList(array, 0, i); + } + } else if (out != null) { + out.add(entry); + } + } + if (out == null) { + return array; + } + return out.toArray(new String[out.size()]); + } + + public static String[] insertAdditionalMoreKeys(final String[] moreKeySpecs, + final String[] additionalMoreKeySpecs) { + final String[] moreKeys = filterOutEmptyString(moreKeySpecs); + final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs); + final int moreKeysCount = moreKeys.length; + final int additionalCount = additionalMoreKeys.length; + 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 = CollectionUtils.arrayAsList(moreKeys, 0, moreKeyIndex); + } + } + } 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 = CollectionUtils.arrayAsList(additionalMoreKeys, additionalIndex, additionalCount); + 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 = CollectionUtils.arrayAsList(moreKeys, 0, moreKeysCount); + for (int i = additionalIndex; i < additionalCount; i++) { + out.add(additionalMoreKeys[additionalIndex]); + } + } + if (out == null && moreKeysCount > 0) { + return moreKeys; + } else if (out != null && out.size() > 0) { + return out.toArray(new String[out.size()]); + } else { + return null; + } + } + + public static int getIntValue(final String[] moreKeys, final String key, + final int defaultValue) { + if (moreKeys == null) { + return defaultValue; + } + final int keyLen = key.length(); + boolean foundValue = false; + int value = defaultValue; + for (int i = 0; i < moreKeys.length; i++) { + final String moreKeySpec = moreKeys[i]; + if (moreKeySpec == null || !moreKeySpec.startsWith(key)) { + continue; + } + moreKeys[i] = null; + try { + if (!foundValue) { + value = Integer.parseInt(moreKeySpec.substring(keyLen)); + foundValue = true; + } + } catch (NumberFormatException e) { + throw new RuntimeException( + "integer should follow after " + key + ": " + moreKeySpec); + } + } + return value; + } + + public static boolean getBooleanValue(final String[] moreKeys, final String key) { + if (moreKeys == null) { + return false; + } + boolean value = false; + for (int i = 0; i < moreKeys.length; i++) { + final String moreKeySpec = moreKeys[i]; + if (moreKeySpec == null || !moreKeySpec.equals(key)) { + continue; + } + moreKeys[i] = null; + value = true; + } + return value; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java index a0935b985..3a9aa81a3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java +++ b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java @@ -20,18 +20,19 @@ import android.util.Log; import android.view.MotionEvent; import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler; import com.android.inputmethod.latin.utils.CoordinateUtils; public final class NonDistinctMultitouchHelper { private static final String TAG = NonDistinctMultitouchHelper.class.getSimpleName(); + private static final int MAIN_POINTER_TRACKER_ID = 0; private int mOldPointerCount = 1; private Key mOldKey; private int[] mLastCoords = CoordinateUtils.newInstance(); - public void processMotionEvent(final MotionEvent me, final KeyEventHandler keyEventHandler) { + public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) { final int pointerCount = me.getPointerCount(); final int oldPointerCount = mOldPointerCount; mOldPointerCount = pointerCount; @@ -41,8 +42,9 @@ public final class NonDistinctMultitouchHelper { return; } - // Use only main (id=0) pointer tracker. - final PointerTracker mainTracker = PointerTracker.getPointerTracker(0, keyEventHandler); + // Use only main pointer tracker. + final PointerTracker mainTracker = PointerTracker.getPointerTracker( + MAIN_POINTER_TRACKER_ID); final int action = me.getActionMasked(); final int index = me.getActionIndex(); final long eventTime = me.getEventTime(); @@ -51,12 +53,12 @@ public final class NonDistinctMultitouchHelper { // In single-touch. if (oldPointerCount == 1 && pointerCount == 1) { if (me.getPointerId(index) == mainTracker.mPointerId) { - mainTracker.processMotionEvent(me, keyEventHandler); + mainTracker.processMotionEvent(me, keyDetector); return; } // Inject a copied event. injectMotionEvent(action, me.getX(index), me.getY(index), downTime, eventTime, - mainTracker, keyEventHandler); + mainTracker, keyDetector); return; } @@ -70,7 +72,7 @@ public final class NonDistinctMultitouchHelper { mOldKey = mainTracker.getKeyOn(x, y); // Inject an artifact up event for the old key. injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime, - mainTracker, keyEventHandler); + mainTracker, keyDetector); return; } @@ -85,11 +87,11 @@ public final class NonDistinctMultitouchHelper { // Inject an artifact down event for the new key. // An artifact up event for the new key will usually be injected as a single-touch. injectMotionEvent(MotionEvent.ACTION_DOWN, x, y, downTime, eventTime, - mainTracker, keyEventHandler); + mainTracker, keyDetector); if (action == MotionEvent.ACTION_UP) { // Inject an artifact up event for the new key also. injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime, - mainTracker, keyEventHandler); + mainTracker, keyDetector); } } return; @@ -101,11 +103,11 @@ public final class NonDistinctMultitouchHelper { private static void injectMotionEvent(final int action, final float x, final float y, final long downTime, final long eventTime, final PointerTracker tracker, - final KeyEventHandler handler) { + final KeyDetector keyDetector) { final MotionEvent me = MotionEvent.obtain( downTime, eventTime, action, x, y, 0 /* metaState */); try { - tracker.processMotionEvent(me, handler); + tracker.processMotionEvent(me, keyDetector); } finally { me.recycle(); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java index 7ee45e8f6..5ac34188c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java @@ -28,7 +28,7 @@ public final class PointerTrackerQueue { public interface Element { public boolean isModifier(); - public boolean isInSlidingKeyInput(); + public boolean isInDraggingFinger(); public void onPhantomUpEvent(long eventTime); public void cancelTrackingForAction(); } @@ -193,13 +193,13 @@ public final class PointerTrackerQueue { } } - public boolean isAnyInSlidingKeyInput() { + public boolean isAnyInDraggingFinger() { synchronized (mExpandableArrayOfActivePointers) { final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; final int arraySize = mArraySize; for (int index = 0; index < arraySize; index++) { final Element element = expandableArray.get(index); - if (element.isInSlidingKeyInput()) { + if (element.isInDraggingFinger()) { return true; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java b/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java deleted file mode 100644 index d1ccdc7b5..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2013 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.util.AttributeSet; -import android.widget.ScrollView; - -/** - * This is an extended {@link ScrollView} that can notify - * {@link ScrollView#onScrollChanged(int,int,int,int} and - * {@link ScrollView#onOverScrolled(int,int,int,int)} to a content view. - */ -public class ScrollViewWithNotifier extends ScrollView { - private ScrollListener mScrollListener = EMPTY_LISTER; - - public interface ScrollListener { - public void notifyScrollChanged(int scrollX, int scrollY, int oldX, int oldY); - public void notifyOverScrolled(int scrollX, int scrollY, boolean clampedX, - boolean clampedY); - } - - private static final ScrollListener EMPTY_LISTER = new ScrollListener() { - @Override - public void notifyScrollChanged(int scrollX, int scrollY, int oldX, int oldY) {} - @Override - public void notifyOverScrolled(int scrollX, int scrollY, boolean clampedX, - boolean clampedY) {} - }; - - public ScrollViewWithNotifier(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onScrollChanged(final int scrollX, final int scrollY, final int oldX, - final int oldY) { - super.onScrollChanged(scrollX, scrollY, oldX, oldY); - mScrollListener.notifyScrollChanged(scrollX, scrollY, oldX, oldY); - } - - @Override - protected void onOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, - final boolean clampedY) { - super.onOverScrolled(scrollX, scrollY, clampedX, clampedY); - mScrollListener.notifyOverScrolled(scrollX, scrollY, clampedX, clampedY); - } - - public void setScrollListener(final ScrollListener listener) { - mScrollListener = listener; - } -} diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java index 2787ebfb9..76cb89160 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java +++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java @@ -29,7 +29,7 @@ import com.android.inputmethod.latin.utils.CoordinateUtils; /** * Draw rubber band preview graphics during sliding key input. */ -public final class SlidingKeyInputPreview extends AbstractDrawingPreview { +public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview { private final float mPreviewBodyRadius; private boolean mShowsSlidingKeyInputPreview; @@ -40,7 +40,8 @@ public final class SlidingKeyInputPreview extends AbstractDrawingPreview { private final RoundedLine mRoundedLine = new RoundedLine(); private final Paint mPaint = new Paint(); - public SlidingKeyInputPreview(final View drawingView, final TypedArray mainKeyboardViewAttr) { + public SlidingKeyInputDrawingPreview(final View drawingView, + final TypedArray mainKeyboardViewAttr) { super(drawingView); final int previewColor = mainKeyboardViewAttr.getColor( R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0); @@ -61,6 +62,11 @@ public final class SlidingKeyInputPreview extends AbstractDrawingPreview { mPaint.setColor(previewColor); } + @Override + public void onDeallocateMemory() { + // Nothing to do here. + } + public void dismissSlidingKeyInputPreview() { mShowsSlidingKeyInputPreview = false; getDrawingView().invalidate(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java new file mode 100644 index 000000000..ec7b9b024 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2013 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.os.Message; +import android.os.SystemClock; +import android.view.ViewConfiguration; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; +import com.android.inputmethod.keyboard.internal.TimerHandler.Callbacks; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; + +// TODO: Separate this class into KeyTimerHandler and BatchInputTimerHandler or so. +public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> implements TimerProxy { + public interface Callbacks { + public void startWhileTypingFadeinAnimation(); + public void startWhileTypingFadeoutAnimation(); + public void onLongPress(PointerTracker tracker); + } + + private static final int MSG_TYPING_STATE_EXPIRED = 0; + private static final int MSG_REPEAT_KEY = 1; + private static final int MSG_LONGPRESS_KEY = 2; + private static final int MSG_LONGPRESS_SHIFT_KEY = 3; + private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 4; + private static final int MSG_UPDATE_BATCH_INPUT = 5; + + private final int mIgnoreAltCodeKeyTimeout; + private final int mGestureRecognitionUpdateTime; + + public TimerHandler(final Callbacks ownerInstance, final int ignoreAltCodeKeyTimeout, + final int gestureRecognitionUpdateTime) { + super(ownerInstance); + mIgnoreAltCodeKeyTimeout = ignoreAltCodeKeyTimeout; + mGestureRecognitionUpdateTime = gestureRecognitionUpdateTime; + } + + @Override + public void handleMessage(final Message msg) { + final Callbacks callbacks = getOwnerInstance(); + if (callbacks == null) { + return; + } + final PointerTracker tracker = (PointerTracker) msg.obj; + switch (msg.what) { + case MSG_TYPING_STATE_EXPIRED: + callbacks.startWhileTypingFadeinAnimation(); + break; + case MSG_REPEAT_KEY: + tracker.onKeyRepeat(msg.arg1 /* code */, msg.arg2 /* repeatCount */); + break; + case MSG_LONGPRESS_KEY: + case MSG_LONGPRESS_SHIFT_KEY: + cancelLongPressTimers(); + callbacks.onLongPress(tracker); + break; + case MSG_UPDATE_BATCH_INPUT: + tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); + startUpdateBatchInputTimer(tracker); + break; + } + } + + @Override + public void startKeyRepeatTimerOf(final PointerTracker tracker, final int repeatCount, + final int delay) { + final Key key = tracker.getKey(); + if (key == null || delay == 0) { + return; + } + sendMessageDelayed( + obtainMessage(MSG_REPEAT_KEY, key.getCode(), repeatCount, tracker), delay); + } + + private void cancelKeyRepeatTimerOf(final PointerTracker tracker) { + removeMessages(MSG_REPEAT_KEY, tracker); + } + + public void cancelKeyRepeatTimers() { + removeMessages(MSG_REPEAT_KEY); + } + + // TODO: Suppress layout changes in key repeat mode + public boolean isInKeyRepeat() { + return hasMessages(MSG_REPEAT_KEY); + } + + @Override + public void startLongPressTimerOf(final PointerTracker tracker, final int delay) { + final Key key = tracker.getKey(); + if (key == null) { + return; + } + // Use a separate message id for long pressing shift key, because long press shift key + // timers should be canceled when other key is pressed. + final int messageId = (key.getCode() == Constants.CODE_SHIFT) + ? MSG_LONGPRESS_SHIFT_KEY : MSG_LONGPRESS_KEY; + sendMessageDelayed(obtainMessage(messageId, tracker), delay); + } + + @Override + public void cancelLongPressTimerOf(final PointerTracker tracker) { + removeMessages(MSG_LONGPRESS_KEY, tracker); + removeMessages(MSG_LONGPRESS_SHIFT_KEY, tracker); + } + + @Override + public void cancelLongPressShiftKeyTimers() { + removeMessages(MSG_LONGPRESS_SHIFT_KEY); + } + + public void cancelLongPressTimers() { + removeMessages(MSG_LONGPRESS_KEY); + removeMessages(MSG_LONGPRESS_SHIFT_KEY); + } + + @Override + public void startTypingStateTimer(final Key typedKey) { + if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { + return; + } + + final boolean isTyping = isTypingState(); + removeMessages(MSG_TYPING_STATE_EXPIRED); + final Callbacks callbacks = getOwnerInstance(); + if (callbacks == null) { + return; + } + + // When user hits the space or the enter key, just cancel the while-typing timer. + final int typedCode = typedKey.getCode(); + if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { + if (isTyping) { + callbacks.startWhileTypingFadeinAnimation(); + } + return; + } + + sendMessageDelayed( + obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); + if (isTyping) { + return; + } + callbacks.startWhileTypingFadeoutAnimation(); + } + + @Override + public boolean isTypingState() { + return hasMessages(MSG_TYPING_STATE_EXPIRED); + } + + @Override + public void startDoubleTapShiftKeyTimer() { + sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY), + ViewConfiguration.getDoubleTapTimeout()); + } + + @Override + public void cancelDoubleTapShiftKeyTimer() { + removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY); + } + + @Override + public boolean isInDoubleTapShiftKeyTimeout() { + return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY); + } + + @Override + public void cancelKeyTimersOf(final PointerTracker tracker) { + cancelKeyRepeatTimerOf(tracker); + cancelLongPressTimerOf(tracker); + } + + public void cancelAllKeyTimers() { + cancelKeyRepeatTimers(); + cancelLongPressTimers(); + } + + @Override + public void startUpdateBatchInputTimer(final PointerTracker tracker) { + if (mGestureRecognitionUpdateTime <= 0) { + return; + } + removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); + sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), + mGestureRecognitionUpdateTime); + } + + @Override + public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { + removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); + } + + @Override + public void cancelAllUpdateBatchInputTimers() { + removeMessages(MSG_UPDATE_BATCH_INPUT); + } + + public void cancelAllMessages() { + cancelAllKeyTimers(); + cancelAllUpdateBatchInputTimers(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/TypingTimeRecorder.java b/java/src/com/android/inputmethod/keyboard/internal/TypingTimeRecorder.java new file mode 100644 index 000000000..9593f715c --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/TypingTimeRecorder.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 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 final class TypingTimeRecorder { + private final int mStaticTimeThresholdAfterFastTyping; // msec + private final int mSuppressKeyPreviewAfterBatchInputDuration; + private long mLastTypingTime; + private long mLastLetterTypingTime; + private long mLastBatchInputTime; + + public TypingTimeRecorder(final int staticTimeThresholdAfterFastTyping, + final int suppressKeyPreviewAfterBatchInputDuration) { + mStaticTimeThresholdAfterFastTyping = staticTimeThresholdAfterFastTyping; + mSuppressKeyPreviewAfterBatchInputDuration = suppressKeyPreviewAfterBatchInputDuration; + } + + public boolean isInFastTyping(final long eventTime) { + final long elapsedTimeSinceLastLetterTyping = eventTime - mLastLetterTypingTime; + return elapsedTimeSinceLastLetterTyping < mStaticTimeThresholdAfterFastTyping; + } + + private boolean wasLastInputTyping() { + return mLastTypingTime >= mLastBatchInputTime; + } + + public void onCodeInput(final int code, final long eventTime) { + // Record the letter typing time when + // 1. Letter keys are typed successively without any batch input in between. + // 2. A letter key is typed within the threshold time since the last any key typing. + // 3. A non-letter key is typed within the threshold time since the last letter key typing. + if (Character.isLetter(code)) { + if (wasLastInputTyping() + || eventTime - mLastTypingTime < mStaticTimeThresholdAfterFastTyping) { + mLastLetterTypingTime = eventTime; + } + } else { + if (eventTime - mLastLetterTypingTime < mStaticTimeThresholdAfterFastTyping) { + // This non-letter typing should be treated as a part of fast typing. + mLastLetterTypingTime = eventTime; + } + } + mLastTypingTime = eventTime; + } + + public void onEndBatchInput(final long eventTime) { + mLastBatchInputTime = eventTime; + } + + public long getLastLetterTypingTime() { + return mLastLetterTypingTime; + } + + public boolean needsToSuppressKeyPreviewPopup(final long eventTime) { + return !wasLastInputTyping() + && eventTime - mLastBatchInputTime < mSuppressKeyPreviewAfterBatchInputDuration; + } +} diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java deleted file mode 100644 index 463d09344..000000000 --- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2013 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.util.Log; - -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; - -import java.io.File; -import java.io.IOException; -import java.util.Map; - -// TODO: Quit extending Dictionary after implementing dynamic binary dictionary. -abstract public class AbstractDictionaryWriter extends Dictionary { - /** Used for Log actions from this class */ - private static final String TAG = AbstractDictionaryWriter.class.getSimpleName(); - - private final Context mContext; - - public AbstractDictionaryWriter(final Context context, final String dictType) { - super(dictType); - mContext = context; - } - - abstract public void clear(); - - /** - * Add a unigram with an optional shortcut to the dictionary. - * @param word The word to add. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this unigram. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored - * if shortcutTarget is null. - * @param isNotAWord true if this is not a word, i.e. shortcut only. - */ - abstract public void addUnigramWord(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq, final boolean isNotAWord); - - // TODO: Remove lastModifiedTime after making binary dictionary support forgetting curve. - abstract public void addBigramWords(final String word0, final String word1, - final int frequency, final boolean isValid, - final long lastModifiedTime); - - abstract public void removeBigramWords(final String word0, final String word1); - - abstract protected void writeDictionary(final DictEncoder dictEncoder, - final Map<String, String> attributeMap) throws IOException, UnsupportedFormatException; - - public void write(final String fileName, final Map<String, String> attributeMap) { - final String tempFileName = fileName + ".temp"; - final File file = new File(mContext.getFilesDir(), fileName); - final File tempFile = new File(mContext.getFilesDir(), tempFileName); - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(tempFile); - writeDictionary(dictEncoder, attributeMap); - tempFile.renameTo(file); - } catch (IOException e) { - Log.e(TAG, "IO exception while writing file", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Unsupported format", e); - } - } -} diff --git a/java/src/com/android/inputmethod/latin/AssetFileAddress.java b/java/src/com/android/inputmethod/latin/AssetFileAddress.java index 875192554..fd6c24dfe 100644 --- a/java/src/com/android/inputmethod/latin/AssetFileAddress.java +++ b/java/src/com/android/inputmethod/latin/AssetFileAddress.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.utils.FileUtils; + import java.io.File; /** @@ -52,4 +54,12 @@ public final class AssetFileAddress { if (!f.isFile()) return null; return new AssetFileAddress(filename, offset, length); } + + public boolean pointsToPhysicalFile() { + return 0 == mOffset; + } + + public void deleteUnderlyingFile() { + FileUtils.deleteRecursively(new File(mFilename)); + } } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index fd296988e..b88509fde 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -17,19 +17,29 @@ package com.android.inputmethod.latin; import android.text.TextUtils; +import android.util.Log; import android.util.SparseArray; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.settings.NativeSuggestOptions; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; +import com.android.inputmethod.latin.utils.LanguageModelParam; import com.android.inputmethod.latin.utils.StringUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -57,17 +67,40 @@ public final class BinaryDictionary extends Dictionary { @UsedForTesting public static final String MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; + public static final int NOT_A_VALID_TIMESTAMP = -1; + + // Format to get unigram flags from native side via getWordPropertyNative(). + private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 4; + private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0; + private static final int FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX = 1; + private static final int FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX = 2; + private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; + + // Format to get probability and historical info from native side via getWordPropertyNative(). + public static final int FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT = 4; + public static final int FORMAT_WORD_PROPERTY_PROBABILITY_INDEX = 0; + public static final int FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX = 1; + public static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 2; + public static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 3; + + public static final String DICT_FILE_NAME_SUFFIX_FOR_MIGRATION = ".migrate"; + private long mNativeDict; private final Locale mLocale; private final long mDictSize; private final String mDictFilePath; + private final boolean mIsUpdatable; + private boolean mHasUpdated; + private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; + private final int[] mOutputSuggestionCount = new int[1]; private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS]; private final int[] mOutputScores = new int[MAX_RESULTS]; private final int[] mOutputTypes = new int[MAX_RESULTS]; // Only one result is ever used private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; + private final float[] mInputOutputLanguageWeight = new float[1]; private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); @@ -91,8 +124,7 @@ public final class BinaryDictionary extends Dictionary { } /** - * Constructor for the binary dictionary. This is supposed to be called from the - * dictionary factory. + * Constructs binary dictionary using existing dictionary file. * @param filename the name of the file to read through native code. * @param offset the offset of the dictionary data within the file. * @param length the length of the binary data. @@ -107,100 +139,188 @@ public final class BinaryDictionary extends Dictionary { mLocale = locale; mDictSize = length; mDictFilePath = filename; + mIsUpdatable = isUpdatable; + mHasUpdated = false; mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); loadDictionary(filename, offset, length, isUpdatable); } + /** + * Constructs binary dictionary on memory. + * @param filename the name of the file used to flush. + * @param useFullEditDistance whether to use the full edit distance in suggestions + * @param dictType the dictionary type, as a human-readable string + * @param formatVersion the format version of the dictionary + * @param attributeMap the attributes of the dictionary + */ + @UsedForTesting + public BinaryDictionary(final String filename, final boolean useFullEditDistance, + final Locale locale, final String dictType, final long formatVersion, + final Map<String, String> attributeMap) { + super(dictType); + mLocale = locale; + mDictSize = 0; + mDictFilePath = filename; + // On memory dictionary is always updatable. + mIsUpdatable = true; + mHasUpdated = false; + mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); + final String[] keyArray = new String[attributeMap.size()]; + final String[] valueArray = new String[attributeMap.size()]; + int index = 0; + for (final String key : attributeMap.keySet()) { + keyArray[index] = key; + valueArray[index] = attributeMap.get(key); + index++; + } + mNativeDict = createOnMemoryNative(formatVersion, locale.toString(), keyArray, valueArray); + } + + static { JniUtils.loadNativeLibrary(); } - private static native boolean createEmptyDictFileNative(String filePath, long dictVersion, - String[] attributeKeyStringArray, String[] attributeValueStringArray); private static native long openNative(String sourceDir, long dictOffset, long dictSize, boolean isUpdatable); + private static native long createOnMemoryNative(long formatVersion, + String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); + private static native void getHeaderInfoNative(long dict, int[] outHeaderSize, + int[] outFormatVersion, ArrayList<int[]> outAttributeKeys, + ArrayList<int[]> outAttributeValues); private static native void flushNative(long dict, String filePath); private static native boolean needsToRunGCNative(long dict, boolean mindsBlockByGC); private static native void flushWithGCNative(long dict, String filePath); private static native void closeNative(long dict); + private static native int getFormatVersionNative(long dict); private static native int getProbabilityNative(long dict, int[] word); private static native int getBigramProbabilityNative(long dict, int[] word0, int[] word1); - private static native int getSuggestionsNative(long dict, long proximityInfo, + private static native void getWordPropertyNative(long dict, int[] word, + int[] outCodePoints, boolean[] outFlags, int[] outProbabilityInfo, + ArrayList<int[]> outBigramTargets, ArrayList<int[]> outBigramProbabilityInfo, + ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities); + private static native int getNextWordNative(long dict, int token, int[] outCodePoints); + private static native void getSuggestionsNative(long dict, long proximityInfo, long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times, - int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint, - int[] suggestOptions, int[] prevWordCodePointArray, - int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes, - int[] outputAutoCommitFirstWordConfidence); - private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); - private static native int editDistanceNative(int[] before, int[] after); - private static native void addUnigramWordNative(long dict, int[] word, int probability); + int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions, + int[] prevWordCodePointArray, int[] outputSuggestionCount, int[] outputCodePoints, + int[] outputScores, int[] outputIndices, int[] outputTypes, + int[] outputAutoCommitFirstWordConfidence, float[] inOutLanguageWeight); + private static native void addUnigramWordNative(long dict, int[] word, int probability, + int[] shortcutTarget, int shortcutProbability, boolean isNotAWord, + boolean isBlacklisted, int timestamp); private static native void addBigramWordsNative(long dict, int[] word0, int[] word1, - int probability); + int probability, int timestamp); private static native void removeBigramWordsNative(long dict, int[] word0, int[] word1); + private static native int addMultipleDictionaryEntriesNative(long dict, + LanguageModelParam[] languageModelParams, int startIndex); private static native int calculateProbabilityNative(long dict, int unigramProbability, int bigramProbability); private static native String getPropertyNative(long dict, String query); - - @UsedForTesting - public static boolean createEmptyDictFile(final String filePath, final long dictVersion, - final Map<String, String> attributeMap) { - final String[] keyArray = new String[attributeMap.size()]; - final String[] valueArray = new String[attributeMap.size()]; - int index = 0; - for (final String key : attributeMap.keySet()) { - keyArray[index] = key; - valueArray[index] = attributeMap.get(key); - index++; - } - return createEmptyDictFileNative(filePath, dictVersion, keyArray, valueArray); - } + private static native boolean isCorruptedNative(long dict); // TODO: Move native dict into session private final void loadDictionary(final String path, final long startOffset, final long length, final boolean isUpdatable) { + mHasUpdated = false; mNativeDict = openNative(path, startOffset, length, isUpdatable); } + // TODO: Check isCorrupted() for main dictionaries. + public boolean isCorrupted() { + if (!isValidDictionary()) { + return false; + } + if (!isCorruptedNative(mNativeDict)) { + return false; + } + // TODO: Record the corruption. + Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted."); + Log.e(TAG, "locale: " + mLocale); + Log.e(TAG, "dict size: " + mDictSize); + Log.e(TAG, "updatable: " + mIsUpdatable); + return true; + } + + public DictionaryHeader getHeader() throws UnsupportedFormatException { + if (mNativeDict == 0) { + return null; + } + final int[] outHeaderSize = new int[1]; + final int[] outFormatVersion = new int[1]; + final ArrayList<int[]> outAttributeKeys = CollectionUtils.newArrayList(); + final ArrayList<int[]> outAttributeValues = CollectionUtils.newArrayList(); + getHeaderInfoNative(mNativeDict, outHeaderSize, outFormatVersion, outAttributeKeys, + outAttributeValues); + final HashMap<String, String> attributes = new HashMap<String, String>(); + for (int i = 0; i < outAttributeKeys.size(); i++) { + final String attributeKey = StringUtils.getStringFromNullTerminatedCodePointArray( + outAttributeKeys.get(i)); + final String attributeValue = StringUtils.getStringFromNullTerminatedCodePointArray( + outAttributeValues.get(i)); + attributes.put(attributeKey, attributeValue); + } + final boolean hasHistoricalInfo = DictionaryHeader.ATTRIBUTE_VALUE_TRUE.equals( + attributes.get(DictionaryHeader.HAS_HISTORICAL_INFO_KEY)); + return new DictionaryHeader(outHeaderSize[0], new DictionaryOptions(attributes), + new FormatSpec.FormatOptions(outFormatVersion[0], hasHistoricalInfo)); + } + + @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, 0 /* sessionId */); + additionalFeaturesOptions, 0 /* sessionId */, inOutLanguageWeight); } @Override public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, - final int sessionId) { - if (!isValidDictionary()) return null; + final int sessionId, final float[] inOutLanguageWeight) { + if (!isValidDictionary()) { + return null; + } Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE); // TODO: toLowerCase in the native code final int[] prevWordCodePointArray = (null == prevWord) ? null : StringUtils.toCodePointArray(prevWord); - final int composerSize = composer.size(); - + final InputPointers inputPointers = composer.getInputPointers(); final boolean isGesture = composer.isBatchMode(); - if (composerSize <= 1 || !isGesture) { - if (composerSize > MAX_WORD_LENGTH - 1) return null; - for (int i = 0; i < composerSize; i++) { - mInputCodePoints[i] = composer.getCodeAt(i); + final int inputSize; + if (!isGesture) { + inputSize = composer.copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount( + mInputCodePoints); + if (inputSize < 0) { + return null; } + } else { + inputSize = inputPointers.getPointerSize(); } - final InputPointers ips = composer.getInputPointers(); - final int inputSize = isGesture ? ips.getPointerSize() : composerSize; mNativeSuggestOptions.setIsGesture(isGesture); mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions); + if (inOutLanguageWeight != null) { + mInputOutputLanguageWeight[0] = inOutLanguageWeight[0]; + } else { + mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT; + } // proximityInfo and/or prevWordForBigrams may not be null. - final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), - getTraverseSession(sessionId).getSession(), ips.getXCoordinates(), - ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints, - inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(), - prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices, - mOutputTypes, mOutputAutoCommitFirstWordConfidence); + getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(), + inputPointers.getYCoordinates(), inputPointers.getTimes(), + inputPointers.getPointerIds(), mInputCodePoints, inputSize, + mNativeSuggestOptions.getOptions(), prevWordCodePointArray, mOutputSuggestionCount, + mOutputCodePoints, mOutputScores, mSpaceIndices, mOutputTypes, + mOutputAutoCommitFirstWordConfidence, mInputOutputLanguageWeight); + if (inOutLanguageWeight != null) { + inOutLanguageWeight[0] = mInputOutputLanguageWeight[0]; + } + final int count = mOutputSuggestionCount[0]; final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); for (int j = 0; j < count; ++j) { final int start = j * MAX_WORD_LENGTH; @@ -235,18 +355,8 @@ public final class BinaryDictionary extends Dictionary { return mNativeDict != 0; } - public static float calcNormalizedScore(final String before, final String after, - final int score) { - return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), - StringUtils.toCodePointArray(after), score); - } - - public static int editDistance(final String before, final String after) { - if (before == null || after == null) { - throw new IllegalArgumentException(); - } - return editDistanceNative(StringUtils.toCodePointArray(before), - StringUtils.toCodePointArray(after)); + public int getFormatVersion() { + return getFormatVersionNative(mNativeDict); } @Override @@ -274,23 +384,77 @@ public final class BinaryDictionary extends Dictionary { return getBigramProbabilityNative(mNativeDict, codePoints0, codePoints1); } - // Add a unigram entry to binary dictionary in native code. - public void addUnigramWord(final String word, final int probability) { + public WordProperty getWordProperty(final String word) { + if (TextUtils.isEmpty(word)) { + return null; + } + final int[] codePoints = StringUtils.toCodePointArray(word); + final int[] outCodePoints = new int[MAX_WORD_LENGTH]; + final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT]; + final int[] outProbabilityInfo = + new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT]; + final ArrayList<int[]> outBigramTargets = CollectionUtils.newArrayList(); + final ArrayList<int[]> outBigramProbabilityInfo = CollectionUtils.newArrayList(); + final ArrayList<int[]> outShortcutTargets = CollectionUtils.newArrayList(); + final ArrayList<Integer> outShortcutProbabilities = CollectionUtils.newArrayList(); + getWordPropertyNative(mNativeDict, codePoints, outCodePoints, outFlags, outProbabilityInfo, + outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, + outShortcutProbabilities); + return new WordProperty(codePoints, + outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX], + outFlags[FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX], + outFlags[FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX], + outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX], outProbabilityInfo, + outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, + outShortcutProbabilities); + } + + public static class GetNextWordPropertyResult { + public WordProperty mWordProperty; + public int mNextToken; + + public GetNextWordPropertyResult(final WordProperty wordPreperty, final int nextToken) { + mWordProperty = wordPreperty; + mNextToken = nextToken; + } + } + + /** + * Method to iterate all words in the dictionary for makedict. + * If token is 0, this method newly starts iterating the dictionary. + */ + public GetNextWordPropertyResult getNextWordProperty(final int token) { + final int[] codePoints = new int[MAX_WORD_LENGTH]; + final int nextToken = getNextWordNative(mNativeDict, token, codePoints); + final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints); + return new GetNextWordPropertyResult(getWordProperty(word), nextToken); + } + + // Add a unigram entry to binary dictionary with unigram attributes in native code. + public void addUnigramWord(final String word, final int probability, + final String shortcutTarget, final int shortcutProbability, final boolean isNotAWord, + final boolean isBlacklisted, final int timestamp) { if (TextUtils.isEmpty(word)) { return; } final int[] codePoints = StringUtils.toCodePointArray(word); - addUnigramWordNative(mNativeDict, codePoints, probability); + final int[] shortcutTargetCodePoints = (shortcutTarget != null) ? + StringUtils.toCodePointArray(shortcutTarget) : null; + addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints, + shortcutProbability, isNotAWord, isBlacklisted, timestamp); + mHasUpdated = true; } - // Add a bigram entry to binary dictionary in native code. - public void addBigramWords(final String word0, final String word1, final int probability) { + // Add a bigram entry to binary dictionary with timestamp in native code. + public void addBigramWords(final String word0, final String word1, final int probability, + final int timestamp) { if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) { return; } final int[] codePoints0 = StringUtils.toCodePointArray(word0); final int[] codePoints1 = StringUtils.toCodePointArray(word1); - addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability); + addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability, timestamp); + mHasUpdated = true; } // Remove a bigram entry form binary dictionary in native code. @@ -301,21 +465,52 @@ public final class BinaryDictionary extends Dictionary { final int[] codePoints0 = StringUtils.toCodePointArray(word0); final int[] codePoints1 = StringUtils.toCodePointArray(word1); removeBigramWordsNative(mNativeDict, codePoints0, codePoints1); + mHasUpdated = true; + } + + public void addMultipleDictionaryEntries(final LanguageModelParam[] languageModelParams) { + if (!isValidDictionary()) return; + int processedParamCount = 0; + while (processedParamCount < languageModelParams.length) { + if (needsToRunGC(true /* mindsBlockByGC */)) { + flushWithGC(); + } + processedParamCount = addMultipleDictionaryEntriesNative(mNativeDict, + languageModelParams, processedParamCount); + mHasUpdated = true; + if (processedParamCount <= 0) { + return; + } + } } private void reopen() { close(); final File dictFile = new File(mDictFilePath); - mNativeDict = openNative(dictFile.getAbsolutePath(), 0 /* startOffset */, - dictFile.length(), true /* isUpdatable */); + // WARNING: Because we pass 0 as the offset and file.length() as the length, this can + // only be called for actual files. Right now it's only called by the flush() family of + // functions, which require an updatable dictionary, so it's okay. But beware. + loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, + dictFile.length(), mIsUpdatable); } + // Flush to dict file if the dictionary has been updated. public void flush() { if (!isValidDictionary()) return; - flushNative(mNativeDict, mDictFilePath); - reopen(); + if (mHasUpdated) { + flushNative(mNativeDict, mDictFilePath); + reopen(); + } } + // Run GC and flush to dict file if the dictionary has been updated. + public void flushWithGCIfHasUpdated() { + if (mHasUpdated) { + flushWithGC(); + } + } + + // Run GC and flush to dict file. public void flushWithGC() { if (!isValidDictionary()) return; flushWithGCNative(mNativeDict, mDictFilePath); @@ -333,6 +528,24 @@ public final class BinaryDictionary extends Dictionary { return needsToRunGCNative(mNativeDict, mindsBlockByGC); } + public boolean migrateTo(final int newFormatVersion) { + if (!isValidDictionary()) { + return false; + } + final String tmpDictFilePath = mDictFilePath + DICT_FILE_NAME_SUFFIX_FOR_MIGRATION; + // TODO: Implement migrateNative(tmpDictFilePath, newFormatVersion). + close(); + final File dictFile = new File(mDictFilePath); + final File tmpDictFile = new File(tmpDictFilePath); + FileUtils.deleteRecursively(dictFile); + if (!BinaryDictionaryUtils.renameDict(tmpDictFile, dictFile)) { + return false; + } + loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, + dictFile.length(), mIsUpdatable); + return true; + } + @UsedForTesting public int calculateProbability(final int unigramProbability, final int bigramProbability) { if (!isValidDictionary()) return NOT_A_PROBABILITY; @@ -340,7 +553,7 @@ public final class BinaryDictionary extends Dictionary { } @UsedForTesting - public String getPropertyForTests(String query) { + public String getPropertyForTest(final String query) { if (!isValidDictionary()) return ""; return getPropertyNative(mNativeDict, query); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 722a82961..e428b1d54 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -98,7 +98,7 @@ public final class BinaryDictionaryFileDumper { * This creates a URI builder able to build a URI pointing to the dictionary * pack content provider for a specific dictionary id. */ - private static Uri.Builder getProviderUriBuilder(final String path) { + public static Uri.Builder getProviderUriBuilder(final String path) { return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(DictionaryPackConstants.AUTHORITY).appendPath(path); } @@ -142,7 +142,7 @@ public final class BinaryDictionaryFileDumper { final ContentProviderClient client = context.getContentResolver(). acquireContentProviderClient(getProviderUriBuilder("").build()); if (null == client) return Collections.<WordListInfo>emptyList(); - + Cursor cursor = null; try { final Uri.Builder builder = getContentUriBuilderForType(clientId, client, QUERY_PATH_DICT_INFO, locale.toString()); @@ -154,24 +154,22 @@ public final class BinaryDictionaryFileDumper { final boolean isProtocolV2 = (QUERY_PARAMETER_PROTOCOL_VALUE.equals( queryUri.getQueryParameter(QUERY_PARAMETER_PROTOCOL))); - Cursor c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); - if (isProtocolV2 && null == c) { + cursor = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); + if (isProtocolV2 && null == cursor) { reinitializeClientRecordInDictionaryContentProvider(context, client, clientId); - c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); + cursor = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null); } - if (null == c) return Collections.<WordListInfo>emptyList(); - if (c.getCount() <= 0 || !c.moveToFirst()) { - c.close(); + if (null == cursor) return Collections.<WordListInfo>emptyList(); + if (cursor.getCount() <= 0 || !cursor.moveToFirst()) { return Collections.<WordListInfo>emptyList(); } final ArrayList<WordListInfo> list = CollectionUtils.newArrayList(); do { - final String wordListId = c.getString(0); - final String wordListLocale = c.getString(1); + final String wordListId = cursor.getString(0); + final String wordListLocale = cursor.getString(1); if (TextUtils.isEmpty(wordListId)) continue; list.add(new WordListInfo(wordListId, wordListLocale)); - } while (c.moveToNext()); - c.close(); + } while (cursor.moveToNext()); return list; } catch (RemoteException e) { // The documentation is unclear as to in which cases this may happen, but it probably @@ -186,6 +184,9 @@ public final class BinaryDictionaryFileDumper { Log.e(TAG, "Unexpected exception communicating with the dictionary pack", e); return Collections.<WordListInfo>emptyList(); } finally { + if (null != cursor) { + cursor.close(); + } client.release(); } } @@ -339,15 +340,25 @@ public final class BinaryDictionaryFileDumper { Log.e(TAG, "Could not copy a word list. Will not be able to use it."); // If we can't copy it we should warn the dictionary provider so that it can mark it // as invalid. - wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT, - QUERY_PARAMETER_FAILURE); + reportBrokenFileToDictionaryProvider(providerClient, clientId, wordlistId); + } + + public static boolean reportBrokenFileToDictionaryProvider( + final ContentProviderClient providerClient, final String clientId, + final String wordlistId) { try { + final Uri.Builder wordListUriBuilder = getContentUriBuilderForType(clientId, + providerClient, QUERY_PATH_DATAFILE, wordlistId /* extraPath */); + wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT, + QUERY_PARAMETER_FAILURE); if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) { - Log.e(TAG, "In addition, we were unable to delete it."); + Log.e(TAG, "Unable to delete a word list."); } } catch (RemoteException e) { - Log.e(TAG, "In addition, communication with the dictionary provider was cut", e); + Log.e(TAG, "Communication with the dictionary provider was cut", e); + return false; } + return true; } // Ideally the two following methods should be merged, but AssetFileDescriptor does not @@ -432,8 +443,9 @@ public final class BinaryDictionaryFileDumper { // Actually copy the file final byte[] buffer = new byte[FILE_READ_BUFFER_SIZE]; - for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) + for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer)) { output.write(buffer, 0, readBytes); + } input.close(); } @@ -478,8 +490,7 @@ public final class BinaryDictionaryFileDumper { * @param context the context for resources and providers. * @param clientId the client ID to use. */ - public static void initializeClientRecordHelper(final Context context, - final String clientId) { + public static void initializeClientRecordHelper(final Context context, final String clientId) { try { final ContentProviderClient client = context.getContentResolver(). acquireContentProviderClient(getProviderUriBuilder("").build()); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 181ad17ea..4c49cb31c 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -21,10 +21,9 @@ import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.util.Log; -import com.android.inputmethod.latin.makedict.DictDecoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; import com.android.inputmethod.latin.utils.LocaleUtils; @@ -112,7 +111,7 @@ final public class BinaryDictionaryGetter { public DictPackSettings(final Context context) { mDictPreferences = null == context ? null : context.getSharedPreferences(COMMON_PREFERENCES_NAME, - Context.MODE_WORLD_READABLE | Context.MODE_MULTI_PROCESS); + Context.MODE_MULTI_PROCESS); } public boolean isWordListActive(final String dictId) { if (null == mDictPreferences) { @@ -226,12 +225,10 @@ final public class BinaryDictionaryGetter { // ## HACK ## we prevent usage of a dictionary before version 18. The reason for this is, since // those do not include whitelist entries, the new code with an old version of the dictionary // would lose whitelist functionality. - private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) { + private static boolean hackCanUseDictionaryFile(final Locale locale, final File file) { try { // Read the version of the file - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(f); - final FileHeader header = dictDecoder.readHeader(); - + final DictionaryHeader header = BinaryDictionaryUtils.getHeader(file); final String version = header.mDictionaryOptions.mAttributes.get(VERSION_KEY); if (null == version) { // No version in the options : the format is unexpected diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 9a9653094..e71723a15 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -70,38 +70,47 @@ public final class Constants { public static final class ExtraValue { /** - * The subtype extra value used to indicate that the subtype keyboard layout is capable - * for typing ASCII characters. + * The subtype extra value used to indicate that this subtype is capable of + * entering ASCII characters. */ public static final String ASCII_CAPABLE = "AsciiCapable"; /** - * The subtype extra value used to indicate that the subtype keyboard layout is capable - * for typing EMOJI characters. + * The subtype extra value used to indicate that this subtype is enabled + * when the default subtype is not marked as ascii capable. + */ + public static final String ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = + "EnabledWhenDefaultIsNotAsciiCapable"; + + /** + * The subtype extra value used to indicate that this subtype is capable of + * entering emoji characters. */ public static final String EMOJI_CAPABLE = "EmojiCapable"; + /** - * The subtype extra value used to indicate that the subtype require network connection - * to work. + * The subtype extra value used to indicate that this subtype requires a network + * connection to work. */ public static final String REQ_NETWORK_CONNECTIVITY = "requireNetworkConnectivity"; /** - * The subtype extra value used to indicate that the subtype display name contains "%s" - * for replacement mark and it should be replaced by this extra value. + * The subtype extra value used to indicate that the display name of this subtype + * contains a "%s" for printf-like replacement and it should be replaced by + * this extra value. * This extra value is supported on JellyBean and later. */ public static final String UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME = "UntranslatableReplacementStringInSubtypeName"; /** - * The subtype extra value used to indicate that the subtype keyboard layout set name. + * The subtype extra value used to indicate this subtype keyboard layout set name. * This extra value is private to LatinIME. */ public static final String KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet"; /** - * The subtype extra value used to indicate that the subtype is additional subtype + * The subtype extra value used to indicate that this subtype is an additional subtype * that the user defined. This extra value is private to LatinIME. */ public static final String IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype"; @@ -124,6 +133,8 @@ public final class Constants { * {@link android.text.TextUtils#CAP_MODE_WORDS}, and * {@link android.text.TextUtils#CAP_MODE_SENTENCES}. */ + // TODO: Straighten this out. It's bizarre to have to use android.text.TextUtils.CAP_MODE_* + // except for OFF that is in Constants.TextUtils. public static final int CAP_MODE_OFF = 0; private TextUtils() { @@ -132,7 +143,8 @@ public final class Constants { } public static final int NOT_A_CODE = -1; - + public static final int NOT_A_CURSOR_POSITION = -1; + // TODO: replace the following constants with state in InputTransaction? public static final int NOT_A_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; public static final int SPELL_CHECKER_COORDINATE = -3; @@ -145,6 +157,13 @@ public final class Constants { // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h public static final int DICTIONARY_MAX_WORD_LENGTH = 48; + // Key events coming any faster than this are long-presses. + public static final int LONG_PRESS_MILLISECONDS = 200; + // TODO: Set this value appropriately. + public static final int GET_SUGGESTED_WORDS_TIMEOUT = 200; + // How many continuous deletes at which to start deleting at a higher speed. + public static final int DELETE_ACCELERATE_AT = 20; + public static boolean isValidCoordinate(final int coordinate) { // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE}, // and {@link SPELL_CHECKER_COORDINATE}. @@ -165,6 +184,7 @@ public final class Constants { public static final int CODE_TAB = '\t'; public static final int CODE_SPACE = ' '; public static final int CODE_PERIOD = '.'; + public static final int CODE_COMMA = ','; public static final int CODE_ARMENIAN_PERIOD = 0x0589; public static final int CODE_DASH = '-'; public static final int CODE_SINGLE_QUOTE = '\''; @@ -172,6 +192,8 @@ public final class Constants { public static final int CODE_QUESTION_MARK = '?'; public static final int CODE_EXCLAMATION_MARK = '!'; public static final int CODE_SLASH = '/'; + public static final int CODE_BACKSLASH = '\\'; + public static final int CODE_VERTICAL_BAR = '|'; public static final int CODE_COMMERCIAL_AT = '@'; public static final int CODE_PLUS = '+'; public static final int CODE_PERCENT = '%'; @@ -197,8 +219,10 @@ public final class Constants { public static final int CODE_LANGUAGE_SWITCH = -10; public static final int CODE_EMOJI = -11; public static final int CODE_SHIFT_ENTER = -12; + public static final int CODE_SYMBOL_SHIFT = -13; + public static final int CODE_ALPHA_FROM_EMOJI = -14; // Code value representing the code is not specified. - public static final int CODE_UNSPECIFIED = -13; + public static final int CODE_UNSPECIFIED = -15; public static boolean isLetterCode(final int code) { return code >= CODE_SPACE; @@ -221,6 +245,7 @@ public final class Constants { case CODE_UNSPECIFIED: return "unspec"; case CODE_TAB: return "tab"; case CODE_ENTER: return "enter"; + case CODE_ALPHA_FROM_EMOJI: return "alpha"; default: if (code < CODE_SPACE) return String.format("'\\u%02x'", code); if (code < 0x100) return String.format("'%c'", code); @@ -228,10 +253,37 @@ public final class Constants { } } + public static String printableCodes(final int[] codes) { + final StringBuilder sb = new StringBuilder(); + boolean addDelimiter = false; + for (final int code : codes) { + if (code == NOT_A_CODE) break; + if (addDelimiter) sb.append(", "); + sb.append(printableCode(code)); + addDelimiter = true; + } + return "[" + sb + "]"; + } + public static final int MAX_INT_BIT_COUNT = 32; + /** + * Screen metrics (a.k.a. Device form factor) constants of + * {@link R.integer#config_screen_metrics}. + */ + public static final int SCREEN_METRICS_SMALL_PHONE = 0; + public static final int SCREEN_METRICS_LARGE_PHONE = 1; + public static final int SCREEN_METRICS_LARGE_TABLET = 2; + public static final int SCREEN_METRICS_SMALL_TABLET = 3; + + /** + * Default capacity of gesture points container. + * This constant is used by {@link BatchInputArbiter} and etc. to preallocate regions that + * contain gesture event points. + */ + public static final int DEFAULT_GESTURE_POINTS_CAPACITY = 128; + private Constants() { // This utility class is not publicly instantiable. } - } diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 47891c6b7..09d0ea210 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.personalization.AccountUtils; - import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; @@ -31,8 +29,10 @@ import android.provider.ContactsContract.Contacts; import android.text.TextUtils; import android.util.Log; +import com.android.inputmethod.latin.personalization.AccountUtils; import com.android.inputmethod.latin.utils.StringUtils; +import java.io.File; import java.util.List; import java.util.Locale; @@ -44,7 +44,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private static final String TAG = ContactsBinaryDictionary.class.getSimpleName(); private static final String NAME = "contacts"; - private static boolean DEBUG = false; + private static final boolean DEBUG = false; + private static final boolean DEBUG_DUMP = false; /** * Frequency for contacts information into the dictionary @@ -71,35 +72,36 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private final boolean mUseFirstLastBigrams; public ContactsBinaryDictionary(final Context context, final Locale locale) { - super(context, getFilenameWithLocale(NAME, locale.toString()), Dictionary.TYPE_CONTACTS, - false /* isUpdatable */); + this(context, locale, null /* dictFile */); + } + + public ContactsBinaryDictionary(final Context context, final Locale locale, + final File dictFile) { + this(context, locale, dictFile, NAME); + } + + protected ContactsBinaryDictionary(final Context context, final Locale locale, + final File dictFile, final String name) { + super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_CONTACTS, + dictFile); mLocale = locale; mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale); registerObserver(context); - - // Load the current binary dictionary from internal storage. If no binary dictionary exists, - // loadDictionary will start a new thread to generate one asynchronously. - loadDictionary(); + reloadDictionaryIfRequired(); } private synchronized void registerObserver(final Context context) { - // Perform a managed query. The Activity will handle closing and requerying the cursor - // when needed. if (mObserver != null) return; ContentResolver cres = context.getContentResolver(); cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) { @Override public void onChange(boolean self) { - setRequiresReload(true); + setNeedsToReload(); } }); } - public void reopen(final Context context) { - registerObserver(context); - } - @Override public synchronized void close() { if (mObserver != null) { @@ -110,14 +112,14 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } @Override - public void loadDictionaryAsync() { - loadDeviceAccountsEmailAddresses(); - loadDictionaryAsyncForUri(ContactsContract.Profile.CONTENT_URI); + public void loadInitialContentsLocked() { + loadDeviceAccountsEmailAddressesLocked(); + loadDictionaryForUriLocked(ContactsContract.Profile.CONTENT_URI); // TODO: Switch this URL to the newer ContactsContract too - loadDictionaryAsyncForUri(Contacts.CONTENT_URI); + loadDictionaryForUriLocked(Contacts.CONTENT_URI); } - private void loadDeviceAccountsEmailAddresses() { + private void loadDeviceAccountsEmailAddressesLocked() { final List<String> accountVocabulary = AccountUtils.getDeviceAccountsEmailAddresses(mContext); if (accountVocabulary == null || accountVocabulary.isEmpty()) { @@ -127,29 +129,32 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { if (DEBUG) { Log.d(TAG, "loadAccountVocabulary: " + word); } - super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS, 0 /* shortcutFreq */, - false /* isNotAWord */); + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addWordDynamicallyLocked(word, FREQUENCY_FOR_CONTACTS, null /* shortcut */, + 0 /* shortcutFreq */, false /* isNotAWord */, false /* isBlacklisted */, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); } } - private void loadDictionaryAsyncForUri(final Uri uri) { + private void loadDictionaryForUriLocked(final Uri uri) { + Cursor cursor = null; try { - Cursor cursor = mContext.getContentResolver() - .query(uri, PROJECTION, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - sContactCountAtLastRebuild = getContactCount(); - addWords(cursor); - } - } finally { - cursor.close(); - } + cursor = mContext.getContentResolver().query(uri, PROJECTION, null, null, null); + if (null == cursor) { + return; + } + if (cursor.moveToFirst()) { + sContactCountAtLastRebuild = getContactCount(); + addWordsLocked(cursor); } } catch (final SQLiteException e) { Log.e(TAG, "SQLiteException in the remote Contacts process.", e); } catch (final IllegalStateException e) { Log.e(TAG, "Contacts DB is having problems", e); + } finally { + if (null != cursor) { + cursor.close(); + } } } @@ -161,13 +166,17 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { return false; } - private void addWords(final Cursor cursor) { + private void addWordsLocked(final Cursor cursor) { int count = 0; while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) { String name = cursor.getString(INDEX_NAME); if (isValidName(name)) { - addName(name); + addNameLocked(name); ++count; + } else { + if (DEBUG_DUMP) { + Log.d(TAG, "Invalid name: " + name); + } } cursor.moveToNext(); } @@ -176,18 +185,20 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private int getContactCount() { // TODO: consider switching to a rawQuery("select count(*)...") on the database if // performance is a bottleneck. + Cursor cursor = null; try { - final Cursor cursor = mContext.getContentResolver().query( - Contacts.CONTENT_URI, PROJECTION_ID_ONLY, null, null, null); - if (cursor != null) { - try { - return cursor.getCount(); - } finally { - cursor.close(); - } + cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, PROJECTION_ID_ONLY, + null, null, null); + if (null == cursor) { + return 0; } + return cursor.getCount(); } catch (final SQLiteException e) { Log.e(TAG, "SQLiteException in the remote Contacts process.", e); + } finally { + if (null != cursor) { + cursor.close(); + } } return 0; } @@ -196,7 +207,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { * Adds the words in a name (e.g., firstname/lastname) to the binary dictionary along with their * bigrams depending on locale. */ - private void addName(final String name) { + private void addNameLocked(final String name) { int len = StringUtils.codePointCount(name); String prevWord = null; // TODO: Better tokenization for non-Latin writing systems @@ -204,6 +215,9 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { if (Character.isLetter(name.codePointAt(i))) { int end = getWordEndPosition(name, len, i); String word = name.substring(i, end); + if (DEBUG_DUMP) { + Log.d(TAG, "addName word = " + word); + } i = end - 1; // Don't add single letter words, possibly confuses // capitalization of i. @@ -212,13 +226,15 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { if (DEBUG) { Log.d(TAG, "addName " + name + ", " + word + ", " + prevWord); } - super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS, - 0 /* shortcutFreq */, false /* isNotAWord */); - if (!TextUtils.isEmpty(prevWord)) { - if (mUseFirstLastBigrams) { - super.addBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM, - 0 /* lastModifiedTime */); - } + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addWordDynamicallyLocked(word, FREQUENCY_FOR_CONTACTS, + null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */, + false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) { + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addBigramDynamicallyLocked(prevWord, word, + FREQUENCY_FOR_CONTACTS_BIGRAM, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); } prevWord = word; } @@ -244,12 +260,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } @Override - protected boolean needsToReloadBeforeWriting() { - return true; - } - - @Override - protected boolean hasContentChanged() { + protected boolean haveContentsChanged() { final long startTime = SystemClock.uptimeMillis(); final int contactCount = getContactCount(); if (contactCount > MAX_CONTACT_COUNT) { @@ -268,26 +279,27 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // Check all contacts since it's not possible to find out which names have changed. // This is needed because it's possible to receive extraneous onChange events even when no // name has changed. - Cursor cursor = mContext.getContentResolver().query( - Contacts.CONTENT_URI, PROJECTION, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - while (!cursor.isAfterLast()) { - String name = cursor.getString(INDEX_NAME); - if (isValidName(name) && !isNameInDictionary(name)) { - if (DEBUG) { - Log.d(TAG, "Contact name missing: " + name + " (runtime = " - + (SystemClock.uptimeMillis() - startTime) + " ms)"); - } - return true; + final Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, PROJECTION, + null, null, null); + if (null == cursor) { + return false; + } + try { + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String name = cursor.getString(INDEX_NAME); + if (isValidName(name) && !isNameInDictionaryLocked(name)) { + if (DEBUG) { + Log.d(TAG, "Contact name missing: " + name + " (runtime = " + + (SystemClock.uptimeMillis() - startTime) + " ms)"); } - cursor.moveToNext(); + return true; } + cursor.moveToNext(); } - } finally { - cursor.close(); } + } finally { + cursor.close(); } if (DEBUG) { Log.d(TAG, "No contacts changed. (runtime = " + (SystemClock.uptimeMillis() - startTime) @@ -306,7 +318,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { /** * Checks if the words in a name are in the current binary dictionary. */ - private boolean isNameInDictionary(final String name) { + private boolean isNameInDictionaryLocked(final String name) { int len = StringUtils.codePointCount(name); String prevWord = null; for (int i = 0; i < len; i++) { @@ -317,11 +329,11 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { final int wordLen = StringUtils.codePointCount(word); if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) { - if (!super.isValidBigramLocked(prevWord, word)) { + if (!isValidBigramLocked(prevWord, word)) { return false; } } else { - if (!super.isValidWordLocked(word)) { + if (!isValidWordLocked(word)) { return false; } } diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index fa79f5af7..0742fbde9 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -27,6 +27,7 @@ import java.util.ArrayList; */ public abstract class Dictionary { public static final int NOT_A_PROBABILITY = -1; + public static final float NOT_A_LANGUAGE_WEIGHT = -1.0f; // The following types do not actually come from real dictionary instances, so we create // corresponding instances. @@ -52,13 +53,10 @@ public abstract class Dictionary { public static final String TYPE_CONTACTS = "contacts"; // User dictionary, the system-managed one. public static final String TYPE_USER = "user"; - // User history dictionary internal to LatinIME. This assumes bigram prediction for now. + // User history dictionary internal to LatinIME. public static final String TYPE_USER_HISTORY = "history"; - // Personalization binary dictionary internal to LatinIME. + // Personalization dictionary. public static final String TYPE_PERSONALIZATION = "personalization"; - // Personalization prediction dictionary internal to LatinIME's Java code. - public static final String TYPE_PERSONALIZATION_PREDICTION_IN_JAVA = - "personalization_prediction_in_java"; public final String mDictType; public Dictionary(final String dictType) { @@ -73,22 +71,26 @@ public abstract class Dictionary { * @param proximityInfo the object for key proximity. May be ignored by some implementations. * @param blockOffensiveWords whether to block potentially offensive words * @param additionalFeaturesOptions options about additional features used for the suggestion. + * @param inOutLanguageWeight the language weight used for generating suggestions. + * inOutLanguageWeight is a float array that has only one element. This can be updated when the + * different language weight is used. * @return the list of suggestions (possibly null if none) */ // TODO: pass more context than just the previous word, to enable better suggestions (n-gram // and more) abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions); + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight); // The default implementation of this method ignores sessionId. // Subclasses that want to use sessionId need to override this method. public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, - final int sessionId) { + final int sessionId, final float[] inOutLanguageWeight) { return getSuggestions(composer, prevWord, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions); + additionalFeaturesOptions, inOutLanguageWeight); } /** @@ -162,7 +164,8 @@ public abstract class Dictionary { @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { return null; } diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index bf075140e..16173fffc 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -58,18 +58,21 @@ public final class DictionaryCollection extends Dictionary { @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries; if (dictionaries.isEmpty()) return null; // To avoid creating unnecessary objects, we get the list out of the first // dictionary and add the rest to it if not null, hence the get(0) ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composer, - prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions); + prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, + inOutLanguageWeight); if (null == suggestions) suggestions = CollectionUtils.newArrayList(); final int length = dictionaries.size(); for (int i = 1; i < length; ++ i) { final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(composer, - prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions); + prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions, + inOutLanguageWeight); if (null != sugg) suggestions.addAll(sugg); } return suggestions; diff --git a/java/src/com/android/inputmethod/latin/DictionaryDumpBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/DictionaryDumpBroadcastReceiver.java new file mode 100644 index 000000000..ee2fdc6c7 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/DictionaryDumpBroadcastReceiver.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +public class DictionaryDumpBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = DictionaryDumpBroadcastReceiver.class.getSimpleName(); + + private static final String DOMAIN = "com.android.inputmethod.latin"; + public static final String DICTIONARY_DUMP_INTENT_ACTION = DOMAIN + ".DICT_DUMP"; + public static final String DICTIONARY_NAME_KEY = "dictName"; + + final LatinIME mLatinIme; + + public DictionaryDumpBroadcastReceiver(final LatinIME latinIme) { + mLatinIme = latinIme; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(DICTIONARY_DUMP_INTENT_ACTION)) { + final String dictName = intent.getStringExtra(DICTIONARY_NAME_KEY); + if (dictName == null) { + Log.e(TAG, "Received dictionary dump intent action " + + "but the dictionary name is not set."); + return; + } + mLatinIme.dumpDictionaryForDebug(dictName); + } + } +} diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java new file mode 100644 index 000000000..b6fcbd1d6 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2013 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.text.TextUtils; +import android.util.Log; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.personalization.PersonalizationDictionary; +import com.android.inputmethod.latin.personalization.PersonalizationHelper; +import com.android.inputmethod.latin.personalization.UserHistoryDictionary; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.ExecutorUtils; +import com.android.inputmethod.latin.utils.LanguageModelParam; +import com.android.inputmethod.latin.utils.SuggestionResults; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +// TODO: Consolidate dictionaries in native code. +public class DictionaryFacilitatorForSuggest { + public static final String TAG = DictionaryFacilitatorForSuggest.class.getSimpleName(); + + // HACK: This threshold is being used when adding a capitalized entry in the User History + // dictionary. + private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140; + + private Dictionaries mDictionaries = new Dictionaries(); + private boolean mIsUserDictEnabled = false; + private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); + // To synchronize assigning mDictionaries to ensure closing dictionaries. + private Object mLock = new Object(); + + private static final String[] dictTypesOrderedToGetSuggestion = + new String[] { + Dictionary.TYPE_MAIN, + Dictionary.TYPE_USER_HISTORY, + Dictionary.TYPE_PERSONALIZATION, + Dictionary.TYPE_USER, + Dictionary.TYPE_CONTACTS + }; + + /** + * Class contains dictionaries for a locale. + */ + private static class Dictionaries { + public final Locale mLocale; + public final ConcurrentHashMap<String, Dictionary> mDictMap = + CollectionUtils.newConcurrentHashMap(); + public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap = + CollectionUtils.newConcurrentHashMap(); + + public Dictionaries() { + mLocale = null; + } + + public Dictionaries(final Locale locale, final Dictionary mainDict, + final ExpandableBinaryDictionary contactsDict, + final ExpandableBinaryDictionary userDict, + final ExpandableBinaryDictionary userHistoryDict, + final ExpandableBinaryDictionary personalizationDict) { + mLocale = locale; + // Main dictionary can be asynchronously loaded. + setMainDict(mainDict); + setSubDict(Dictionary.TYPE_CONTACTS, contactsDict); + setSubDict(Dictionary.TYPE_USER, userDict); + setSubDict(Dictionary.TYPE_USER_HISTORY, userHistoryDict); + setSubDict(Dictionary.TYPE_PERSONALIZATION, personalizationDict); + } + + private void setSubDict(final String dictType, final ExpandableBinaryDictionary dict) { + if (dict != null) { + mDictMap.put(dictType, dict); + mSubDictMap.put(dictType, dict); + } + } + + public void setMainDict(final Dictionary mainDict) { + // Close old dictionary if exists. Main dictionary can be assigned multiple times. + final Dictionary oldDict; + if (mainDict != null) { + oldDict = mDictMap.put(Dictionary.TYPE_MAIN, mainDict); + } else { + oldDict = mDictMap.remove(Dictionary.TYPE_MAIN); + } + if (oldDict != null && mainDict != oldDict) { + oldDict.close(); + } + } + + public Dictionary getMainDict() { + return mDictMap.get(Dictionary.TYPE_MAIN); + } + + public ExpandableBinaryDictionary getSubDict(final String dictType) { + return mSubDictMap.get(dictType); + } + + public boolean hasDict(final String dictType) { + return mDictMap.containsKey(dictType); + } + + public void closeDict(final String dictType) { + final Dictionary dict = mDictMap.remove(dictType); + mSubDictMap.remove(dictType); + if (dict != null) { + dict.close(); + } + } + } + + public interface DictionaryInitializationListener { + public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable); + } + + public DictionaryFacilitatorForSuggest() {} + + public Locale getLocale() { + return mDictionaries.mLocale; + } + + public void resetDictionaries(final Context context, final Locale newLocale, + final boolean useContactsDict, final boolean usePersonalizedDicts, + final boolean forceReloadMainDictionary, + final DictionaryInitializationListener listener) { + final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale); + // We always try to have the main dictionary. Other dictionaries can be unused. + final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary; + final boolean closeContactsDictionary = localeHasBeenChanged || !useContactsDict; + final boolean closeUserDictionary = localeHasBeenChanged; + final boolean closeUserHistoryDictionary = localeHasBeenChanged || !usePersonalizedDicts; + final boolean closePersonalizationDictionary = + localeHasBeenChanged || !usePersonalizedDicts; + + final Dictionary newMainDict; + if (reloadMainDictionary) { + // The main dictionary will be asynchronously loaded. + newMainDict = null; + } else { + newMainDict = mDictionaries.getMainDict(); + } + + // Open or move contacts dictionary. + final ExpandableBinaryDictionary newContactsDict; + if (!closeContactsDictionary && mDictionaries.hasDict(Dictionary.TYPE_CONTACTS)) { + newContactsDict = mDictionaries.getSubDict(Dictionary.TYPE_CONTACTS); + } else if (useContactsDict) { + newContactsDict = new ContactsBinaryDictionary(context, newLocale); + } else { + newContactsDict = null; + } + + // Open or move user dictionary. + final ExpandableBinaryDictionary newUserDictionary; + if (!closeUserDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER)) { + newUserDictionary = mDictionaries.getSubDict(Dictionary.TYPE_USER); + } else { + newUserDictionary = new UserBinaryDictionary(context, newLocale); + mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context); + } + + // Open or move user history dictionary. + final ExpandableBinaryDictionary newUserHistoryDict; + if (!closeUserHistoryDictionary && mDictionaries.hasDict(Dictionary.TYPE_USER_HISTORY)) { + newUserHistoryDict = mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); + } else if (usePersonalizedDicts) { + newUserHistoryDict = PersonalizationHelper.getUserHistoryDictionary(context, newLocale); + } else { + newUserHistoryDict = null; + } + + // Open or move personalization dictionary. + final ExpandableBinaryDictionary newPersonalizationDict; + if (!closePersonalizationDictionary + && mDictionaries.hasDict(Dictionary.TYPE_PERSONALIZATION)) { + newPersonalizationDict = mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); + } else if (usePersonalizedDicts) { + newPersonalizationDict = + PersonalizationHelper.getPersonalizationDictionary(context, newLocale); + } else { + newPersonalizationDict = null; + } + + // Replace Dictionaries. + final Dictionaries newDictionaries = new Dictionaries(newLocale, newMainDict, + newContactsDict, newUserDictionary, newUserHistoryDict, newPersonalizationDict); + final Dictionaries oldDictionaries; + synchronized (mLock) { + oldDictionaries = mDictionaries; + mDictionaries = newDictionaries; + if (reloadMainDictionary) { + asyncReloadMainDictionary(context, newLocale, listener); + } + } + if (listener != null) { + listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary()); + } + + // Clean up old dictionaries. + if (reloadMainDictionary) { + oldDictionaries.closeDict(Dictionary.TYPE_MAIN); + } + if (closeContactsDictionary) { + oldDictionaries.closeDict(Dictionary.TYPE_CONTACTS); + } + if (closeUserDictionary) { + oldDictionaries.closeDict(Dictionary.TYPE_USER); + } + if (closeUserHistoryDictionary) { + oldDictionaries.closeDict(Dictionary.TYPE_USER_HISTORY); + } + if (closePersonalizationDictionary) { + oldDictionaries.closeDict(Dictionary.TYPE_PERSONALIZATION); + } + oldDictionaries.mDictMap.clear(); + oldDictionaries.mSubDictMap.clear(); + } + + private void asyncReloadMainDictionary(final Context context, final Locale locale, + final DictionaryInitializationListener listener) { + final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1); + mLatchForWaitingLoadingMainDictionary = latchForWaitingLoadingMainDictionary; + ExecutorUtils.getExecutor("InitializeBinaryDictionary").execute(new Runnable() { + @Override + public void run() { + final Dictionary mainDict = + DictionaryFactory.createMainDictionaryFromManager(context, locale); + synchronized (mLock) { + if (locale.equals(mDictionaries.mLocale)) { + mDictionaries.setMainDict(mainDict); + } else { + // Dictionary facilitator has been reset for another locale. + mainDict.close(); + } + } + if (listener != null) { + listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary()); + } + latchForWaitingLoadingMainDictionary.countDown(); + } + }); + } + + @UsedForTesting + public void resetDictionariesForTesting(final Context context, final Locale locale, + final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, + final Map<String, Map<String, String>> additionalDictAttributes) { + Dictionary mainDictionary = null; + ContactsBinaryDictionary contactsDictionary = null; + UserBinaryDictionary userDictionary = null; + UserHistoryDictionary userHistoryDictionary = null; + PersonalizationDictionary personalizationDictionary = null; + + for (final String dictType : dictionaryTypes) { + if (dictType.equals(Dictionary.TYPE_MAIN)) { + mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale); + } else if (dictType.equals(Dictionary.TYPE_USER_HISTORY)) { + userHistoryDictionary = + PersonalizationHelper.getUserHistoryDictionary(context, locale); + // Staring with an empty user history dictionary for testing. + // Testing program may populate this dictionary before actual testing. + userHistoryDictionary.reloadDictionaryIfRequired(); + userHistoryDictionary.waitAllTasksForTests(); + if (additionalDictAttributes.containsKey(dictType)) { + userHistoryDictionary.clearAndFlushDictionaryWithAdditionalAttributes( + additionalDictAttributes.get(dictType)); + } + } else if (dictType.equals(Dictionary.TYPE_PERSONALIZATION)) { + personalizationDictionary = + PersonalizationHelper.getPersonalizationDictionary(context, locale); + // Staring with an empty personalization dictionary for testing. + // Testing program may populate this dictionary before actual testing. + personalizationDictionary.reloadDictionaryIfRequired(); + personalizationDictionary.waitAllTasksForTests(); + if (additionalDictAttributes.containsKey(dictType)) { + personalizationDictionary.clearAndFlushDictionaryWithAdditionalAttributes( + additionalDictAttributes.get(dictType)); + } + } else if (dictType.equals(Dictionary.TYPE_USER)) { + final File file = dictionaryFiles.get(dictType); + userDictionary = new UserBinaryDictionary(context, locale, file); + userDictionary.reloadDictionaryIfRequired(); + userDictionary.waitAllTasksForTests(); + } else if (dictType.equals(Dictionary.TYPE_CONTACTS)) { + final File file = dictionaryFiles.get(dictType); + contactsDictionary = new ContactsBinaryDictionary(context, locale, file); + contactsDictionary.reloadDictionaryIfRequired(); + contactsDictionary.waitAllTasksForTests(); + } else { + throw new RuntimeException("Unknown dictionary type: " + dictType); + } + } + mDictionaries = new Dictionaries(locale, mainDictionary, contactsDictionary, + userDictionary, userHistoryDictionary, personalizationDictionary); + } + + public void closeDictionaries() { + final Dictionaries dictionaries; + synchronized (mLock) { + dictionaries = mDictionaries; + mDictionaries = new Dictionaries(); + } + for (final Dictionary dict : dictionaries.mDictMap.values()) { + dict.close(); + } + } + + // The main dictionary could have been loaded asynchronously. Don't cache the return value + // of this method. + public boolean hasInitializedMainDictionary() { + final Dictionary mainDict = mDictionaries.getMainDict(); + return mainDict != null && mainDict.isInitialized(); + } + + public boolean hasPersonalizationDictionary() { + return mDictionaries.hasDict(Dictionary.TYPE_PERSONALIZATION); + } + + public void flushPersonalizationDictionary() { + final ExpandableBinaryDictionary personalizationDict = + mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); + if (personalizationDict != null) { + personalizationDict.asyncFlushBinaryDictionary(); + } + } + + public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit) + throws InterruptedException { + mLatchForWaitingLoadingMainDictionary.await(timeout, unit); + } + + @UsedForTesting + public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit) + throws InterruptedException { + waitForLoadingMainDictionary(timeout, unit); + final Map<String, ExpandableBinaryDictionary> dictMap = mDictionaries.mSubDictMap; + for (final ExpandableBinaryDictionary dict : dictMap.values()) { + dict.waitAllTasksForTests(); + } + } + + public boolean isUserDictionaryEnabled() { + return mIsUserDictEnabled; + } + + public void addWordToUserDictionary(final Context context, final String word) { + final Locale locale = getLocale(); + if (locale == null) { + return; + } + UserBinaryDictionary.addWordToUserDictionary(context, locale, word); + } + + public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, + final String previousWord, final int timeStampInSeconds) { + final Dictionaries dictionaries = mDictionaries; + final ExpandableBinaryDictionary userHistoryDictionary = + dictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); + if (userHistoryDictionary == null) { + return; + } + final int maxFreq = getMaxFrequency(suggestion); + if (maxFreq == 0) { + return; + } + final String suggestionLowerCase = suggestion.toLowerCase(dictionaries.mLocale); + final String secondWord; + if (wasAutoCapitalized) { + if (isValidWord(suggestion, false /* ignoreCase */) + && !isValidWord(suggestionLowerCase, false /* ignoreCase */)) { + // If the word was auto-capitalized and exists only as a capitalized word in the + // dictionary, then we must not downcase it before registering it. For example, + // the name of the contacts in start-of-sentence position would come here with the + // wasAutoCapitalized flag: if we downcase it, we'd register a lower-case version + // of that contact's name which would end up popping in suggestions. + secondWord = suggestion; + } else { + // If however the word is not in the dictionary, or exists as a lower-case word + // only, then we consider that was a lower-case word that had been auto-capitalized. + secondWord = suggestionLowerCase; + } + } else { + // HACK: We'd like to avoid adding the capitalized form of common words to the User + // History dictionary in order to avoid suggesting them until the dictionary + // consolidation is done. + // TODO: Remove this hack when ready. + final int lowerCaseFreqInMainDict = dictionaries.hasDict(Dictionary.TYPE_MAIN) ? + dictionaries.getMainDict().getFrequency(suggestionLowerCase) : + Dictionary.NOT_A_PROBABILITY; + if (maxFreq < lowerCaseFreqInMainDict + && lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) { + // Use lower cased word as the word can be a distracter of the popular word. + secondWord = suggestionLowerCase; + } else { + secondWord = suggestion; + } + } + // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". + // We don't add words with 0-frequency (assuming they would be profanity etc.). + final boolean isValid = maxFreq > 0; + UserHistoryDictionary.addToDictionary(userHistoryDictionary, previousWord, secondWord, + isValid, timeStampInSeconds); + } + + public void cancelAddingUserHistory(final String previousWord, final String committedWord) { + final ExpandableBinaryDictionary userHistoryDictionary = + mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); + if (userHistoryDictionary != null) { + userHistoryDictionary.removeBigramDynamically(previousWord, committedWord); + } + } + + // TODO: Revise the way to fusion suggestion results. + public SuggestionResults getSuggestionResults(final WordComposer composer, + final String prevWord, final ProximityInfo proximityInfo, + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final int sessionId, final ArrayList<SuggestedWordInfo> rawSuggestions) { + final Dictionaries dictionaries = mDictionaries; + final Map<String, Dictionary> dictMap = dictionaries.mDictMap; + final SuggestionResults suggestionResults = + new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS); + final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT }; + for (final String dictType : dictTypesOrderedToGetSuggestion) { + final Dictionary dictionary = dictMap.get(dictType); + if (null == dictionary) continue; + final ArrayList<SuggestedWordInfo> dictionarySuggestions = + dictionary.getSuggestionsWithSessionId(composer, prevWord, proximityInfo, + blockOffensiveWords, additionalFeaturesOptions, sessionId, + languageWeight); + if (null == dictionarySuggestions) continue; + suggestionResults.addAll(dictionarySuggestions); + if (null != rawSuggestions) { + rawSuggestions.addAll(dictionarySuggestions); + } + } + return suggestionResults; + } + + public boolean isValidMainDictWord(final String word) { + final Dictionaries dictionaries = mDictionaries; + if (TextUtils.isEmpty(word) || !dictionaries.hasDict(Dictionary.TYPE_MAIN)) { + return false; + } + return dictionaries.getMainDict().isValidWord(word); + } + + public boolean isValidWord(final String word, final boolean ignoreCase) { + if (TextUtils.isEmpty(word)) { + return false; + } + final Dictionaries dictionaries = mDictionaries; + if (dictionaries.mLocale == null) { + return false; + } + final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale); + final Map<String, Dictionary> dictMap = dictionaries.mDictMap; + for (final Dictionary dictionary : dictMap.values()) { + // 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; + } + } + return false; + } + + private int getMaxFrequency(final String word) { + if (TextUtils.isEmpty(word)) { + return Dictionary.NOT_A_PROBABILITY; + } + int maxFreq = -1; + final Map<String, Dictionary> dictMap = mDictionaries.mDictMap; + for (final Dictionary dictionary : dictMap.values()) { + final int tempFreq = dictionary.getFrequency(word); + if (tempFreq >= maxFreq) { + maxFreq = tempFreq; + } + } + return maxFreq; + } + + public void clearUserHistoryDictionary() { + final ExpandableBinaryDictionary userHistoryDict = + mDictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY); + if (userHistoryDict == null) { + return; + } + userHistoryDict.clear(); + } + + // This method gets called only when the IME receives a notification to remove the + // personalization dictionary. + public void clearPersonalizationDictionary() { + final ExpandableBinaryDictionary personalizationDict = + mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); + if (personalizationDict == null) { + return; + } + personalizationDict.clear(); + } + + public void addMultipleDictionaryEntriesToPersonalizationDictionary( + final ArrayList<LanguageModelParam> languageModelParams, + final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) { + final ExpandableBinaryDictionary personalizationDict = + mDictionaries.getSubDict(Dictionary.TYPE_PERSONALIZATION); + if (personalizationDict == null || languageModelParams == null + || languageModelParams.isEmpty()) { + if (callback != null) { + callback.onFinished(); + } + return; + } + personalizationDict.addMultipleDictionaryEntriesDynamically(languageModelParams, callback); + } + + public void dumpDictionaryForDebug(final String dictName) { + final ExpandableBinaryDictionary dictToDump = mDictionaries.getSubDict(dictName); + if (dictToDump == null) { + Log.e(TAG, "Cannot dump " + dictName + ". " + + "The dictionary is not being used for suggestion or cannot be dumped."); + return; + } + dictToDump.dumpAllWordsForDebug(); + } +} diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 828e54f14..e09c309ea 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import android.content.ContentProviderClient; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; @@ -64,6 +65,10 @@ public final class DictionaryFactory { useFullEditDistance, locale, Dictionary.TYPE_MAIN); if (readOnlyBinaryDictionary.isValidDictionary()) { dictList.add(readOnlyBinaryDictionary); + } else { + readOnlyBinaryDictionary.close(); + // Prevent this dictionary to do any further harm. + killDictionary(context, f); } } } @@ -75,6 +80,51 @@ public final class DictionaryFactory { } /** + * Kills a dictionary so that it is never used again, if possible. + * @param context The context to contact the dictionary provider, if possible. + * @param f A file address to the dictionary to kill. + */ + private static void killDictionary(final Context context, final AssetFileAddress f) { + if (f.pointsToPhysicalFile()) { + f.deleteUnderlyingFile(); + // Warn the dictionary provider if the dictionary came from there. + final ContentProviderClient providerClient; + try { + providerClient = context.getContentResolver().acquireContentProviderClient( + BinaryDictionaryFileDumper.getProviderUriBuilder("").build()); + } catch (final SecurityException e) { + Log.e(TAG, "No permission to communicate with the dictionary provider", e); + return; + } + if (null == providerClient) { + Log.e(TAG, "Can't establish communication with the dictionary provider"); + return; + } + final String wordlistId = + DictionaryInfoUtils.getWordListIdFromFileName(new File(f.mFilename).getName()); + if (null != wordlistId) { + // TODO: this is a reasonable last resort, but it is suboptimal. + // The following will remove the entry for this dictionary with the dictionary + // provider. When the metadata is downloaded again, we will try downloading it + // again. + // However, in the practice that will mean the user will find themselves without + // the new dictionary. That's fine for languages where it's included in the APK, + // but for other languages it will leave the user without a dictionary at all until + // the next update, which may be a few days away. + // Ideally, we would trigger a new download right away, and use increasing retry + // delays for this particular id/version combination. + // Then again, this is expected to only ever happen in case of human mistake. If + // the wrong file is on the server, the following is still doing the right thing. + // If it's a file left over from the last version however, it's not great. + BinaryDictionaryFileDumper.reportBrokenFileToDictionaryProvider( + providerClient, + context.getString(R.string.dictionary_pack_client_id), + wordlistId); + } + } + } + + /** * Initializes a main dictionary collection from a dictionary pack, with default flags. * * This searches for a content provider providing a dictionary pack for the specified diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java deleted file mode 100644 index 3df2a2b63..000000000 --- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2013 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 com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -/** - * An in memory dictionary for memorizing entries and writing a binary dictionary. - */ -public class DictionaryWriter extends AbstractDictionaryWriter { - private static final int BINARY_DICT_VERSION = 3; - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = - new FormatSpec.FormatOptions(BINARY_DICT_VERSION, true /* supportsDynamicUpdate */); - - private FusionDictionary mFusionDictionary; - - public DictionaryWriter(final Context context, final String dictType) { - super(context, dictType); - clear(); - } - - @Override - public void clear() { - final HashMap<String, String> attributes = CollectionUtils.newHashMap(); - mFusionDictionary = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(attributes, false, false)); - } - - /** - * Adds a word unigram to the fusion dictionary. - */ - // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries, - // considering performance regression. - @Override - public void addUnigramWord(final String word, final String shortcutTarget, final int frequency, - final int shortcutFreq, final boolean isNotAWord) { - if (shortcutTarget == null) { - mFusionDictionary.add(word, frequency, null, isNotAWord); - } else { - // TODO: Do this in the subclass, with this class taking an arraylist. - final ArrayList<WeightedString> shortcutTargets = CollectionUtils.newArrayList(); - shortcutTargets.add(new WeightedString(shortcutTarget, shortcutFreq)); - mFusionDictionary.add(word, frequency, shortcutTargets, isNotAWord); - } - } - - @Override - public void addBigramWords(final String word0, final String word1, final int frequency, - final boolean isValid, final long lastModifiedTime) { - mFusionDictionary.setBigram(word0, word1, frequency); - } - - @Override - public void removeBigramWords(final String word0, final String word1) { - // This class don't support removing bigram words. - } - - @Override - protected void writeDictionary(final DictEncoder dictEncoder, - final Map<String, String> attributeMap) throws IOException, UnsupportedFormatException { - for (final Map.Entry<String, String> entry : attributeMap.entrySet()) { - mFusionDictionary.addOptionAttribute(entry.getKey(), entry.getValue()); - } - dictEncoder.writeDictionary(mFusionDictionary, FORMAT_OPTIONS); - } - - @Override - public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, - final String prevWord, final ProximityInfo proximityInfo, - boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { - // This class doesn't support suggestion. - return null; - } - - @Override - public boolean isValidWord(String word) { - // This class doesn't support dictionary retrieval. - return false; - } -} diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index eb8650e6f..550db4a6c 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -17,33 +17,35 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.os.SystemClock; import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.personalization.DynamicPersonalizationDictionaryWriter; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.utils.AsyncResultHolder; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.PrioritizedSerialExecutor; +import com.android.inputmethod.latin.utils.CombinedFormatUtils; +import com.android.inputmethod.latin.utils.ExecutorUtils; +import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LanguageModelParam; import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.Locale; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Abstract base class for an expandable dictionary that can be created and updated dynamically * during runtime. When updated it automatically generates a new binary dictionary to handle future - * queries in native code. This binary dictionary is written to internal storage, and potentially - * shared across multiple ExpandableBinaryDictionary instances. Updates to each dictionary filename - * are controlled across multiple instances to ensure that only one instance can update the same - * dictionary at the same time. + * queries in native code. This binary dictionary is written to internal storage. */ abstract public class ExpandableBinaryDictionary extends Dictionary { @@ -52,34 +54,19 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** Whether to print debug output to log */ private static boolean DEBUG = false; - - // TODO: Remove. - /** Whether to call binary dictionary dynamically updating methods. */ - public static boolean ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE = true; + private static final boolean DBG_STRESS_TEST = false; private static final int TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS = 100; + private static final int DEFAULT_MAX_UNIGRAM_COUNT = 10000; + private static final int DEFAULT_MAX_BIGRAM_COUNT = 10000; + /** * The maximum length of a word in this dictionary. */ protected static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; - private static final int DICTIONARY_FORMAT_VERSION = 3; - - private static final String SUPPORTS_DYNAMIC_UPDATE = - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE; - - /** - * A static map of update controllers, each of which records the time of accesses to a single - * binary dictionary file and tracks whether the file is regenerating. The key for this map is - * the filename and the value is the shared dictionary time recorder associated with that - * filename. - */ - private static final ConcurrentHashMap<String, DictionaryUpdateController> - sFilenameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap(); - - private static final ConcurrentHashMap<String, PrioritizedSerialExecutor> - sFilenameExecutorMap = CollectionUtils.newConcurrentHashMap(); + private static final int DICTIONARY_FORMAT_VERSION = FormatSpec.VERSION4; /** The application context. */ protected final Context mContext; @@ -90,138 +77,113 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ private BinaryDictionary mBinaryDictionary; - // TODO: Remove and handle dictionaries in native code. - /** The in-memory dictionary used to generate the binary dictionary. */ - protected AbstractDictionaryWriter mDictionaryWriter; - /** - * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple - * dictionary instances with the same filename is supported, with access controlled by - * DictionaryTimeRecorder. + * The name of this dictionary, used as a part of the filename for storing the binary + * dictionary. */ - private final String mFilename; + private final String mDictName; - /** Whether to support dynamically updating the dictionary */ - private final boolean mIsUpdatable; + /** Dictionary locale */ + private final Locale mLocale; - // TODO: remove, once dynamic operations is serialized - /** Controls updating the shared binary dictionary file across multiple instances. */ - private final DictionaryUpdateController mFilenameDictionaryUpdateController; + /** Dictionary file */ + private final File mDictFile; - // TODO: remove, once dynamic operations is serialized - /** Controls updating the local binary dictionary for this instance. */ - private final DictionaryUpdateController mPerInstanceDictionaryUpdateController = - new DictionaryUpdateController(); + /** Indicates whether a task for reloading the dictionary has been scheduled. */ + private final AtomicBoolean mIsReloading; - /* A extension for a binary dictionary file. */ - public static final String DICT_FILE_EXTENSION = ".dict"; + /** Indicates whether the current dictionary needs to be reloaded. */ + private boolean mNeedsToReload; - private final AtomicReference<Runnable> mUnfinishedFlushingTask = - new AtomicReference<Runnable>(); + private final ReentrantReadWriteLock mLock; - /** - * Abstract method for loading the unigrams and bigrams of a given dictionary in a background - * thread. - */ - protected abstract void loadDictionaryAsync(); + /* A extension for a binary dictionary file. */ + protected static final String DICT_FILE_EXTENSION = ".dict"; /** - * Indicates that the source dictionary content has changed and a rebuild of the binary file is - * required. If it returns false, the next reload will only read the current binary dictionary - * from file. Note that the shared binary dictionary is locked when this is called. + * Abstract method for loading initial contents of a given dictionary. */ - protected abstract boolean hasContentChanged(); + protected abstract void loadInitialContentsLocked(); /** - * Gets the dictionary update controller for the given filename. + * Indicates that the source dictionary contents have changed and a rebuild of the binary file + * is required. If it returns false, the next reload will only read the current binary + * dictionary from file. */ - private static DictionaryUpdateController getDictionaryUpdateController( - String filename) { - DictionaryUpdateController recorder = sFilenameDictionaryUpdateControllerMap.get(filename); - if (recorder == null) { - synchronized(sFilenameDictionaryUpdateControllerMap) { - recorder = new DictionaryUpdateController(); - sFilenameDictionaryUpdateControllerMap.put(filename, recorder); - } - } - return recorder; + protected abstract boolean haveContentsChanged(); + + private boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) { + return formatVersion == FormatSpec.VERSION4; } - /** - * Gets the executor for the given filename. - */ - private static PrioritizedSerialExecutor getExecutor(final String filename) { - PrioritizedSerialExecutor executor = sFilenameExecutorMap.get(filename); - if (executor == null) { - synchronized(sFilenameExecutorMap) { - executor = new PrioritizedSerialExecutor(); - sFilenameExecutorMap.put(filename, executor); - } - } - return executor; + private boolean needsToMigrateDictionary(final int formatVersion) { + // TODO: Check version. + return false; } - private static AbstractDictionaryWriter getDictionaryWriter(final Context context, - final String dictType, final boolean isDynamicPersonalizationDictionary) { - if (isDynamicPersonalizationDictionary) { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - return null; - } else { - return new DynamicPersonalizationDictionaryWriter(context, dictType); - } - } else { - return new DictionaryWriter(context, dictType); - } + public boolean isValidDictionaryLocked() { + return mBinaryDictionary.isValidDictionary(); } /** * Creates a new expandable binary dictionary. * * @param context The application context of the parent. - * @param filename The filename for this binary dictionary. Multiple dictionaries with the same - * filename is supported. + * @param dictName The name of the dictionary. Multiple instances with the same + * name is supported. + * @param locale the dictionary locale. * @param dictType the dictionary type, as a human-readable string - * @param isUpdatable whether to support dynamically updating the dictionary. Please note that - * dynamic dictionary has negative effects on memory space and computation time. + * @param dictFile dictionary file path. if null, use default dictionary path based on + * dictionary type. */ - public ExpandableBinaryDictionary(final Context context, final String filename, - final String dictType, final boolean isUpdatable) { + public ExpandableBinaryDictionary(final Context context, final String dictName, + final Locale locale, final String dictType, final File dictFile) { super(dictType); - mFilename = filename; + mDictName = dictName; mContext = context; - mIsUpdatable = isUpdatable; + mLocale = locale; + mDictFile = getDictFile(context, dictName, dictFile); mBinaryDictionary = null; - mFilenameDictionaryUpdateController = getDictionaryUpdateController(filename); - // Currently, only dynamic personalization dictionary is updatable. - mDictionaryWriter = getDictionaryWriter(context, dictType, isUpdatable); + mIsReloading = new AtomicBoolean(); + mNeedsToReload = false; + mLock = new ReentrantReadWriteLock(); } - protected static String getFilenameWithLocale(final String name, final String localeStr) { - return name + "." + localeStr + DICT_FILE_EXTENSION; + public static File getDictFile(final Context context, final String dictName, + final File dictFile) { + return (dictFile != null) ? dictFile + : new File(context.getFilesDir(), dictName + DICT_FILE_EXTENSION); } - /** - * Closes and cleans up the binary dictionary. - */ - @Override - public void close() { - getExecutor(mFilename).execute(new Runnable() { + public static String getDictName(final String name, final Locale locale, + final File dictFile) { + return dictFile != null ? dictFile.getName() : name + "." + locale.toString(); + } + + private void asyncExecuteTaskWithWriteLock(final Runnable task) { + asyncExecuteTaskWithLock(mLock.writeLock(), task); + } + + private void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) { + ExecutorUtils.getExecutor(mDictName).execute(new Runnable() { @Override public void run() { - if (mBinaryDictionary!= null) { - mBinaryDictionary.close(); - mBinaryDictionary = null; - } - if (mDictionaryWriter != null) { - mDictionaryWriter.close(); + lock.lock(); + try { + task.run(); + } finally { + lock.unlock(); } } }); } - protected void closeBinaryDictionary() { - // Ensure that no other threads are accessing the local binary dictionary. - getExecutor(mFilename).execute(new Runnable() { + /** + * Closes and cleans up the binary dictionary. + */ + @Override + public void close() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { if (mBinaryDictionary != null) { @@ -234,239 +196,241 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected Map<String, String> getHeaderAttributeMap() { HashMap<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - SUPPORTS_DYNAMIC_UPDATE); - attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mFilename); + attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, mDictName); + attributeMap.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, mLocale.toString()); + attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, + String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); + attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY, + String.valueOf(DEFAULT_MAX_UNIGRAM_COUNT)); + attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY, + String.valueOf(DEFAULT_MAX_BIGRAM_COUNT)); return attributeMap; } - protected void clear() { - getExecutor(mFilename).execute(new Runnable() { + private void removeBinaryDictionary() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE && mDictionaryWriter == null) { - mBinaryDictionary.close(); - final File file = new File(mContext.getFilesDir(), mFilename); - BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap()); - mBinaryDictionary = new BinaryDictionary( - file.getAbsolutePath(), 0 /* offset */, file.length(), - true /* useFullEditDistance */, null, mDictType, mIsUpdatable); - } else { - mDictionaryWriter.clear(); - } + removeBinaryDictionaryLocked(); } }); } - /** - * Adds a word unigram to the dictionary. Used for loading a dictionary. - * @param word The word to add. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this unigram. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored - * if shortcutTarget is null. - * @param isNotAWord true if this is not a word, i.e. shortcut only. - */ - protected void addWord(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq, final boolean isNotAWord) { - mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, shortcutFreq, isNotAWord); + private void removeBinaryDictionaryLocked() { + if (mBinaryDictionary != null) { + mBinaryDictionary.close(); + } + if (mDictFile.exists() && !FileUtils.deleteRecursively(mDictFile)) { + Log.e(TAG, "Can't remove a file: " + mDictFile.getName()); + } + mBinaryDictionary = null; } - /** - * Adds a word bigram in the dictionary. Used for loading a dictionary. - */ - protected void addBigram(final String prevWord, final String word, final int frequency, - final long lastModifiedTime) { - mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */, - lastModifiedTime); + private void openBinaryDictionaryLocked() { + mBinaryDictionary = new BinaryDictionary( + mDictFile.getAbsolutePath(), 0 /* offset */, mDictFile.length(), + true /* useFullEditDistance */, mLocale, mDictType, true /* isUpdatable */); + } + + private void createOnMemoryBinaryDictionaryLocked() { + mBinaryDictionary = new BinaryDictionary( + mDictFile.getAbsolutePath(), true /* useFullEditDistance */, mLocale, mDictType, + DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap()); + } + + public void clear() { + asyncExecuteTaskWithWriteLock(new Runnable() { + @Override + public void run() { + removeBinaryDictionaryLocked(); + createOnMemoryBinaryDictionaryLocked(); + } + }); } /** * Check whether GC is needed and run GC if required. */ protected void runGCIfRequired(final boolean mindsBlockByGC) { - if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return; - getExecutor(mFilename).execute(new Runnable() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - runGCIfRequiredInternalLocked(mindsBlockByGC); + if (mBinaryDictionary == null) { + return; + } + runGCIfRequiredLocked(mindsBlockByGC); } }); } - private void runGCIfRequiredInternalLocked(final boolean mindsBlockByGC) { - if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return; - // Calls to needsToRunGC() need to be serialized. + protected void runGCIfRequiredLocked(final boolean mindsBlockByGC) { if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) { - if (setIsRegeneratingIfNotRegenerating()) { - // Run GC after currently existing time sensitive operations. - getExecutor(mFilename).executePrioritized(new Runnable() { - @Override - public void run() { - try { - mBinaryDictionary.flushWithGC(); - } finally { - mFilenameDictionaryUpdateController.mIsRegenerating.set(false); - } - } - }); - } + mBinaryDictionary.flushWithGC(); } } /** * Dynamically adds a word unigram to the dictionary. May overwrite an existing entry. */ - protected void addWordDynamically(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq, final boolean isNotAWord) { - if (!mIsUpdatable) { - Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename); - return; - } - getExecutor(mFilename).execute(new Runnable() { + public void addWordDynamically(final String word, final int frequency, + final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord, + final boolean isBlacklisted, final int timestamp) { + reloadDictionaryIfRequired(); + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); - mBinaryDictionary.addUnigramWord(word, frequency); - } else { - // TODO: Remove. - mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, shortcutFreq, - isNotAWord); + if (mBinaryDictionary == null) { + return; } + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addWordDynamicallyLocked(word, frequency, shortcutTarget, shortcutFreq, + isNotAWord, isBlacklisted, timestamp); } }); } + protected void addWordDynamicallyLocked(final String word, final int frequency, + final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord, + final boolean isBlacklisted, final int timestamp) { + mBinaryDictionary.addUnigramWord(word, frequency, shortcutTarget, shortcutFreq, + isNotAWord, isBlacklisted, timestamp); + } + /** * Dynamically adds a word bigram in the dictionary. May overwrite an existing entry. */ - protected void addBigramDynamically(final String word0, final String word1, - final int frequency, final boolean isValid) { - if (!mIsUpdatable) { - Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: " - + mFilename); - return; - } - getExecutor(mFilename).execute(new Runnable() { + public void addBigramDynamically(final String word0, final String word1, + final int frequency, final int timestamp) { + reloadDictionaryIfRequired(); + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); - mBinaryDictionary.addBigramWords(word0, word1, frequency); - } else { - // TODO: Remove. - mDictionaryWriter.addBigramWords(word0, word1, frequency, isValid, - 0 /* lastTouchedTime */); + if (mBinaryDictionary == null) { + return; } + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addBigramDynamicallyLocked(word0, word1, frequency, timestamp); } }); } + protected void addBigramDynamicallyLocked(final String word0, final String word1, + final int frequency, final int timestamp) { + mBinaryDictionary.addBigramWords(word0, word1, frequency, timestamp); + } + /** * Dynamically remove a word bigram in the dictionary. */ - protected void removeBigramDynamically(final String word0, final String word1) { - if (!mIsUpdatable) { - Log.w(TAG, "removeBigramDynamically is called for non-updatable dictionary: " - + mFilename); - return; - } - getExecutor(mFilename).execute(new Runnable() { + public void removeBigramDynamically(final String word0, final String word1) { + reloadDictionaryIfRequired(); + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - runGCIfRequiredInternalLocked(true /* mindsBlockByGC */); - mBinaryDictionary.removeBigramWords(word0, word1); - } else { - // TODO: Remove. - mDictionaryWriter.removeBigramWords(word0, word1); + if (mBinaryDictionary == null) { + return; } + runGCIfRequiredLocked(true /* mindsBlockByGC */); + mBinaryDictionary.removeBigramWords(word0, word1); } }); } - @Override - public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, - final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, - final int sessionId) { + public interface AddMultipleDictionaryEntriesCallback { + public void onFinished(); + } + + /** + * Dynamically add multiple entries to the dictionary. + */ + public void addMultipleDictionaryEntriesDynamically( + final ArrayList<LanguageModelParam> languageModelParams, + final AddMultipleDictionaryEntriesCallback callback) { reloadDictionaryIfRequired(); - if (isRegenerating()) { - return null; - } - final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); - final AsyncResultHolder<ArrayList<SuggestedWordInfo>> holder = - new AsyncResultHolder<ArrayList<SuggestedWordInfo>>(); - getExecutor(mFilename).executePrioritized(new Runnable() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { + try { if (mBinaryDictionary == null) { - holder.set(null); return; } - final ArrayList<SuggestedWordInfo> binarySuggestion = - mBinaryDictionary.getSuggestionsWithSessionId(composer, prevWord, - proximityInfo, blockOffensiveWords, additionalFeaturesOptions, - sessionId); - holder.set(binarySuggestion); - } else { - final ArrayList<SuggestedWordInfo> inMemDictSuggestion = - composer.isBatchMode() ? null : - mDictionaryWriter.getSuggestionsWithSessionId(composer, - prevWord, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, sessionId); - // TODO: Remove checking mIsUpdatable and use native suggestion. - if (mBinaryDictionary != null && !mIsUpdatable) { - final ArrayList<SuggestedWordInfo> binarySuggestion = - mBinaryDictionary.getSuggestionsWithSessionId(composer, prevWord, - proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, sessionId); - if (inMemDictSuggestion == null) { - holder.set(binarySuggestion); - } else if (binarySuggestion == null) { - holder.set(inMemDictSuggestion); - } else { - binarySuggestion.addAll(inMemDictSuggestion); - holder.set(binarySuggestion); - } - } else { - holder.set(inMemDictSuggestion); + mBinaryDictionary.addMultipleDictionaryEntries( + languageModelParams.toArray( + new LanguageModelParam[languageModelParams.size()])); + } finally { + if (callback != null) { + callback.onFinished(); } } } }); - return holder.get(null, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS); + } + + @Override + public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, + final String prevWord, final ProximityInfo proximityInfo, + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final int sessionId, final float[] inOutLanguageWeight) { + reloadDictionaryIfRequired(); + boolean lockAcquired = false; + try { + lockAcquired = mLock.readLock().tryLock( + TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS, TimeUnit.MILLISECONDS); + if (lockAcquired) { + if (mBinaryDictionary == null) { + return null; + } + final ArrayList<SuggestedWordInfo> suggestions = + mBinaryDictionary.getSuggestionsWithSessionId(composer, prevWord, + proximityInfo, blockOffensiveWords, additionalFeaturesOptions, + sessionId, inOutLanguageWeight); + if (mBinaryDictionary.isCorrupted()) { + Log.i(TAG, "Dictionary (" + mDictName +") is corrupted. " + + "Remove and regenerate it."); + removeBinaryDictionary(); + } + return suggestions; + } + } catch (final InterruptedException e) { + Log.e(TAG, "Interrupted tryLock() in getSuggestionsWithSessionId().", e); + } finally { + if (lockAcquired) { + mLock.readLock().unlock(); + } + } + return null; } @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, 0 /* sessionId */); + additionalFeaturesOptions, 0 /* sessionId */, inOutLanguageWeight); } @Override public boolean isValidWord(final String word) { reloadDictionaryIfRequired(); - return isValidWordInner(word); - } - - protected boolean isValidWordInner(final String word) { - if (isRegenerating()) { - return false; - } - final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>(); - getExecutor(mFilename).executePrioritized(new Runnable() { - @Override - public void run() { - holder.set(isValidWordLocked(word)); + boolean lockAcquired = false; + try { + lockAcquired = mLock.readLock().tryLock( + TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS, TimeUnit.MILLISECONDS); + if (lockAcquired) { + if (mBinaryDictionary == null) { + return false; + } + return isValidWordLocked(word); } - }); - return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS); + } catch (final InterruptedException e) { + Log.e(TAG, "Interrupted tryLock() in isValidWord().", e); + } finally { + if (lockAcquired) { + mLock.readLock().unlock(); + } + } + return false; } protected boolean isValidWordLocked(final String word) { @@ -480,257 +444,180 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } /** - * Load the current binary dictionary from internal storage in a background thread. If no binary - * dictionary exists, this method will generate one. - */ - protected void loadDictionary() { - mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = SystemClock.uptimeMillis(); - reloadDictionaryIfRequired(); - } - - /** * Loads the current binary dictionary from internal storage. Assumes the dictionary file * exists. */ - private void loadBinaryDictionary() { - if (DEBUG) { - Log.d(TAG, "Loading binary dictionary: " + mFilename + " request=" - + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); + private void loadBinaryDictionaryLocked() { + if (DBG_STRESS_TEST) { + // Test if this class does not cause problems when it takes long time to load binary + // dictionary. + try { + Log.w(TAG, "Start stress in loading: " + mDictName); + Thread.sleep(15000); + Log.w(TAG, "End stress in loading"); + } catch (InterruptedException e) { + } } - - final File file = new File(mContext.getFilesDir(), mFilename); - final String filename = file.getAbsolutePath(); - final long length = file.length(); - - // Build the new binary dictionary - final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0 /* offset */, - length, true /* useFullEditDistance */, null, mDictType, mIsUpdatable); - - // Ensure all threads accessing the current dictionary have finished before - // swapping in the new one. - // TODO: Ensure multi-thread assignment of mBinaryDictionary. final BinaryDictionary oldBinaryDictionary = mBinaryDictionary; - getExecutor(mFilename).executePrioritized(new Runnable() { - @Override - public void run() { - mBinaryDictionary = newBinaryDictionary; - if (oldBinaryDictionary != null) { - oldBinaryDictionary.close(); - } - } - }); + openBinaryDictionaryLocked(); + if (oldBinaryDictionary != null) { + oldBinaryDictionary.close(); + } + if (mBinaryDictionary.isValidDictionary() + && needsToMigrateDictionary(mBinaryDictionary.getFormatVersion())) { + mBinaryDictionary.migrateTo(DICTIONARY_FORMAT_VERSION); + } } /** - * Abstract method for checking if it is required to reload the dictionary before writing - * a binary dictionary. - */ - abstract protected boolean needsToReloadBeforeWriting(); - - /** - * Writes a new binary dictionary based on the contents of the fusion dictionary. + * Create a new binary dictionary and load initial contents. */ - private void writeBinaryDictionary() { - if (DEBUG) { - Log.d(TAG, "Generating binary dictionary: " + mFilename + " request=" - + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); - } - if (needsToReloadBeforeWriting()) { - mDictionaryWriter.clear(); - loadDictionaryAsync(); - mDictionaryWriter.write(mFilename, getHeaderAttributeMap()); - } else { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - if (mBinaryDictionary == null || !mBinaryDictionary.isValidDictionary()) { - final File file = new File(mContext.getFilesDir(), mFilename); - BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - DICTIONARY_FORMAT_VERSION, getHeaderAttributeMap()); - } else { - if (mBinaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { - mBinaryDictionary.flushWithGC(); - } else { - mBinaryDictionary.flush(); - } - } - } else { - mDictionaryWriter.write(mFilename, getHeaderAttributeMap()); - } - } + private void createNewDictionaryLocked() { + removeBinaryDictionaryLocked(); + createOnMemoryBinaryDictionaryLocked(); + loadInitialContentsLocked(); + // Run GC and flush to file when initial contents have been loaded. + mBinaryDictionary.flushWithGCIfHasUpdated(); } /** - * Marks that the dictionary is out of date and requires a reload. + * Marks that the dictionary needs to be reloaded. * - * @param requiresRebuild Indicates that the source dictionary content has changed and a rebuild - * of the binary file is required. If not true, the next reload process will only read - * the current binary dictionary from file. */ - protected void setRequiresReload(final boolean requiresRebuild) { - final long time = SystemClock.uptimeMillis(); - mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = time; - mFilenameDictionaryUpdateController.mLastUpdateRequestTime = time; - if (DEBUG) { - Log.d(TAG, "Reload request: " + mFilename + ": request=" + time + " update=" - + mFilenameDictionaryUpdateController.mLastUpdateTime); - } + protected void setNeedsToReload() { + mNeedsToReload = true; } /** - * Reloads the dictionary if required. + * Load the current binary dictionary from internal storage. If the dictionary file doesn't + * exists or needs to be regenerated, the new dictionary file will be asynchronously generated. + * However, the dictionary itself is accessible even before the new dictionary file is actually + * generated. It may return a null result for getSuggestions() in that case by design. */ public final void reloadDictionaryIfRequired() { if (!isReloadRequired()) return; - if (setIsRegeneratingIfNotRegenerating()) { - reloadDictionary(); - } + asyncReloadDictionary(); } /** * Returns whether a dictionary reload is required. */ private boolean isReloadRequired() { - return mBinaryDictionary == null || mPerInstanceDictionaryUpdateController.isOutOfDate(); - } - - private boolean isRegenerating() { - return mFilenameDictionaryUpdateController.mIsRegenerating.get(); - } - - // Returns whether the dictionary can be regenerated. - private boolean setIsRegeneratingIfNotRegenerating() { - return mFilenameDictionaryUpdateController.mIsRegenerating.compareAndSet( - false /* expect */ , true /* update */); + return mBinaryDictionary == null || mNeedsToReload; } /** - * Reloads the dictionary. Access is controlled on a per dictionary file basis and supports - * concurrent calls from multiple instances that share the same dictionary file. + * Reloads the dictionary. Access is controlled on a per dictionary file basis. */ - private final void reloadDictionary() { - // Ensure that only one thread attempts to read or write to the shared binary dictionary - // file at the same time. - getExecutor(mFilename).execute(new Runnable() { - @Override - public void run() { - try { - final long time = SystemClock.uptimeMillis(); - final boolean dictionaryFileExists = dictionaryFileExists(); - if (mFilenameDictionaryUpdateController.isOutOfDate() - || !dictionaryFileExists) { - // If the shared dictionary file does not exist or is out of date, the - // first instance that acquires the lock will generate a new one. - if (hasContentChanged() || !dictionaryFileExists) { - // If the source content has changed or the dictionary does not exist, - // rebuild the binary dictionary. Empty dictionaries are supported (in - // the case where loadDictionaryAsync() adds nothing) in order to - // provide a uniform framework. - mFilenameDictionaryUpdateController.mLastUpdateTime = time; - writeBinaryDictionary(); - loadBinaryDictionary(); - } else { - // If not, the reload request was unnecessary so revert - // LastUpdateRequestTime to LastUpdateTime. - mFilenameDictionaryUpdateController.mLastUpdateRequestTime = - mFilenameDictionaryUpdateController.mLastUpdateTime; + private final void asyncReloadDictionary() { + if (mIsReloading.compareAndSet(false, true)) { + asyncExecuteTaskWithWriteLock(new Runnable() { + @Override + public void run() { + try { + // TODO: Quit checking contents in ExpandableBinaryDictionary. + if (!mDictFile.exists() || (mNeedsToReload && haveContentsChanged())) { + // If the dictionary file does not exist or contents have been updated, + // generate a new one. + createNewDictionaryLocked(); + } else if (mBinaryDictionary == null) { + // Otherwise, load the existing dictionary. + loadBinaryDictionaryLocked(); } - } else if (mBinaryDictionary == null || - mPerInstanceDictionaryUpdateController.mLastUpdateTime - < mFilenameDictionaryUpdateController.mLastUpdateTime) { - // Otherwise, if the local dictionary is older than the shared dictionary, - // load the shared dictionary. - loadBinaryDictionary(); - } - if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) { - // Binary dictionary is not valid. Regenerate the dictionary file. - mFilenameDictionaryUpdateController.mLastUpdateTime = time; - writeBinaryDictionary(); - loadBinaryDictionary(); + mNeedsToReload = false; + if (mBinaryDictionary != null && !(isValidDictionaryLocked() + // TODO: remove the check below + && matchesExpectedBinaryDictFormatVersionForThisType( + mBinaryDictionary.getFormatVersion()))) { + // Binary dictionary or its format version is not valid. Regenerate + // the dictionary file. writeBinaryDictionary will remove the + // existing files if appropriate. + createNewDictionaryLocked(); + } + } finally { + mIsReloading.set(false); } - mPerInstanceDictionaryUpdateController.mLastUpdateTime = time; - } finally { - mFilenameDictionaryUpdateController.mIsRegenerating.set(false); } - } - }); - } - - // TODO: cache the file's existence so that we avoid doing a disk access each time. - private boolean dictionaryFileExists() { - final File file = new File(mContext.getFilesDir(), mFilename); - return file.exists(); + }); + } } /** - * Load the dictionary to memory. + * Flush binary dictionary to dictionary file. */ - protected void asyncLoadDictionaryToMemory() { - getExecutor(mFilename).executePrioritized(new Runnable() { + public void asyncFlushBinaryDictionary() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { - if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - loadDictionaryAsync(); + if (mBinaryDictionary == null) { + return; + } + if (mBinaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + mBinaryDictionary.flushWithGC(); + } else { + mBinaryDictionary.flush(); } } }); } - /** - * Generate binary dictionary using DictionaryWriter. - */ - protected void asyncFlashAllBinaryDictionary() { - final Runnable newTask = new Runnable() { - @Override - public void run() { - writeBinaryDictionary(); + // TODO: Implement BinaryDictionary.isInDictionary(). + @UsedForTesting + public boolean isInUnderlyingBinaryDictionaryForTests(final String word) { + mLock.readLock().lock(); + try { + if (mBinaryDictionary != null && mDictType == Dictionary.TYPE_USER_HISTORY) { + return mBinaryDictionary.isValidWord(word); } - }; - final Runnable oldTask = mUnfinishedFlushingTask.getAndSet(newTask); - getExecutor(mFilename).replaceAndExecute(oldTask, newTask); - } - - /** - * For tracking whether the dictionary is out of date and the dictionary is regenerating. - * Can be shared across multiple dictionary instances that access the same filename. - */ - private static class DictionaryUpdateController { - public volatile long mLastUpdateTime = 0; - public volatile long mLastUpdateRequestTime = 0; - public volatile AtomicBoolean mIsRegenerating = new AtomicBoolean(); - - public boolean isOutOfDate() { - return (mLastUpdateRequestTime > mLastUpdateTime); + return false; + } finally { + mLock.readLock().unlock(); } } - // TODO: Implement native binary methods once the dynamic dictionary implementation is done. @UsedForTesting - public boolean isInDictionaryForTests(final String word) { - final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>(); - getExecutor(mFilename).executePrioritized(new Runnable() { + public void waitAllTasksForTests() { + final CountDownLatch countDownLatch = new CountDownLatch(1); + ExecutorUtils.getExecutor(mDictName).execute(new Runnable() { @Override public void run() { - if (mDictType == Dictionary.TYPE_USER_HISTORY) { - if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - holder.set(mBinaryDictionary.isValidWord(word)); - } else { - holder.set(((DynamicPersonalizationDictionaryWriter) mDictionaryWriter) - .isInBigramListForTests(word)); - } - } + countDownLatch.countDown(); } }); - return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS); - } - - @UsedForTesting - public void shutdownExecutorForTests() { - getExecutor(mFilename).shutdown(); + try { + countDownLatch.await(); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted while waiting for finishing dictionary operations.", e); + } } @UsedForTesting - public boolean isTerminatedForTests() { - return getExecutor(mFilename).isTerminated(); + public void dumpAllWordsForDebug() { + reloadDictionaryIfRequired(); + asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() { + @Override + public void run() { + Log.d(TAG, "Dump dictionary: " + mDictName); + try { + final DictionaryHeader header = mBinaryDictionary.getHeader(); + Log.d(TAG, CombinedFormatUtils.formatAttributeMap( + header.mDictionaryOptions.mAttributes)); + } catch (final UnsupportedFormatException e) { + Log.d(TAG, "Cannot fetch header information.", e); + } + int token = 0; + do { + final BinaryDictionary.GetNextWordPropertyResult result = + mBinaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + if (wordProperty == null) { + Log.d(TAG, " dictionary is empty."); + break; + } + Log.d(TAG, wordProperty.toString()); + token = result.mNextToken; + } while (token != 0); + } + }); } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java deleted file mode 100644 index 95c9bcab9..000000000 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ /dev/null @@ -1,894 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin; - -import android.text.TextUtils; -import android.util.Log; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams; - -import java.util.ArrayList; -import java.util.LinkedList; - -/** - * Class for an in-memory dictionary that can grow dynamically and can - * be searched for suggestions and valid words. - */ -// TODO: Remove after binary dictionary supports dynamic update. -public class ExpandableDictionary extends Dictionary { - private static final String TAG = ExpandableDictionary.class.getSimpleName(); - /** - * The weight to give to a word if it's length is the same as the number of typed characters. - */ - private static final int FULL_WORD_SCORE_MULTIPLIER = 2; - - private char[] mWordBuilder = new char[Constants.DICTIONARY_MAX_WORD_LENGTH]; - private int mMaxDepth; - private int mInputLength; - - private static final class Node { - char mCode; - int mFrequency; - boolean mTerminal; - Node mParent; - NodeArray mChildren; - ArrayList<char[]> mShortcutTargets; - boolean mShortcutOnly; - LinkedList<NextWord> mNGrams; // Supports ngram - } - - private static final class NodeArray { - Node[] mData; - int mLength = 0; - private static final int INCREMENT = 2; - - NodeArray() { - mData = new Node[INCREMENT]; - } - - void add(final Node n) { - if (mLength + 1 > mData.length) { - Node[] tempData = new Node[mLength + INCREMENT]; - if (mLength > 0) { - System.arraycopy(mData, 0, tempData, 0, mLength); - } - mData = tempData; - } - mData[mLength++] = n; - } - } - - public interface NextWord { - public Node getWordNode(); - public int getFrequency(); - public ForgettingCurveParams getFcParams(); - public int notifyTypedAgainAndGetFrequency(); - } - - private static final class NextStaticWord implements NextWord { - public final Node mWord; - private final int mFrequency; - public NextStaticWord(Node word, int frequency) { - mWord = word; - mFrequency = frequency; - } - - @Override - public Node getWordNode() { - return mWord; - } - - @Override - public int getFrequency() { - return mFrequency; - } - - @Override - public ForgettingCurveParams getFcParams() { - return null; - } - - @Override - public int notifyTypedAgainAndGetFrequency() { - return mFrequency; - } - } - - private static final class NextHistoryWord implements NextWord { - public final Node mWord; - public final ForgettingCurveParams mFcp; - - public NextHistoryWord(Node word, ForgettingCurveParams fcp) { - mWord = word; - mFcp = fcp; - } - - @Override - public Node getWordNode() { - return mWord; - } - - @Override - public int getFrequency() { - return mFcp.getFrequency(); - } - - @Override - public ForgettingCurveParams getFcParams() { - return mFcp; - } - - @Override - public int notifyTypedAgainAndGetFrequency() { - return mFcp.notifyTypedAgainAndGetFrequency(); - } - } - - private NodeArray mRoots; - - private int[][] mCodes; - - public ExpandableDictionary(final String dictType) { - super(dictType); - clearDictionary(); - mCodes = new int[Constants.DICTIONARY_MAX_WORD_LENGTH][]; - } - - public int getMaxWordLength() { - return Constants.DICTIONARY_MAX_WORD_LENGTH; - } - - /** - * Add a word with an optional shortcut to the dictionary. - * @param word The word to add. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this unigram. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored - * if shortcutTarget is null. - */ - public void addWord(final String word, final String shortcutTarget, final int frequency, - final int shortcutFreq) { - if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH) { - return; - } - addWordRec(mRoots, word, 0, shortcutTarget, frequency, shortcutFreq, null); - } - - /** - * Add a word, recursively searching for its correct place in the trie tree. - * @param children The node to recursively search for addition. Initially, the root of the tree. - * @param word The word to add. - * @param depth The current depth in the tree. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this unigram. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored - * if shortcutTarget is null. - * @param parentNode The parent node, for up linking. Initially null, as the root has no parent. - */ - private void addWordRec(final NodeArray children, final String word, final int depth, - final String shortcutTarget, final int frequency, final int shortcutFreq, - final Node parentNode) { - final int wordLength = word.length(); - if (wordLength <= depth) return; - final char c = word.charAt(depth); - // Does children have the current character? - final int childrenLength = children.mLength; - Node childNode = null; - for (int i = 0; i < childrenLength; i++) { - final Node node = children.mData[i]; - if (node.mCode == c) { - childNode = node; - break; - } - } - final boolean isShortcutOnly = (null != shortcutTarget); - if (childNode == null) { - childNode = new Node(); - childNode.mCode = c; - childNode.mParent = parentNode; - childNode.mShortcutOnly = isShortcutOnly; - children.add(childNode); - } - if (wordLength == depth + 1) { - // Terminate this word - childNode.mTerminal = true; - if (isShortcutOnly) { - if (null == childNode.mShortcutTargets) { - childNode.mShortcutTargets = CollectionUtils.newArrayList(); - } - childNode.mShortcutTargets.add(shortcutTarget.toCharArray()); - } else { - childNode.mShortcutOnly = false; - } - childNode.mFrequency = Math.max(frequency, childNode.mFrequency); - if (childNode.mFrequency > 255) childNode.mFrequency = 255; - return; - } - if (childNode.mChildren == null) { - childNode.mChildren = new NodeArray(); - } - addWordRec(childNode.mChildren, word, depth + 1, shortcutTarget, frequency, shortcutFreq, - childNode); - } - - @Override - public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, - final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { - if (composer.size() > 1) { - if (composer.size() >= Constants.DICTIONARY_MAX_WORD_LENGTH) { - return null; - } - final ArrayList<SuggestedWordInfo> suggestions = - getWordsInner(composer, prevWord, proximityInfo); - return suggestions; - } else { - if (TextUtils.isEmpty(prevWord)) return null; - final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); - runBigramReverseLookUp(prevWord, suggestions); - return suggestions; - } - } - - private ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes, - final String prevWordForBigrams, final ProximityInfo proximityInfo) { - final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); - mInputLength = codes.size(); - if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; - final InputPointers ips = codes.getInputPointers(); - final int[] xCoordinates = ips.getXCoordinates(); - final int[] yCoordinates = ips.getYCoordinates(); - // Cache the codes so that we don't have to lookup an array list - for (int i = 0; i < mInputLength; i++) { - // TODO: Calculate proximity info here. - if (mCodes[i] == null || mCodes[i].length < 1) { - mCodes[i] = new int[ProximityInfo.MAX_PROXIMITY_CHARS_SIZE]; - } - final int x = xCoordinates != null && i < xCoordinates.length ? - xCoordinates[i] : Constants.NOT_A_COORDINATE; - final int y = xCoordinates != null && i < yCoordinates.length ? - yCoordinates[i] : Constants.NOT_A_COORDINATE; - proximityInfo.fillArrayWithNearestKeyCodes(x, y, codes.getCodeAt(i), mCodes[i]); - } - mMaxDepth = mInputLength * 3; - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, suggestions); - for (int i = 0; i < mInputLength; i++) { - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, suggestions); - } - return suggestions; - } - - @Override - public synchronized boolean isValidWord(final String word) { - final Node node = searchNode(mRoots, word, 0, word.length()); - // If node is null, we didn't find the word, so it's not valid. - // If node.mShortcutOnly is true, then it exists as a shortcut but not as a word, - // so that means it's not a valid word. - // If node.mShortcutOnly is false, then it exists as a word (it may also exist as - // a shortcut, but this does not matter), so it's a valid word. - return (node == null) ? false : !node.mShortcutOnly; - } - - public boolean removeBigram(final String word0, final String word1) { - // Refer to addOrSetBigram() about word1.toLowerCase() - final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null); - final Node secondWord = searchWord(mRoots, word1, 0, null); - LinkedList<NextWord> bigrams = firstWord.mNGrams; - NextWord bigramNode = null; - if (bigrams == null || bigrams.size() == 0) { - return false; - } else { - for (NextWord nw : bigrams) { - if (nw.getWordNode() == secondWord) { - bigramNode = nw; - break; - } - } - } - if (bigramNode == null) { - return false; - } - return bigrams.remove(bigramNode); - } - - /** - * Returns the word's frequency or -1 if not found - */ - @UsedForTesting - public int getWordFrequency(final String word) { - // Case-sensitive search - final Node node = searchNode(mRoots, word, 0, word.length()); - return (node == null) ? -1 : node.mFrequency; - } - - public NextWord getBigramWord(final String word0, final String word1) { - // Refer to addOrSetBigram() about word0.toLowerCase() - final Node firstWord = searchWord(mRoots, word0.toLowerCase(), 0, null); - final Node secondWord = searchWord(mRoots, word1, 0, null); - LinkedList<NextWord> bigrams = firstWord.mNGrams; - if (bigrams == null || bigrams.size() == 0) { - return null; - } else { - for (NextWord nw : bigrams) { - if (nw.getWordNode() == secondWord) { - return nw; - } - } - } - return null; - } - - private static int computeSkippedWordFinalFreq(final int freq, final int snr, - final int inputLength) { - // The computation itself makes sense for >= 2, but the == 2 case returns 0 - // anyway so we may as well test against 3 instead and return the constant - if (inputLength >= 3) { - return (freq * snr * (inputLength - 2)) / (inputLength - 1); - } else { - return 0; - } - } - - /** - * Helper method to add a word and its shortcuts. - * - * @param node the terminal node - * @param word the word to insert, as an array of code points - * @param depth the depth of the node in the tree - * @param finalFreq the frequency for this word - * @param suggestions the suggestion collection to add the suggestions to - * @return whether there is still space for more words. - */ - private boolean addWordAndShortcutsFromNode(final Node node, final char[] word, final int depth, - final int finalFreq, final ArrayList<SuggestedWordInfo> suggestions) { - if (finalFreq > 0 && !node.mShortcutOnly) { - // Use KIND_CORRECTION always. This dictionary does not really have a notion of - // COMPLETION against CORRECTION; we could artificially add one by looking at - // the respective size of the typed word and the suggestion if it matters sometime - // in the future. - suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq, - SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); - if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false; - } - if (null != node.mShortcutTargets) { - final int length = node.mShortcutTargets.size(); - for (int shortcutIndex = 0; shortcutIndex < length; ++shortcutIndex) { - final char[] shortcut = node.mShortcutTargets.get(shortcutIndex); - suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length), - finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); - if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false; - } - } - return true; - } - - /** - * Recursively traverse the tree for words that match the input. Input consists of - * a list of arrays. Each item in the list is one input character position. An input - * character is actually an array of multiple possible candidates. This function is not - * optimized for speed, assuming that the user dictionary will only be a few hundred words in - * size. - * @param roots node whose children have to be search for matches - * @param codes the input character codes - * @param word the word being composed as a possible match - * @param depth the depth of traversal - the length of the word being composed thus far - * @param completion whether the traversal is now in completion mode - meaning that we've - * exhausted the input and we're looking for all possible suffixes. - * @param snr current weight of the word being formed - * @param inputIndex position in the input characters. This can be off from the depth in - * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type - * "wouldve", it could be matching "would've", so the depth will be one more than the - * inputIndex - * @param suggestions the list in which to add suggestions - */ - // TODO: Share this routine with the native code for BinaryDictionary - private void getWordsRec(final NodeArray roots, final WordComposer codes, final char[] word, - final int depth, final boolean completion, final int snr, final int inputIndex, - final int skipPos, final ArrayList<SuggestedWordInfo> suggestions) { - final int count = roots.mLength; - final int codeSize = mInputLength; - // Optimization: Prune out words that are too long compared to how much was typed. - if (depth > mMaxDepth) { - return; - } - final int[] currentChars; - if (codeSize <= inputIndex) { - currentChars = null; - } else { - currentChars = mCodes[inputIndex]; - } - - for (int i = 0; i < count; i++) { - final Node node = roots.mData[i]; - final char c = node.mCode; - final char lowerC = toLowerCase(c); - final boolean terminal = node.mTerminal; - final NodeArray children = node.mChildren; - final int freq = node.mFrequency; - if (completion || currentChars == null) { - word[depth] = c; - if (terminal) { - final int finalFreq; - if (skipPos < 0) { - finalFreq = freq * snr; - } else { - finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength); - } - if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, suggestions)) { - // No space left in the queue, bail out - return; - } - } - if (children != null) { - getWordsRec(children, codes, word, depth + 1, true, snr, inputIndex, - skipPos, suggestions); - } - } else if ((c == Constants.CODE_SINGLE_QUOTE - && currentChars[0] != Constants.CODE_SINGLE_QUOTE) || depth == skipPos) { - // Skip the ' and continue deeper - word[depth] = c; - if (children != null) { - getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, - skipPos, suggestions); - } - } else { - // Don't use alternatives if we're looking for missing characters - final int alternativesSize = skipPos >= 0 ? 1 : currentChars.length; - for (int j = 0; j < alternativesSize; j++) { - final int addedAttenuation = (j > 0 ? 1 : 2); - final int currentChar = currentChars[j]; - if (currentChar == Constants.NOT_A_CODE) { - break; - } - if (currentChar == lowerC || currentChar == c) { - word[depth] = c; - - if (codeSize == inputIndex + 1) { - if (terminal) { - final int finalFreq; - if (skipPos < 0) { - finalFreq = freq * snr * addedAttenuation - * FULL_WORD_SCORE_MULTIPLIER; - } else { - finalFreq = computeSkippedWordFinalFreq(freq, - snr * addedAttenuation, mInputLength); - } - if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, - suggestions)) { - // No space left in the queue, bail out - return; - } - } - if (children != null) { - getWordsRec(children, codes, word, depth + 1, - true, snr * addedAttenuation, inputIndex + 1, - skipPos, suggestions); - } - } else if (children != null) { - getWordsRec(children, codes, word, depth + 1, - false, snr * addedAttenuation, inputIndex + 1, - skipPos, suggestions); - } - } - } - } - } - } - - public int setBigramAndGetFrequency(final String word0, final String word1, - final int frequency) { - return setBigramAndGetFrequency(word0, word1, frequency, null /* unused */); - } - - public int setBigramAndGetFrequency(final String word0, final String word1, - final ForgettingCurveParams fcp) { - return setBigramAndGetFrequency(word0, word1, 0 /* unused */, fcp); - } - - /** - * Adds bigrams to the in-memory trie structure that is being used to retrieve any word - * @param word0 the first word of this bigram - * @param word1 the second word of this bigram - * @param frequency frequency for this bigram - * @param fcp an instance of ForgettingCurveParams to use for decay policy - * @return returns the final bigram frequency - */ - private int setBigramAndGetFrequency(final String word0, final String word1, - final int frequency, final ForgettingCurveParams fcp) { - if (TextUtils.isEmpty(word0)) { - Log.e(TAG, "Invalid bigram previous word: " + word0); - return frequency; - } - // We don't want results to be different according to case of the looked up left hand side - // word. We do want however to return the correct case for the right hand side. - // So we want to squash the case of the left hand side, and preserve that of the right - // hand side word. - final String word0Lower = word0.toLowerCase(); - if (TextUtils.isEmpty(word0Lower) || TextUtils.isEmpty(word1)) { - Log.e(TAG, "Invalid bigram pair: " + word0 + ", " + word0Lower + ", " + word1); - return frequency; - } - final Node firstWord = searchWord(mRoots, word0Lower, 0, null); - final Node secondWord = searchWord(mRoots, word1, 0, null); - LinkedList<NextWord> bigrams = firstWord.mNGrams; - if (bigrams == null || bigrams.size() == 0) { - firstWord.mNGrams = CollectionUtils.newLinkedList(); - bigrams = firstWord.mNGrams; - } else { - for (NextWord nw : bigrams) { - if (nw.getWordNode() == secondWord) { - return nw.notifyTypedAgainAndGetFrequency(); - } - } - } - if (fcp != null) { - // history - firstWord.mNGrams.add(new NextHistoryWord(secondWord, fcp)); - } else { - firstWord.mNGrams.add(new NextStaticWord(secondWord, frequency)); - } - return frequency; - } - - /** - * Searches for the word and add the word if it does not exist. - * @return Returns the terminal node of the word we are searching for. - */ - private Node searchWord(final NodeArray children, final String word, final int depth, - final Node parentNode) { - final int wordLength = word.length(); - final char c = word.charAt(depth); - // Does children have the current character? - final int childrenLength = children.mLength; - Node childNode = null; - for (int i = 0; i < childrenLength; i++) { - final Node node = children.mData[i]; - if (node.mCode == c) { - childNode = node; - break; - } - } - if (childNode == null) { - childNode = new Node(); - childNode.mCode = c; - childNode.mParent = parentNode; - children.add(childNode); - } - if (wordLength == depth + 1) { - // Terminate this word - childNode.mTerminal = true; - return childNode; - } - if (childNode.mChildren == null) { - childNode.mChildren = new NodeArray(); - } - return searchWord(childNode.mChildren, word, depth + 1, childNode); - } - - private void runBigramReverseLookUp(final String previousWord, - final ArrayList<SuggestedWordInfo> suggestions) { - // Search for the lowercase version of the word only, because that's where bigrams - // store their sons. - final Node prevWord = searchNode(mRoots, previousWord.toLowerCase(), 0, - previousWord.length()); - if (prevWord != null && prevWord.mNGrams != null) { - reverseLookUp(prevWord.mNGrams, suggestions); - } - } - - // Local to reverseLookUp, but do not allocate each time. - private final char[] mLookedUpString = new char[Constants.DICTIONARY_MAX_WORD_LENGTH]; - - /** - * reverseLookUp retrieves the full word given a list of terminal nodes and adds those words - * to the suggestions list passed as an argument. - * @param terminalNodes list of terminal nodes we want to add - * @param suggestions the suggestion collection to add the word to - */ - private void reverseLookUp(final LinkedList<NextWord> terminalNodes, - final ArrayList<SuggestedWordInfo> suggestions) { - Node node; - int freq; - for (NextWord nextWord : terminalNodes) { - node = nextWord.getWordNode(); - freq = nextWord.getFrequency(); - int index = Constants.DICTIONARY_MAX_WORD_LENGTH; - do { - --index; - mLookedUpString[index] = node.mCode; - node = node.mParent; - } while (node != null && index > 0); - - // If node is null, we have a word longer than MAX_WORD_LENGTH in the dictionary. - // It's a little unclear how this can happen, but just in case it does it's safer - // to ignore the word in this case. - if (freq >= 0 && node == null) { - suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index, - Constants.DICTIONARY_MAX_WORD_LENGTH - index), - freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); - } - } - } - - /** - * Recursively search for the terminal node of the word. - * - * One iteration takes the full word to search for and the current index of the recursion. - * - * @param children the node of the trie to search under. - * @param word the word to search for. Only read [offset..length] so there may be trailing chars - * @param offset the index in {@code word} this recursion should operate on. - * @param length the length of the input word. - * @return Returns the terminal node of the word if the word exists - */ - private Node searchNode(final NodeArray children, final CharSequence word, final int offset, - final int length) { - final int count = children.mLength; - final char currentChar = word.charAt(offset); - for (int j = 0; j < count; j++) { - final Node node = children.mData[j]; - if (node.mCode == currentChar) { - if (offset == length - 1) { - if (node.mTerminal) { - return node; - } - } else { - if (node.mChildren != null) { - Node returnNode = searchNode(node.mChildren, word, offset + 1, length); - if (returnNode != null) return returnNode; - } - } - } - } - return null; - } - - public void clearDictionary() { - mRoots = new NodeArray(); - } - - private static char toLowerCase(final char c) { - char baseChar = c; - if (c < BASE_CHARS.length) { - baseChar = BASE_CHARS[c]; - } - if (baseChar >= 'A' && baseChar <= 'Z') { - return (char)(baseChar | 32); - } else if (baseChar > 127) { - return Character.toLowerCase(baseChar); - } - return baseChar; - } - - /** - * 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. - * - * cf. native/jni/src/utils/char_utils.cpp - */ - private static final char BASE_CHARS[] = { - /* U+0000 */ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - /* U+0008 */ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, - /* U+0010 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - /* U+0018 */ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, - /* U+0020 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - /* U+0028 */ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, - /* U+0030 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - /* U+0038 */ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, - /* U+0040 */ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - /* U+0048 */ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, - /* U+0050 */ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - /* U+0058 */ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, - /* U+0060 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - /* U+0068 */ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, - /* U+0070 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - /* U+0078 */ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, - /* U+0080 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - /* U+0088 */ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - /* U+0090 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - /* U+0098 */ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - /* U+00A0 */ 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - /* U+00A8 */ 0x0020, 0x00A9, 0x0061, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0020, - /* U+00B0 */ 0x00B0, 0x00B1, 0x0032, 0x0033, 0x0020, 0x03BC, 0x00B6, 0x00B7, - /* U+00B8 */ 0x0020, 0x0031, 0x006F, 0x00BB, 0x0031, 0x0031, 0x0033, 0x00BF, - /* U+00C0 */ 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00C6, 0x0043, - /* U+00C8 */ 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, - /* U+00D0 */ 0x00D0, 0x004E, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x00D7, - /* U+00D8 */ 0x004F, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00DE, 0x0073, - // U+00D8: Manually changed from 00D8 to 004F - // TODO: Check if it's really acceptable to consider Ø a diacritical variant of O - // U+00DF: Manually changed from 00DF to 0073 - /* U+00E0 */ 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00E6, 0x0063, - /* U+00E8 */ 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, - /* U+00F0 */ 0x00F0, 0x006E, 0x006F, 0x006F, 0x006F, 0x006F, 0x006F, 0x00F7, - /* U+00F8 */ 0x006F, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00FE, 0x0079, - // U+00F8: Manually changed from 00F8 to 006F - // TODO: Check if it's really acceptable to consider ø a diacritical variant of o - /* U+0100 */ 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063, - /* U+0108 */ 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064, - /* U+0110 */ 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065, - /* U+0118 */ 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, - /* U+0120 */ 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, - /* U+0128 */ 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, - /* U+0130 */ 0x0049, 0x0131, 0x0049, 0x0069, 0x004A, 0x006A, 0x004B, 0x006B, - /* U+0138 */ 0x0138, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C, - /* U+0140 */ 0x006C, 0x004C, 0x006C, 0x004E, 0x006E, 0x004E, 0x006E, 0x004E, - // U+0141: Manually changed from 0141 to 004C - // U+0142: Manually changed from 0142 to 006C - /* U+0148 */ 0x006E, 0x02BC, 0x014A, 0x014B, 0x004F, 0x006F, 0x004F, 0x006F, - /* U+0150 */ 0x004F, 0x006F, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072, - /* U+0158 */ 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073, - /* U+0160 */ 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167, - /* U+0168 */ 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, - /* U+0170 */ 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079, - /* U+0178 */ 0x0059, 0x005A, 0x007A, 0x005A, 0x007A, 0x005A, 0x007A, 0x0073, - /* U+0180 */ 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, - /* U+0188 */ 0x0188, 0x0189, 0x018A, 0x018B, 0x018C, 0x018D, 0x018E, 0x018F, - /* U+0190 */ 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, - /* U+0198 */ 0x0198, 0x0199, 0x019A, 0x019B, 0x019C, 0x019D, 0x019E, 0x019F, - /* U+01A0 */ 0x004F, 0x006F, 0x01A2, 0x01A3, 0x01A4, 0x01A5, 0x01A6, 0x01A7, - /* U+01A8 */ 0x01A8, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AD, 0x01AE, 0x0055, - /* U+01B0 */ 0x0075, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5, 0x01B6, 0x01B7, - /* U+01B8 */ 0x01B8, 0x01B9, 0x01BA, 0x01BB, 0x01BC, 0x01BD, 0x01BE, 0x01BF, - /* U+01C0 */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x0044, 0x0044, 0x0064, 0x004C, - /* U+01C8 */ 0x004C, 0x006C, 0x004E, 0x004E, 0x006E, 0x0041, 0x0061, 0x0049, - /* U+01D0 */ 0x0069, 0x004F, 0x006F, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, - // U+01D5: Manually changed from 00DC to 0055 - // U+01D6: Manually changed from 00FC to 0075 - // U+01D7: Manually changed from 00DC to 0055 - /* U+01D8 */ 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x01DD, 0x0041, 0x0061, - // U+01D8: Manually changed from 00FC to 0075 - // U+01D9: Manually changed from 00DC to 0055 - // U+01DA: Manually changed from 00FC to 0075 - // U+01DB: Manually changed from 00DC to 0055 - // U+01DC: Manually changed from 00FC to 0075 - // U+01DE: Manually changed from 00C4 to 0041 - // U+01DF: Manually changed from 00E4 to 0061 - /* U+01E0 */ 0x0041, 0x0061, 0x00C6, 0x00E6, 0x01E4, 0x01E5, 0x0047, 0x0067, - // U+01E0: Manually changed from 0226 to 0041 - // U+01E1: Manually changed from 0227 to 0061 - /* U+01E8 */ 0x004B, 0x006B, 0x004F, 0x006F, 0x004F, 0x006F, 0x01B7, 0x0292, - // U+01EC: Manually changed from 01EA to 004F - // U+01ED: Manually changed from 01EB to 006F - /* U+01F0 */ 0x006A, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01F6, 0x01F7, - /* U+01F8 */ 0x004E, 0x006E, 0x0041, 0x0061, 0x00C6, 0x00E6, 0x004F, 0x006F, - // U+01FA: Manually changed from 00C5 to 0041 - // U+01FB: Manually changed from 00E5 to 0061 - // U+01FE: Manually changed from 00D8 to 004F - // TODO: Check if it's really acceptable to consider Ø a diacritical variant of O - // U+01FF: Manually changed from 00F8 to 006F - // TODO: Check if it's really acceptable to consider ø a diacritical variant of o - /* U+0200 */ 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065, - /* U+0208 */ 0x0049, 0x0069, 0x0049, 0x0069, 0x004F, 0x006F, 0x004F, 0x006F, - /* U+0210 */ 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075, - /* U+0218 */ 0x0053, 0x0073, 0x0054, 0x0074, 0x021C, 0x021D, 0x0048, 0x0068, - /* U+0220 */ 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061, - /* U+0228 */ 0x0045, 0x0065, 0x004F, 0x006F, 0x004F, 0x006F, 0x004F, 0x006F, - // U+022A: Manually changed from 00D6 to 004F - // U+022B: Manually changed from 00F6 to 006F - // U+022C: Manually changed from 00D5 to 004F - // U+022D: Manually changed from 00F5 to 006F - /* U+0230 */ 0x004F, 0x006F, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237, - // U+0230: Manually changed from 022E to 004F - // U+0231: Manually changed from 022F to 006F - /* U+0238 */ 0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F, - /* U+0240 */ 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, - /* U+0248 */ 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F, - /* U+0250 */ 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, - /* U+0258 */ 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, 0x025D, 0x025E, 0x025F, - /* U+0260 */ 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, - /* U+0268 */ 0x0268, 0x0269, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x026F, - /* U+0270 */ 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, - /* U+0278 */ 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, - /* U+0280 */ 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, - /* U+0288 */ 0x0288, 0x0289, 0x028A, 0x028B, 0x028C, 0x028D, 0x028E, 0x028F, - /* U+0290 */ 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, - /* U+0298 */ 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, - /* U+02A0 */ 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7, - /* U+02A8 */ 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC, 0x02AD, 0x02AE, 0x02AF, - /* U+02B0 */ 0x0068, 0x0266, 0x006A, 0x0072, 0x0279, 0x027B, 0x0281, 0x0077, - /* U+02B8 */ 0x0079, 0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF, - /* U+02C0 */ 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, 0x02C5, 0x02C6, 0x02C7, - /* U+02C8 */ 0x02C8, 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF, - /* U+02D0 */ 0x02D0, 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, - /* U+02D8 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02DE, 0x02DF, - /* U+02E0 */ 0x0263, 0x006C, 0x0073, 0x0078, 0x0295, 0x02E5, 0x02E6, 0x02E7, - /* U+02E8 */ 0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF, - /* U+02F0 */ 0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7, - /* U+02F8 */ 0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x02FE, 0x02FF, - /* U+0300 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - /* U+0308 */ 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, - /* U+0310 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - /* U+0318 */ 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, - /* U+0320 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - /* U+0328 */ 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, - /* U+0330 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - /* U+0338 */ 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, - /* U+0340 */ 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347, - /* U+0348 */ 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, - /* U+0350 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - /* U+0358 */ 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, - /* U+0360 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - /* U+0368 */ 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, - /* U+0370 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x02B9, 0x0375, 0x0376, 0x0377, - /* U+0378 */ 0x0378, 0x0379, 0x0020, 0x037B, 0x037C, 0x037D, 0x003B, 0x037F, - /* U+0380 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00A8, 0x0391, 0x00B7, - /* U+0388 */ 0x0395, 0x0397, 0x0399, 0x038B, 0x039F, 0x038D, 0x03A5, 0x03A9, - /* U+0390 */ 0x03CA, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - /* U+0398 */ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, - /* U+03A0 */ 0x03A0, 0x03A1, 0x03A2, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, - /* U+03A8 */ 0x03A8, 0x03A9, 0x0399, 0x03A5, 0x03B1, 0x03B5, 0x03B7, 0x03B9, - /* U+03B0 */ 0x03CB, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, - /* U+03B8 */ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, - /* U+03C0 */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, - /* U+03C8 */ 0x03C8, 0x03C9, 0x03B9, 0x03C5, 0x03BF, 0x03C5, 0x03C9, 0x03CF, - /* U+03D0 */ 0x03B2, 0x03B8, 0x03A5, 0x03D2, 0x03D2, 0x03C6, 0x03C0, 0x03D7, - /* U+03D8 */ 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF, - /* U+03E0 */ 0x03E0, 0x03E1, 0x03E2, 0x03E3, 0x03E4, 0x03E5, 0x03E6, 0x03E7, - /* U+03E8 */ 0x03E8, 0x03E9, 0x03EA, 0x03EB, 0x03EC, 0x03ED, 0x03EE, 0x03EF, - /* U+03F0 */ 0x03BA, 0x03C1, 0x03C2, 0x03F3, 0x0398, 0x03B5, 0x03F6, 0x03F7, - /* U+03F8 */ 0x03F8, 0x03A3, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF, - /* U+0400 */ 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406, - /* U+0408 */ 0x0408, 0x0409, 0x040A, 0x040B, 0x041A, 0x0418, 0x0423, 0x040F, - /* U+0410 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - /* U+0418 */ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, - // U+0419: Manually changed from 0418 to 0419 - /* U+0420 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - /* U+0428 */ 0x0428, 0x0429, 0x042C, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, - // U+042A: Manually changed from 042A to 042C - /* U+0430 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - /* U+0438 */ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - // U+0439: Manually changed from 0438 to 0439 - /* U+0440 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - /* U+0448 */ 0x0448, 0x0449, 0x044C, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, - // U+044A: Manually changed from 044A to 044C - /* U+0450 */ 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456, - /* U+0458 */ 0x0458, 0x0459, 0x045A, 0x045B, 0x043A, 0x0438, 0x0443, 0x045F, - /* U+0460 */ 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, - /* U+0468 */ 0x0468, 0x0469, 0x046A, 0x046B, 0x046C, 0x046D, 0x046E, 0x046F, - /* U+0470 */ 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475, - /* U+0478 */ 0x0478, 0x0479, 0x047A, 0x047B, 0x047C, 0x047D, 0x047E, 0x047F, - /* U+0480 */ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, - /* U+0488 */ 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F, - /* U+0490 */ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, - /* U+0498 */ 0x0498, 0x0499, 0x049A, 0x049B, 0x049C, 0x049D, 0x049E, 0x049F, - /* U+04A0 */ 0x04A0, 0x04A1, 0x04A2, 0x04A3, 0x04A4, 0x04A5, 0x04A6, 0x04A7, - /* U+04A8 */ 0x04A8, 0x04A9, 0x04AA, 0x04AB, 0x04AC, 0x04AD, 0x04AE, 0x04AF, - /* U+04B0 */ 0x04B0, 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, - /* U+04B8 */ 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, - /* U+04C0 */ 0x04C0, 0x0416, 0x0436, 0x04C3, 0x04C4, 0x04C5, 0x04C6, 0x04C7, - /* U+04C8 */ 0x04C8, 0x04C9, 0x04CA, 0x04CB, 0x04CC, 0x04CD, 0x04CE, 0x04CF, - /* U+04D0 */ 0x0410, 0x0430, 0x0410, 0x0430, 0x04D4, 0x04D5, 0x0415, 0x0435, - /* U+04D8 */ 0x04D8, 0x04D9, 0x04D8, 0x04D9, 0x0416, 0x0436, 0x0417, 0x0437, - /* U+04E0 */ 0x04E0, 0x04E1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041E, 0x043E, - /* U+04E8 */ 0x04E8, 0x04E9, 0x04E8, 0x04E9, 0x042D, 0x044D, 0x0423, 0x0443, - /* U+04F0 */ 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04F6, 0x04F7, - /* U+04F8 */ 0x042B, 0x044B, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, - }; -} diff --git a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java new file mode 100644 index 000000000..567087c81 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 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.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; + +import com.android.inputmethod.latin.utils.DialogUtils; +import com.android.inputmethod.latin.utils.ImportantNoticeUtils; + +/** + * The dialog box that shows the important notice contents. + */ +public final class ImportantNoticeDialog extends AlertDialog implements OnClickListener { + public interface ImportantNoticeDialogListener { + public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion); + public void onClickSettingsOfImportantNoticeDialog(final int nextVersion); + } + + private final ImportantNoticeDialogListener mListener; + private final int mNextImportantNoticeVersion; + + public ImportantNoticeDialog( + final Context context, final ImportantNoticeDialogListener listener) { + super(DialogUtils.getPlatformDialogThemeContext(context)); + mListener = listener; + mNextImportantNoticeVersion = ImportantNoticeUtils.getNextImportantNoticeVersion(context); + setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context)); + // Create buttons and set listeners. + setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), this); + if (shouldHaveSettingsButton()) { + setButton(BUTTON_NEGATIVE, context.getString(R.string.go_to_settings), this); + } + // This dialog is cancelable by pressing back key. See {@link #onBackPress()}. + setCancelable(true /* cancelable */); + setCanceledOnTouchOutside(false /* cancelable */); + } + + private boolean shouldHaveSettingsButton() { + return mNextImportantNoticeVersion + == ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS; + } + + private void userAcknowledged() { + ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext()); + mListener.onUserAcknowledgmentOfImportantNoticeDialog(mNextImportantNoticeVersion); + } + + @Override + public void onClick(final DialogInterface dialog, final int which) { + if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) { + mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion); + } + userAcknowledged(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + userAcknowledged(); + } +} diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index 8caf6f17f..726b3d141 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -20,22 +20,29 @@ import android.text.InputType; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.StringUtils; +import java.util.ArrayList; +import java.util.Arrays; + /** * Class to hold attributes of the input field. */ public final class InputAttributes { private final String TAG = InputAttributes.class.getSimpleName(); + final public String mTargetApplicationPackageName; final public boolean mInputTypeNoAutoCorrect; + final public boolean mIsPasswordField; final public boolean mIsSettingsSuggestionStripOn; final public boolean mApplicationSpecifiedCompletionOn; final public boolean mShouldInsertSpacesAutomatically; final private int mInputType; public InputAttributes(final EditorInfo editorInfo, final boolean isFullscreenMode) { + mTargetApplicationPackageName = null != editorInfo ? editorInfo.packageName : null; final int inputType = null != editorInfo ? editorInfo.inputType : 0; final int inputClass = inputType & InputType.TYPE_MASK_CLASS; mInputType = inputType; @@ -52,55 +59,50 @@ public final class InputAttributes { } 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)); + + " imeOptions=0x%08x", inputType, editorInfo.imeOptions)); } + mIsPasswordField = false; mIsSettingsSuggestionStripOn = false; mInputTypeNoAutoCorrect = false; mApplicationSpecifiedCompletionOn = false; mShouldInsertSpacesAutomatically = 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); - - // TODO: Have a helper method in InputTypeUtils - // Make sure that passwords are not displayed in {@link SuggestionStripView}. - if (InputTypeUtils.isPasswordInputType(inputType) - || InputTypeUtils.isVisiblePasswordInputType(inputType) - || InputTypeUtils.isEmailVariation(variation) - || InputType.TYPE_TEXT_VARIATION_URI == variation - || InputType.TYPE_TEXT_VARIATION_FILTER == variation - || flagNoSuggestions - || flagAutoComplete) { - mIsSettingsSuggestionStripOn = false; - } else { - mIsSettingsSuggestionStripOn = true; - } + return; + } + // inputClass == InputType.TYPE_CLASS_TEXT + 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); - mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType); - - // 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; - } + mIsPasswordField = InputTypeUtils.isPasswordInputType(inputType) + || InputTypeUtils.isVisiblePasswordInputType(inputType); + // TODO: Have a helper method in InputTypeUtils + // Make sure that passwords are not displayed in {@link SuggestionStripView}. + final boolean noSuggestionStrip = mIsPasswordField + || InputTypeUtils.isEmailVariation(variation) + || InputType.TYPE_TEXT_VARIATION_URI == variation + || InputType.TYPE_TEXT_VARIATION_FILTER == variation + || flagNoSuggestions + || flagAutoComplete; + mIsSettingsSuggestionStripOn = !noSuggestionStrip; - mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode; - } + mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType); + + // 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 + mInputTypeNoAutoCorrect = + (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT && !flagAutoCorrect) + || flagNoSuggestions + || (!flagAutoCorrect && !flagMultiLine); + + mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode; } public boolean isTypeNull() { @@ -113,99 +115,144 @@ public final class InputAttributes { @SuppressWarnings("unused") private void dumpFlags(final int inputType) { - Log.i(TAG, "Input class:"); final int inputClass = inputType & InputType.TYPE_MASK_CLASS; - if (inputClass == InputType.TYPE_CLASS_TEXT) - Log.i(TAG, " TYPE_CLASS_TEXT"); - if (inputClass == InputType.TYPE_CLASS_PHONE) - Log.i(TAG, " TYPE_CLASS_PHONE"); - if (inputClass == InputType.TYPE_CLASS_NUMBER) - Log.i(TAG, " TYPE_CLASS_NUMBER"); - if (inputClass == InputType.TYPE_CLASS_DATETIME) - Log.i(TAG, " TYPE_CLASS_DATETIME"); - Log.i(TAG, "Variation:"); - switch (InputType.TYPE_MASK_VARIATION & inputType) { - case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT: - Log.i(TAG, " TYPE_TEXT_VARIATION_EMAIL_SUBJECT"); - break; - case InputType.TYPE_TEXT_VARIATION_FILTER: - Log.i(TAG, " TYPE_TEXT_VARIATION_FILTER"); - break; - case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE: - Log.i(TAG, " TYPE_TEXT_VARIATION_LONG_MESSAGE"); - break; - case InputType.TYPE_TEXT_VARIATION_NORMAL: - Log.i(TAG, " TYPE_TEXT_VARIATION_NORMAL"); - break; - case InputType.TYPE_TEXT_VARIATION_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_PASSWORD"); - break; - case InputType.TYPE_TEXT_VARIATION_PERSON_NAME: - Log.i(TAG, " TYPE_TEXT_VARIATION_PERSON_NAME"); - break; - case InputType.TYPE_TEXT_VARIATION_PHONETIC: - Log.i(TAG, " TYPE_TEXT_VARIATION_PHONETIC"); - break; - case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_POSTAL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE: - Log.i(TAG, " TYPE_TEXT_VARIATION_SHORT_MESSAGE"); - break; - case InputType.TYPE_TEXT_VARIATION_URI: - Log.i(TAG, " TYPE_TEXT_VARIATION_URI"); - break; - case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_VISIBLE_PASSWORD"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS"); - break; - case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD: - Log.i(TAG, " TYPE_TEXT_VARIATION_WEB_PASSWORD"); - break; - default: - Log.i(TAG, " Unknown variation"); - break; + final String inputClassString = toInputClassString(inputClass); + final String variationString = toVariationString( + inputClass, inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + final String flagsString = toFlagsString(inputType & InputType.TYPE_MASK_FLAGS); + Log.i(TAG, "Input class: " + inputClassString); + Log.i(TAG, "Variation: " + variationString); + Log.i(TAG, "Flags: " + flagsString); + } + + private static String toInputClassString(final int inputClass) { + switch (inputClass) { + case InputType.TYPE_CLASS_TEXT: + return "TYPE_CLASS_TEXT"; + case InputType.TYPE_CLASS_PHONE: + return "TYPE_CLASS_PHONE"; + case InputType.TYPE_CLASS_NUMBER: + return "TYPE_CLASS_NUMBER"; + case InputType.TYPE_CLASS_DATETIME: + return "TYPE_CLASS_DATETIME"; + default: + return String.format("unknownInputClass<0x%08x>", inputClass); + } + } + + private static String toVariationString(final int inputClass, final int variation) { + switch (inputClass) { + case InputType.TYPE_CLASS_TEXT: + return toTextVariationString(variation); + case InputType.TYPE_CLASS_NUMBER: + return toNumberVariationString(variation); + case InputType.TYPE_CLASS_DATETIME: + return toDatetimeVariationString(variation); + default: + return ""; } - Log.i(TAG, "Flags:"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)) - Log.i(TAG, " TYPE_TEXT_FLAG_NO_SUGGESTIONS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE)) - Log.i(TAG, " TYPE_TEXT_FLAG_MULTI_LINE"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE)) - Log.i(TAG, " TYPE_TEXT_FLAG_IME_MULTI_LINE"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_WORDS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_SENTENCES"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)) - Log.i(TAG, " TYPE_TEXT_FLAG_CAP_CHARACTERS"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)) - Log.i(TAG, " TYPE_TEXT_FLAG_AUTO_CORRECT"); - if (0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)) - Log.i(TAG, " TYPE_TEXT_FLAG_AUTO_COMPLETE"); + } + + private static String toTextVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS: + return " TYPE_TEXT_VARIATION_EMAIL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT: + return "TYPE_TEXT_VARIATION_EMAIL_SUBJECT"; + case InputType.TYPE_TEXT_VARIATION_FILTER: + return "TYPE_TEXT_VARIATION_FILTER"; + case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE: + return "TYPE_TEXT_VARIATION_LONG_MESSAGE"; + case InputType.TYPE_TEXT_VARIATION_NORMAL: + return "TYPE_TEXT_VARIATION_NORMAL"; + case InputType.TYPE_TEXT_VARIATION_PASSWORD: + return "TYPE_TEXT_VARIATION_PASSWORD"; + case InputType.TYPE_TEXT_VARIATION_PERSON_NAME: + return "TYPE_TEXT_VARIATION_PERSON_NAME"; + case InputType.TYPE_TEXT_VARIATION_PHONETIC: + return "TYPE_TEXT_VARIATION_PHONETIC"; + case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS: + return "TYPE_TEXT_VARIATION_POSTAL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE: + return "TYPE_TEXT_VARIATION_SHORT_MESSAGE"; + case InputType.TYPE_TEXT_VARIATION_URI: + return "TYPE_TEXT_VARIATION_URI"; + case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD: + return "TYPE_TEXT_VARIATION_VISIBLE_PASSWORD"; + case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT: + return "TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"; + case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS: + return "TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS"; + case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD: + return "TYPE_TEXT_VARIATION_WEB_PASSWORD"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toNumberVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_NUMBER_VARIATION_NORMAL: + return "TYPE_NUMBER_VARIATION_NORMAL"; + case InputType.TYPE_NUMBER_VARIATION_PASSWORD: + return "TYPE_NUMBER_VARIATION_PASSWORD"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toDatetimeVariationString(final int variation) { + switch (variation) { + case InputType.TYPE_DATETIME_VARIATION_NORMAL: + return "TYPE_DATETIME_VARIATION_NORMAL"; + case InputType.TYPE_DATETIME_VARIATION_DATE: + return "TYPE_DATETIME_VARIATION_DATE"; + case InputType.TYPE_DATETIME_VARIATION_TIME: + return "TYPE_DATETIME_VARIATION_TIME"; + default: + return String.format("unknownVariation<0x%08x>", variation); + } + } + + private static String toFlagsString(final int flags) { + final ArrayList<String> flagsArray = CollectionUtils.newArrayList(); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)) + flagsArray.add("TYPE_TEXT_FLAG_NO_SUGGESTIONS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_MULTI_LINE)) + flagsArray.add("TYPE_TEXT_FLAG_MULTI_LINE"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE)) + flagsArray.add("TYPE_TEXT_FLAG_IME_MULTI_LINE"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_WORDS)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_WORDS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_SENTENCES"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)) + flagsArray.add("TYPE_TEXT_FLAG_CAP_CHARACTERS"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)) + flagsArray.add("TYPE_TEXT_FLAG_AUTO_CORRECT"); + if (0 != (flags & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)) + flagsArray.add("TYPE_TEXT_FLAG_AUTO_COMPLETE"); + return flagsArray.isEmpty() ? "" : Arrays.toString(flagsArray.toArray()); } // Pretty print @Override public String toString() { - return "\n mInputTypeNoAutoCorrect = " + mInputTypeNoAutoCorrect - + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn - + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn; + return String.format( + "%s: inputType=0x%08x%s%s%s%s%s targetApp=%s\n", getClass().getSimpleName(), + mInputType, + (mInputTypeNoAutoCorrect ? " noAutoCorrect" : ""), + (mIsPasswordField ? " password" : ""), + (mIsSettingsSuggestionStripOn ? " suggestionStrip" : ""), + (mApplicationSpecifiedCompletionOn ? " appSpecified" : ""), + (mShouldInsertSpacesAutomatically ? " insertSpaces" : ""), + mTargetApplicationPackageName); } - public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo editorInfo) { + public static boolean inPrivateImeOptions(final String packageName, final String key, + final EditorInfo editorInfo) { if (editorInfo == null) return false; - final String findingKey = (packageName != null) ? packageName + "." + key - : key; + final String findingKey = (packageName != null) ? packageName + "." + key : key; return StringUtils.containsInCommaSplittableText(findingKey, editorInfo.privateImeOptions); } } diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java index 2e638aaf3..47bc6b078 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -16,14 +16,17 @@ package com.android.inputmethod.latin; +import android.util.Log; +import android.util.SparseIntArray; + import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.utils.ResizableIntArray; -import android.util.Log; - // TODO: This class is not thread-safe. public final class InputPointers { private static final String TAG = InputPointers.class.getSimpleName(); + private static final boolean DEBUG_TIME = false; + private final int mDefaultCapacity; private final ResizableIntArray mXCoordinates; private final ResizableIntArray mYCoordinates; @@ -38,11 +41,29 @@ public final class InputPointers { mTimes = new ResizableIntArray(defaultCapacity); } - public void addPointer(int index, int x, int y, int pointerId, int time) { - mXCoordinates.add(index, x); - mYCoordinates.add(index, y); - mPointerIds.add(index, pointerId); - mTimes.add(index, time); + private void fillWithLastTimeUntil(final int index) { + final int fromIndex = mTimes.getLength(); + // Fill the gap with the latest time. + // See {@link #getTime(int)} and {@link #isValidTimeStamps()}. + if (fromIndex <= 0) { + return; + } + final int fillLength = index - fromIndex + 1; + if (fillLength <= 0) { + return; + } + final int lastTime = mTimes.get(fromIndex - 1); + mTimes.fill(lastTime, fromIndex, fillLength); + } + + public void addPointerAt(int index, int x, int y, int pointerId, int time) { + mXCoordinates.addAt(index, x); + mYCoordinates.addAt(index, y); + mPointerIds.addAt(index, pointerId); + if (LatinImeLogger.sDBG || DEBUG_TIME) { + fillWithLastTimeUntil(index); + } + mTimes.addAt(index, time); } @UsedForTesting @@ -68,23 +89,6 @@ public final class InputPointers { } /** - * Append the pointers in the specified {@link InputPointers} to the end of this. - * @param src the source {@link InputPointers} to read the data from. - * @param startPos the starting index of the pointers in {@code src}. - * @param length the number of pointers to be appended. - */ - @UsedForTesting - void append(InputPointers src, int startPos, int length) { - if (length == 0) { - return; - } - mXCoordinates.append(src.mXCoordinates, startPos, length); - mYCoordinates.append(src.mYCoordinates, startPos, length); - mPointerIds.append(src.mPointerIds, startPos, length); - mTimes.append(src.mTimes, startPos, length); - } - - /** * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray} * to the end of this. * @param pointerId the pointer id of the source. @@ -141,7 +145,7 @@ public final class InputPointers { } public int[] getTimes() { - if (LatinImeLogger.sDBG) { + if (LatinImeLogger.sDBG || DEBUG_TIME) { if (!isValidTimeStamps()) { throw new RuntimeException("Time stamps are invalid."); } @@ -157,14 +161,21 @@ public final class InputPointers { private boolean isValidTimeStamps() { final int[] times = mTimes.getPrimitiveArray(); - for (int i = 1; i < getPointerSize(); ++i) { - if (times[i] < times[i - 1]) { + final int[] pointerIds = mPointerIds.getPrimitiveArray(); + final SparseIntArray lastTimeOfPointers = new SparseIntArray(); + final int size = getPointerSize(); + for (int i = 0; i < size; ++i) { + final int pointerId = pointerIds[i]; + final int time = times[i]; + final int lastTime = lastTimeOfPointers.get(pointerId, time); + if (time < lastTime) { // dump - for (int j = 0; j < times.length; ++j) { + for (int j = 0; j < size; ++j) { Log.d(TAG, "--- (" + j + ") " + times[j]); } return false; } + lastTimeOfPointers.put(pointerId, time); } return true; } diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java index 81ccf83d8..ea7859e60 100644 --- a/java/src/com/android/inputmethod/latin/InputView.java +++ b/java/src/com/android/inputmethod/latin/InputView.java @@ -23,87 +23,210 @@ import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; -public final class InputView extends LinearLayout { - private View mSuggestionStripView; - private View mKeyboardView; - private int mKeyboardTopPadding; +import com.android.inputmethod.keyboard.MainKeyboardView; +import com.android.inputmethod.latin.suggestions.MoreSuggestionsView; +import com.android.inputmethod.latin.suggestions.SuggestionStripView; - private boolean mIsForwardingEvent; +public final class InputView extends LinearLayout { private final Rect mInputViewRect = new Rect(); - private final Rect mEventForwardingRect = new Rect(); - private final Rect mEventReceivingRect = new Rect(); + private KeyboardTopPaddingForwarder mKeyboardTopPaddingForwarder; + private MoreSuggestionsViewCanceler mMoreSuggestionsViewCanceler; + private MotionEventForwarder<?, ?> mActiveForwarder; public InputView(final Context context, final AttributeSet attrs) { super(context, attrs, 0); } - public void setKeyboardGeometry(final int keyboardTopPadding) { - mKeyboardTopPadding = keyboardTopPadding; - } - @Override protected void onFinishInflate() { - mSuggestionStripView = findViewById(R.id.suggestion_strip_view); - mKeyboardView = findViewById(R.id.keyboard_view); + final SuggestionStripView suggestionStripView = + (SuggestionStripView)findViewById(R.id.suggestion_strip_view); + final MainKeyboardView mainKeyboardView = + (MainKeyboardView)findViewById(R.id.keyboard_view); + mKeyboardTopPaddingForwarder = new KeyboardTopPaddingForwarder( + mainKeyboardView, suggestionStripView); + mMoreSuggestionsViewCanceler = new MoreSuggestionsViewCanceler( + mainKeyboardView, suggestionStripView); + } + + public void setKeyboardTopPadding(final int keyboardTopPadding) { + mKeyboardTopPaddingForwarder.setKeyboardTopPadding(keyboardTopPadding); } @Override - public boolean dispatchTouchEvent(final MotionEvent me) { - if (mSuggestionStripView.getVisibility() != VISIBLE - || mKeyboardView.getVisibility() != VISIBLE) { - return super.dispatchTouchEvent(me); - } + public boolean onInterceptTouchEvent(final MotionEvent me) { + final Rect rect = mInputViewRect; + getGlobalVisibleRect(rect); + final int index = me.getActionIndex(); + final int x = (int)me.getX(index) + rect.left; + final int y = (int)me.getY(index) + rect.top; // The touch events that hit the top padding of keyboard should be forwarded to // {@link SuggestionStripView}. + if (mKeyboardTopPaddingForwarder.onInterceptTouchEvent(x, y, me)) { + mActiveForwarder = mKeyboardTopPaddingForwarder; + return true; + } + + // To cancel {@link MoreSuggestionsView}, we should intercept a touch event to + // {@link MainKeyboardView} and dismiss the {@link MoreSuggestionsView}. + if (mMoreSuggestionsViewCanceler.onInterceptTouchEvent(x, y, me)) { + mActiveForwarder = mMoreSuggestionsViewCanceler; + return true; + } + + mActiveForwarder = null; + return false; + } + + @Override + public boolean onTouchEvent(final MotionEvent me) { + if (mActiveForwarder == null) { + return super.onTouchEvent(me); + } + final Rect rect = mInputViewRect; - this.getGlobalVisibleRect(rect); - final int x = (int)me.getX() + rect.left; - final int y = (int)me.getY() + rect.top; + getGlobalVisibleRect(rect); + final int index = me.getActionIndex(); + final int x = (int)me.getX(index) + rect.left; + final int y = (int)me.getY(index) + rect.top; + return mActiveForwarder.onTouchEvent(x, y, me); + } - final Rect forwardingRect = mEventForwardingRect; - mKeyboardView.getGlobalVisibleRect(forwardingRect); - if (!mIsForwardingEvent && !forwardingRect.contains(x, y)) { - return super.dispatchTouchEvent(me); + /** + * This class forwards series of {@link MotionEvent}s from <code>SenderView</code> to + * <code>ReceiverView</code>. + * + * @param <SenderView> a {@link View} that may send a {@link MotionEvent} to <ReceiverView>. + * @param <ReceiverView> a {@link View} that receives forwarded {@link MotionEvent} from + * <SenderView>. + */ + private static abstract class + MotionEventForwarder<SenderView extends View, ReceiverView extends View> { + protected final SenderView mSenderView; + protected final ReceiverView mReceiverView; + + protected final Rect mEventSendingRect = new Rect(); + protected final Rect mEventReceivingRect = new Rect(); + + public MotionEventForwarder(final SenderView senderView, final ReceiverView receiverView) { + mSenderView = senderView; + mReceiverView = receiverView; } - final int forwardingLimitY = forwardingRect.top + mKeyboardTopPadding; - boolean sendToTarget = false; + // Return true if a touch event of global coordinate x, y needs to be forwarded. + protected abstract boolean needsToForward(final int x, final int y); - switch (me.getAction()) { - case MotionEvent.ACTION_DOWN: - if (y < forwardingLimitY) { - // This down event and further move and up events should be forwarded to the target. - mIsForwardingEvent = true; - sendToTarget = true; + // Translate global x-coordinate to <code>ReceiverView</code> local coordinate. + protected int translateX(final int x) { + return x - mEventReceivingRect.left; + } + + // Translate global y-coordinate to <code>ReceiverView</code> local coordinate. + protected int translateY(final int y) { + return y - mEventReceivingRect.top; + } + + // Callback when a {@link MotionEvent} is forwarded. + protected void onForwardingEvent(final MotionEvent me) {} + + // Returns true if a {@link MotionEvent} is needed to be forwarded to + // <code>ReceiverView</code>. Otherwise returns false. + public boolean onInterceptTouchEvent(final int x, final int y, final MotionEvent me) { + // Forwards a {link MotionEvent} only if both <code>SenderView</code> and + // <code>ReceiverView</code> are visible. + if (mSenderView.getVisibility() != View.VISIBLE || + mReceiverView.getVisibility() != View.VISIBLE) { + return false; + } + mSenderView.getGlobalVisibleRect(mEventSendingRect); + if (!mEventSendingRect.contains(x, y)) { + return false; } - break; - case MotionEvent.ACTION_MOVE: - sendToTarget = mIsForwardingEvent; - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - sendToTarget = mIsForwardingEvent; - mIsForwardingEvent = false; - break; - } - - if (!sendToTarget) { - return super.dispatchTouchEvent(me); - } - - final Rect receivingRect = mEventReceivingRect; - mSuggestionStripView.getGlobalVisibleRect(receivingRect); - final int translatedX = x - receivingRect.left; - final int translatedY; - if (y < forwardingLimitY) { - // The forwarded event should have coordinates that are inside of the target. - translatedY = Math.min(y - receivingRect.top, receivingRect.height() - 1); - } else { - translatedY = y - receivingRect.top; - } - me.setLocation(translatedX, translatedY); - mSuggestionStripView.dispatchTouchEvent(me); - return true; + + if (me.getActionMasked() == MotionEvent.ACTION_DOWN) { + // If the down event happens in the forwarding area, successive + // {@link MotionEvent}s should be forwarded to <code>ReceiverView</code>. + if (needsToForward(x, y)) { + return true; + } + } + + return false; + } + + // Returns true if a {@link MotionEvent} is forwarded to <code>ReceiverView</code>. + // Otherwise returns false. + public boolean onTouchEvent(final int x, final int y, final MotionEvent me) { + mReceiverView.getGlobalVisibleRect(mEventReceivingRect); + // Translate global coordinates to <code>ReceiverView</code> local coordinates. + me.setLocation(translateX(x), translateY(y)); + mReceiverView.dispatchTouchEvent(me); + onForwardingEvent(me); + return true; + } + } + + /** + * This class forwards {@link MotionEvent}s happened in the top padding of + * {@link MainKeyboardView} to {@link SuggestionStripView}. + */ + private static class KeyboardTopPaddingForwarder + extends MotionEventForwarder<MainKeyboardView, SuggestionStripView> { + private int mKeyboardTopPadding; + + public KeyboardTopPaddingForwarder(final MainKeyboardView mainKeyboardView, + final SuggestionStripView suggestionStripView) { + super(mainKeyboardView, suggestionStripView); + } + + public void setKeyboardTopPadding(final int keyboardTopPadding) { + mKeyboardTopPadding = keyboardTopPadding; + } + + private boolean isInKeyboardTopPadding(final int y) { + return y < mEventSendingRect.top + mKeyboardTopPadding; + } + + @Override + protected boolean needsToForward(final int x, final int y) { + return isInKeyboardTopPadding(y); + } + + @Override + protected int translateY(final int y) { + final int translatedY = super.translateY(y); + if (isInKeyboardTopPadding(y)) { + // The forwarded event should have coordinates that are inside of the target. + return Math.min(translatedY, mEventReceivingRect.height() - 1); + } + return translatedY; + } + } + + /** + * This class forwards {@link MotionEvent}s happened in the {@link MainKeyboardView} to + * {@link SuggestionStripView} when the {@link MoreSuggestionsView} is showing. + * {@link SuggestionStripView} dismisses {@link MoreSuggestionsView} when it receives any event + * outside of it. + */ + private static class MoreSuggestionsViewCanceler + extends MotionEventForwarder<MainKeyboardView, SuggestionStripView> { + public MoreSuggestionsViewCanceler(final MainKeyboardView mainKeyboardView, + final SuggestionStripView suggestionStripView) { + super(mainKeyboardView, suggestionStripView); + } + + @Override + protected boolean needsToForward(final int x, final int y) { + return mReceiverView.isShowingMoreSuggestionPanel() && mEventSendingRect.contains(x, y); + } + + @Override + protected void onForwardingEvent(final MotionEvent me) { + if (me.getActionMasked() == MotionEvent.ACTION_DOWN) { + mReceiverView.dismissMoreSuggestionsPanel(); + } + } } } diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 2e9280c77..232bf7407 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -18,6 +18,10 @@ package com.android.inputmethod.latin; import android.text.TextUtils; +import com.android.inputmethod.event.Event; + +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. @@ -40,9 +44,9 @@ public final class LastComposedWord { public static final String NOT_A_SEPARATOR = ""; - public final int[] mPrimaryKeyCodes; + public final ArrayList<Event> mEvents; public final String mTypedWord; - public final String mCommittedWord; + public final CharSequence mCommittedWord; public final String mSeparatorString; public final String mPrevWord; public final int mCapitalizedMode; @@ -52,19 +56,20 @@ public final class LastComposedWord { private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(null, null, "", "", NOT_A_SEPARATOR, null, - WordComposer.CAPS_MODE_OFF); + new LastComposedWord(new ArrayList<Event>(), null, "", "", + NOT_A_SEPARATOR, null, WordComposer.CAPS_MODE_OFF); // 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 int[] primaryKeyCodes, final InputPointers inputPointers, - final String typedWord, final String committedWord, final String separatorString, + public LastComposedWord(final ArrayList<Event> events, + final InputPointers inputPointers, final String typedWord, + final CharSequence committedWord, final String separatorString, final String prevWord, final int capitalizedMode) { - mPrimaryKeyCodes = primaryKeyCodes; if (inputPointers != null) { mInputPointers.copy(inputPointers); } mTypedWord = typedWord; + mEvents = new ArrayList<Event>(events); mCommittedWord = committedWord; mSeparatorString = separatorString; mActive = true; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 77d07019f..e5dcb12ae 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -25,10 +25,10 @@ import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; @@ -36,39 +36,33 @@ import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; import android.os.Debug; -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; -import android.os.SystemClock; import android.preference.PreferenceManager; import android.text.InputType; import android.text.TextUtils; -import android.text.style.SuggestionSpan; import android.util.Log; -import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.view.KeyCharacterMap; +import android.util.SparseArray; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.compat.AppWorkaroundsUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; -import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; -import com.android.inputmethod.event.EventInterpreter; -import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.event.Event; +import com.android.inputmethod.event.HardwareEventDecoder; +import com.android.inputmethod.event.HardwareKeyboardEventDecoder; +import com.android.inputmethod.event.InputTransaction; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; @@ -77,232 +71,175 @@ import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; +import com.android.inputmethod.latin.inputlogic.InputLogic; import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever; -import com.android.inputmethod.latin.personalization.PersonalizationDictionary; -import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister; +import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegistrar; import com.android.inputmethod.latin.personalization.PersonalizationHelper; -import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary; -import com.android.inputmethod.latin.personalization.UserHistoryDictionary; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsActivity; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.suggestions.SuggestionStripView; +import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.utils.ApplicationUtils; -import com.android.inputmethod.latin.utils.AsyncResultHolder; -import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.CompletionInfoUtils; -import com.android.inputmethod.latin.utils.InputTypeUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; +import com.android.inputmethod.latin.utils.DialogUtils; +import com.android.inputmethod.latin.utils.DistracterFilter; +import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import com.android.inputmethod.latin.utils.IntentUtils; import com.android.inputmethod.latin.utils.JniUtils; -import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; -import com.android.inputmethod.latin.utils.RecapitalizeStatus; -import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; -import com.android.inputmethod.latin.utils.StringUtils; -import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; -import com.android.inputmethod.latin.utils.TextRange; -import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils; +import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; +import com.android.inputmethod.latin.utils.StatsUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.research.ResearchLogger; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Locale; -import java.util.TreeSet; +import java.util.concurrent.TimeUnit; /** * Input method implementation for Qwerty'ish keyboard. */ public class LatinIME extends InputMethodService implements KeyboardActionListener, - SuggestionStripView.Listener, TargetPackageInfoGetterTask.OnTargetPackageInfoKnownListener, - Suggest.SuggestInitializationListener { + SuggestionStripView.Listener, SuggestionStripViewAccessor, + DictionaryFacilitatorForSuggest.DictionaryInitializationListener, + ImportantNoticeDialog.ImportantNoticeDialogListener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean TRACE = false; - private static boolean DEBUG; + private static boolean DEBUG = false; private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; - // How many continuous deletes at which to start deleting at a higher speed. - private static final int DELETE_ACCELERATE_AT = 20; - // Key events coming any faster than this are long-presses. - private static final int QUICK_PRESS = 200; - private static final int PENDING_IMS_CALLBACK_DURATION = 800; private static final int PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT = 2; - // TODO: Set this value appropriately. - private static final int GET_SUGGESTED_WORDS_TIMEOUT = 200; - /** * The name of the scheme used by the Package Manager to warn of a new package installation, * replacement or removal. */ private static final String SCHEME_PACKAGE = "package"; - 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 space and a punctuation from the suggestion strip - // have just been swapped. Undoing this swaps them back; the space is still considered weak. - 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 final Settings mSettings; + private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */, + this /* SuggestionStripViewAccessor */); + // We expect to have only one decoder in almost all cases, hence the default capacity of 1. + // If it turns out we need several, it will get grown seamlessly. + final SparseArray<HardwareEventDecoder> mHardwareEventDecoders + = new SparseArray<HardwareEventDecoder>(1); private View mExtractArea; private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; - // Never null - private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; - private Suggest mSuggest; - private CompletionInfo[] mApplicationSpecifiedCompletions; - private AppWorkaroundsUtils mAppWorkAroundsUtils = new AppWorkaroundsUtils(); private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); - // At start, create a default event interpreter that does nothing by passing it no decoder spec. - // The event interpreter should never be null. - private EventInterpreter mEventInterpreter = new EventInterpreter(this); - - private boolean mIsMainDictionaryAvailable; - private UserBinaryDictionary mUserDictionary; - private UserHistoryDictionary mUserHistoryDictionary; - private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary; - private PersonalizationDictionary mPersonalizationDictionary; - private boolean mIsUserDictionaryAvailable; - - private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; - private final WordComposer mWordComposer = new WordComposer(); - private final RichInputConnection mConnection = new RichInputConnection(this); - private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); - - // Keep track of the last selection range to decide if we need to show word alternatives - 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. - private boolean mExpectingUpdateSelection; - private int mDeleteCount; - private long mLastKeyTime; - private final TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet(); - // Personalization debugging params - private boolean mUseOnlyPersonalizationDictionaryForDebug = false; - private boolean mBoostPersonalizationDictionaryForDebug = false; - - // Member variables for remembering the current device orientation. - private int mDisplayOrientation; // Object for reacting to adding/removing a dictionary pack. private BroadcastReceiver mDictionaryPackInstallReceiver = new DictionaryPackInstallBroadcastReceiver(this); - // Keeps track of most recently inserted text (multi-character key) for reverting - private String mEnteredText; - - // TODO: This boolean is persistent state and causes large side effects at unexpected times. - // Find a way to remove it for readability. - private boolean mIsAutoCorrectionIndicatorOn; + private BroadcastReceiver mDictionaryDumpBroadcastReceiver = + new DictionaryDumpBroadcastReceiver(this); private AlertDialog mOptionsDialog; private final boolean mIsHardwareAcceleratedDrawingEnabled; public final UIHandler mHandler = new UIHandler(this); - private InputUpdater mInputUpdater; - public static final class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { + public static final class UIHandler extends LeakGuardHandlerWrapper<LatinIME> { private static final int MSG_UPDATE_SHIFT_STATE = 0; private static final int MSG_PENDING_IMS_CALLBACK = 1; private static final int MSG_UPDATE_SUGGESTION_STRIP = 2; private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3; private static final int MSG_RESUME_SUGGESTIONS = 4; private static final int MSG_REOPEN_DICTIONARIES = 5; - private static final int MSG_ON_END_BATCH_INPUT = 6; + private static final int MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED = 6; private static final int MSG_RESET_CACHES = 7; + // Update this when adding new messages + private static final int MSG_LAST = MSG_RESET_CACHES; private static final int ARG1_NOT_GESTURE_INPUT = 0; private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; private static final int ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT = 2; - private static final int ARG2_WITHOUT_TYPED_WORD = 0; - private static final int ARG2_WITH_TYPED_WORD = 1; + private static final int ARG2_UNUSED = 0; private int mDelayUpdateSuggestions; private int mDelayUpdateShiftState; - private long mDoubleSpacePeriodTimeout; - private long mDoubleSpacePeriodTimerStart; - public UIHandler(final LatinIME outerInstance) { - super(outerInstance); + public UIHandler(final LatinIME ownerInstance) { + super(ownerInstance); } public void onCreate() { - final Resources res = getOuterInstance().getResources(); - mDelayUpdateSuggestions = - res.getInteger(R.integer.config_delay_update_suggestions); - mDelayUpdateShiftState = - res.getInteger(R.integer.config_delay_update_shift_state); - mDoubleSpacePeriodTimeout = - res.getInteger(R.integer.config_double_space_period_timeout); + final LatinIME latinIme = getOwnerInstance(); + if (latinIme == null) { + return; + } + final Resources res = latinIme.getResources(); + mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions); + mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state); } @Override public void handleMessage(final Message msg) { - final LatinIME latinIme = getOuterInstance(); + final LatinIME latinIme = getOwnerInstance(); + if (latinIme == null) { + return; + } final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; switch (msg.what) { case MSG_UPDATE_SUGGESTION_STRIP: - latinIme.updateSuggestionStrip(); + cancelUpdateSuggestionStrip(); + latinIme.mInputLogic.performUpdateSuggestionStripSync( + latinIme.mSettings.getCurrent()); break; case MSG_UPDATE_SHIFT_STATE: - switcher.updateShiftState(); + switcher.requestUpdatingShiftState(latinIme.getCurrentAutoCapsState(), + latinIme.getCurrentRecapitalizeState()); break; case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: if (msg.arg1 == ARG1_NOT_GESTURE_INPUT) { - if (msg.arg2 == ARG2_WITH_TYPED_WORD) { - final Pair<SuggestedWords, String> p = - (Pair<SuggestedWords, String>) msg.obj; - latinIme.showSuggestionStripWithTypedWord(p.first, p.second); - } else { - latinIme.showSuggestionStrip((SuggestedWords) msg.obj); - } + final SuggestedWords suggestedWords = (SuggestedWords) msg.obj; + latinIme.showSuggestionStrip(suggestedWords); } else { latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords) msg.obj, msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT); } break; case MSG_RESUME_SUGGESTIONS: - latinIme.restartSuggestionsOnWordTouchedByCursor(); + latinIme.mInputLogic.restartSuggestionsOnWordTouchedByCursor( + latinIme.mSettings.getCurrent(), + false /* includeResumedWordInSuggestions */); break; case MSG_REOPEN_DICTIONARIES: - latinIme.initSuggest(); + latinIme.resetSuggest(); // In theory we could call latinIme.updateSuggestionStrip() right away, but // in the practice, the dictionary is not finished opening yet so we wouldn't // get any suggestions. Wait one frame. postUpdateSuggestionStrip(); break; - case MSG_ON_END_BATCH_INPUT: - latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj); + case MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED: + latinIme.mInputLogic.onUpdateTailBatchInputCompleted( + latinIme.mSettings.getCurrent(), + (SuggestedWords) msg.obj, latinIme.mKeyboardSwitcher); break; case MSG_RESET_CACHES: - latinIme.retryResetCaches(msg.arg1 == 1 /* tryResumeSuggestions */, - msg.arg2 /* remainingTries */); + final SettingsValues settingsValues = latinIme.mSettings.getCurrent(); + if (latinIme.mInputLogic.retryResetCachesAndReturnSuccess(settingsValues, + msg.arg1 == 1 /* tryResumeSuggestions */, + msg.arg2 /* remainingTries */, this /* handler */)) { + // If we were able to reset the caches, then we can reload the keyboard. + // Otherwise, we'll do it when we can. + latinIme.mKeyboardSwitcher.loadKeyboard(latinIme.getCurrentInputEditorInfo(), + settingsValues, latinIme.getCurrentAutoCapsState(), + latinIme.getCurrentRecapitalizeState()); + } break; } } @@ -316,6 +253,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } public void postResumeSuggestions() { + final LatinIME latinIme = getOwnerInstance(); + if (latinIme == null) { + return; + } + if (!latinIme.mSettings.getCurrent().isSuggestionStripVisible()) { + return; + } removeMessages(MSG_RESUME_SUGGESTIONS); sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions); } @@ -343,8 +287,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); } - public void cancelUpdateShiftState() { - removeMessages(MSG_UPDATE_SHIFT_STATE); + @UsedForTesting + public void removeAllMessages() { + for (int i = 0; i <= MSG_LAST; ++i) { + removeMessages(i); + } } public void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, @@ -354,39 +301,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT : ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT; obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, - ARG2_WITHOUT_TYPED_WORD, suggestedWords).sendToTarget(); + ARG2_UNUSED, suggestedWords).sendToTarget(); } public void showSuggestionStrip(final SuggestedWords suggestedWords) { removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, - ARG1_NOT_GESTURE_INPUT, ARG2_WITHOUT_TYPED_WORD, suggestedWords).sendToTarget(); - } - - // TODO: Remove this method. - public void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords, - final String typedWord) { - removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); - obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, ARG1_NOT_GESTURE_INPUT, - ARG2_WITH_TYPED_WORD, - new Pair<SuggestedWords, String>(suggestedWords, typedWord)).sendToTarget(); + ARG1_NOT_GESTURE_INPUT, ARG2_UNUSED, suggestedWords).sendToTarget(); } - public void onEndBatchInput(final SuggestedWords suggestedWords) { - obtainMessage(MSG_ON_END_BATCH_INPUT, suggestedWords).sendToTarget(); - } - - public void startDoubleSpacePeriodTimer() { - mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis(); - } - - public void cancelDoubleSpacePeriodTimer() { - mDoubleSpacePeriodTimerStart = 0; - } - - public boolean isAcceptingDoubleSpacePeriod() { - return SystemClock.uptimeMillis() - mDoubleSpacePeriodTimerStart - < mDoubleSpacePeriodTimeout; + public void showTailBatchInputResult(final SuggestedWords suggestedWords) { + obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget(); } // Working variables for the following methods. @@ -401,7 +326,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen removeMessages(MSG_PENDING_IMS_CALLBACK); resetPendingImsCallback(); mIsOrientationChanging = true; - final LatinIME latinIme = getOuterInstance(); + final LatinIME latinIme = getOwnerInstance(); + if (latinIme == null) { + return; + } if (latinIme.isInputViewShown()) { latinIme.mKeyboardSwitcher.saveKeyboardState(); } @@ -415,12 +343,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void executePendingImsCallback(final LatinIME latinIme, final EditorInfo editorInfo, boolean restarting) { - if (mHasPendingFinishInputView) + if (mHasPendingFinishInputView) { latinIme.onFinishInputViewInternal(mHasPendingFinishInput); - if (mHasPendingFinishInput) + } + if (mHasPendingFinishInput) { latinIme.onFinishInputInternal(); - if (mHasPendingStartInput) + } + if (mHasPendingStartInput) { latinIme.onStartInputInternal(editorInfo, restarting); + } resetPendingImsCallback(); } @@ -434,9 +365,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mIsOrientationChanging = false; mPendingSuccessiveImsCallback = true; } - final LatinIME latinIme = getOuterInstance(); - executePendingImsCallback(latinIme, editorInfo, restarting); - latinIme.onStartInputInternal(editorInfo, restarting); + final LatinIME latinIme = getOwnerInstance(); + if (latinIme != null) { + executePendingImsCallback(latinIme, editorInfo, restarting); + latinIme.onStartInputInternal(editorInfo, restarting); + if (ProductionFlag.USES_CURSOR_ANCHOR_MONITOR) { + // Currently we need to call this every time when the IME is attached to + // new application. + // TODO: Consider if we can do this automatically in the framework. + InputMethodServiceCompatUtils.setCursorAnchorMonitorMode(latinIme, 1); + } + } } } @@ -453,10 +392,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), PENDING_IMS_CALLBACK_DURATION); } - final LatinIME latinIme = getOuterInstance(); - executePendingImsCallback(latinIme, editorInfo, restarting); - latinIme.onStartInputViewInternal(editorInfo, restarting); - mAppliedEditorInfo = editorInfo; + final LatinIME latinIme = getOwnerInstance(); + if (latinIme != null) { + executePendingImsCallback(latinIme, editorInfo, restarting); + latinIme.onStartInputViewInternal(editorInfo, restarting); + mAppliedEditorInfo = editorInfo; + } } } @@ -465,9 +406,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Typically this is the first onFinishInputView after orientation changed. mHasPendingFinishInputView = true; } else { - final LatinIME latinIme = getOuterInstance(); - latinIme.onFinishInputViewInternal(finishingInput); - mAppliedEditorInfo = null; + final LatinIME latinIme = getOwnerInstance(); + if (latinIme != null) { + latinIme.onFinishInputViewInternal(finishingInput); + mAppliedEditorInfo = null; + } } } @@ -476,9 +419,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Typically this is the first onFinishInput after orientation changed. mHasPendingFinishInput = true; } else { - final LatinIME latinIme = getOuterInstance(); - executePendingImsCallback(latinIme, null, false); - latinIme.onFinishInputInternal(); + final LatinIME latinIme = getOwnerInstance(); + if (latinIme != null) { + executePendingImsCallback(latinIme, null, false); + latinIme.onFinishInputInternal(); + } } } } @@ -536,7 +481,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen KeyboardSwitcher.init(this); AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); - PersonalizationDictionarySessionRegister.init(this); super.onCreate(); @@ -545,19 +489,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // TODO: Resolve mutual dependencies of {@link #loadSettings()} and {@link #initSuggest()}. loadSettings(); - initSuggest(); + resetSuggest(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.getInstance().init(this, mKeyboardSwitcher, mSuggest); + ResearchLogger.getInstance().init(this, mKeyboardSwitcher); + ResearchLogger.getInstance().initDictionary( + mInputLogic.mSuggest.mDictionaryFacilitator); } - mDisplayOrientation = getResources().getConfiguration().orientation; // Register to receive ringer mode change and network state change. // Also receive installation and removal of a dictionary pack. final IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - registerReceiver(mReceiver, filter); + registerReceiver(mConnectivityAndRingerModeChangeReceiver, filter); final IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); @@ -569,47 +514,88 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION); registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); + final IntentFilter dictDumpFilter = new IntentFilter(); + dictDumpFilter.addAction(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION); + registerReceiver(mDictionaryDumpBroadcastReceiver, dictDumpFilter); + DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(this); - mInputUpdater = new InputUpdater(this); + StatsUtils.onCreateCompleted(this); } // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - final InputAttributes inputAttributes = - new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); - mSettings.loadSettings(locale, inputAttributes); - AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(mSettings.getCurrent()); - // To load the keyboard we need to load all the settings once, but resetting the - // contacts dictionary should be deferred until after the new layout has been displayed - // to improve responsivity. In the language switching process, we post a reopenDictionaries - // message, then come here to read the settings for the new language before we change - // the layout; at this time, we need to skip resetting the contacts dictionary. It will - // be done later inside {@see #initSuggest()} when the reopenDictionaries message is - // processed. + final EditorInfo editorInfo = getCurrentInputEditorInfo(); + final InputAttributes inputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); + mSettings.loadSettings(this, locale, inputAttributes); + final SettingsValues currentSettingsValues = mSettings.getCurrent(); + AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues); + // This method is called on startup and language switch, before the new layout has + // been displayed. Opening dictionaries never affects responsivity as dictionaries are + // asynchronously loaded. if (!mHandler.hasPendingReopenDictionaries()) { - // May need to reset the contacts dictionary depending on the user settings. - resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); + resetSuggestForLocale(locale); + } + refreshPersonalizationDictionarySession(); + } + + private DistracterFilter createDistracterFilter() { + final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); + // TODO: Create Keyboard when mainKeyboardView is null. + // TODO: Figure out the most reasonable keyboard for the filter. Refer to the + // spellchecker's logic. + final Keyboard keyboard = (mainKeyboardView != null) ? + mainKeyboardView.getKeyboard() : null; + final DistracterFilter distracterFilter = new DistracterFilter(mInputLogic.mSuggest, + keyboard); + return distracterFilter; + } + + private void refreshPersonalizationDictionarySession() { + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + final boolean shouldKeepUserHistoryDictionaries; + final boolean shouldKeepPersonalizationDictionaries; + if (mSettings.getCurrent().mUsePersonalizedDicts) { + shouldKeepUserHistoryDictionaries = true; + // TODO: Eliminate this restriction + shouldKeepPersonalizationDictionaries = + mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes(); + } else { + shouldKeepUserHistoryDictionaries = false; + shouldKeepPersonalizationDictionaries = false; + } + if (!shouldKeepUserHistoryDictionaries) { + // Remove user history dictionaries. + PersonalizationHelper.removeAllUserHistoryDictionaries(this); + dictionaryFacilitator.clearUserHistoryDictionary(); + } + if (!shouldKeepPersonalizationDictionaries) { + // Remove personalization dictionaries. + PersonalizationHelper.removeAllPersonalizationDictionaries(this); + PersonalizationDictionarySessionRegistrar.resetAll(this); + } else { + final DistracterFilter distracterFilter = createDistracterFilter(); + PersonalizationDictionarySessionRegistrar.init( + this, dictionaryFacilitator, distracterFilter); } } // Note that this method is called from a non-UI thread. @Override public void onUpdateMainDictionaryAvailability(final boolean isMainDictionaryAvailable) { - mIsMainDictionaryAvailable = isMainDictionaryAvailable; final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); if (mainKeyboardView != null) { mainKeyboardView.setMainDictionaryAvailability(isMainDictionaryAvailable); } } - private void initSuggest() { + private void resetSuggest() { final Locale switcherSubtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); final String switcherLocaleStr = switcherSubtypeLocale.toString(); final Locale subtypeLocale; - final String localeStr; if (TextUtils.isEmpty(switcherLocaleStr)) { // This happens in very rare corner cases - for example, immediately after a switch // to LatinIME has been requested, about a frame later another switch happens. In this @@ -619,132 +605,81 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // of knowing anyway. Log.e(TAG, "System is reporting no current subtype."); subtypeLocale = getResources().getConfiguration().locale; - localeStr = subtypeLocale.toString(); } else { subtypeLocale = switcherSubtypeLocale; - localeStr = switcherLocaleStr; - } - - final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale, - this /* SuggestInitializationListener */); - final SettingsValues settingsValues = mSettings.getCurrent(); - if (settingsValues.mCorrectionEnabled) { - newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold); - } - - mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.getInstance().initSuggest(newSuggest); } - - mUserDictionary = new UserBinaryDictionary(this, localeStr); - mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); - newSuggest.setUserDictionary(mUserDictionary); - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - mUserHistoryDictionary = PersonalizationHelper.getUserHistoryDictionary( - this, localeStr, prefs); - newSuggest.setUserHistoryDictionary(mUserHistoryDictionary); - mPersonalizationDictionary = PersonalizationHelper - .getPersonalizationDictionary(this, localeStr, prefs); - newSuggest.setPersonalizationDictionary(mPersonalizationDictionary); - mPersonalizationPredictionDictionary = PersonalizationHelper - .getPersonalizationPredictionDictionary(this, localeStr, prefs); - newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary); - - final Suggest oldSuggest = mSuggest; - resetContactsDictionary(null != oldSuggest ? oldSuggest.getContactsDictionary() : null); - mSuggest = newSuggest; - if (oldSuggest != null) oldSuggest.close(); + resetSuggestForLocale(subtypeLocale); } /** - * Resets the contacts dictionary in mSuggest according to the user settings. + * Reset suggest by loading dictionaries for the locale and the current settings values. * - * This method takes an optional contacts dictionary to use when the locale hasn't changed - * since the contacts dictionary can be opened or closed as necessary depending on the settings. - * - * @param oldContactsDictionary an optional dictionary to use, or null + * @param locale the locale */ - private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { - final Suggest suggest = mSuggest; - final boolean shouldSetDictionary = - (null != suggest && mSettings.getCurrent().mUseContactsDict); - - final ContactsBinaryDictionary dictionaryToUse; - if (!shouldSetDictionary) { - // Make sure the dictionary is closed. If it is already closed, this is a no-op, - // so it's safe to call it anyways. - if (null != oldContactsDictionary) oldContactsDictionary.close(); - dictionaryToUse = null; - } else { - final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - if (null != oldContactsDictionary) { - if (!oldContactsDictionary.mLocale.equals(locale)) { - // If the locale has changed then recreate the contacts dictionary. This - // allows locale dependent rules for handling bigram name predictions. - oldContactsDictionary.close(); - dictionaryToUse = new ContactsBinaryDictionary(this, locale); - } else { - // Make sure the old contacts dictionary is opened. If it is already open, - // this is a no-op, so it's safe to call it anyways. - oldContactsDictionary.reopen(this); - dictionaryToUse = oldContactsDictionary; - } - } else { - dictionaryToUse = new ContactsBinaryDictionary(this, locale); - } - } - - if (null != suggest) { - suggest.setContactsDictionary(dictionaryToUse); + private void resetSuggestForLocale(final Locale locale) { + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + final SettingsValues settingsValues = mSettings.getCurrent(); + dictionaryFacilitator.resetDictionaries(this /* context */, locale, + settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, + false /* forceReloadMainDictionary */, this); + if (settingsValues.mCorrectionEnabled) { + mInputLogic.mSuggest.setAutoCorrectionThreshold( + settingsValues.mAutoCorrectionThreshold); } } + /** + * Reset suggest by loading the main dictionary of the current locale. + */ /* package private */ void resetSuggestMainDict() { - final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - mSuggest.resetMainDict(this, subtypeLocale, this /* SuggestInitializationListener */); - mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + final SettingsValues settingsValues = mSettings.getCurrent(); + dictionaryFacilitator.resetDictionaries(this /* context */, + dictionaryFacilitator.getLocale(), settingsValues.mUseContactsDict, + settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, this); } @Override public void onDestroy() { - final Suggest suggest = mSuggest; - if (suggest != null) { - suggest.close(); - mSuggest = null; - } + mInputLogic.mSuggest.mDictionaryFacilitator.closeDictionaries(); mSettings.onDestroy(); - unregisterReceiver(mReceiver); + unregisterReceiver(mConnectivityAndRingerModeChangeReceiver); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.getInstance().onDestroy(); } unregisterReceiver(mDictionaryPackInstallReceiver); - PersonalizationDictionarySessionRegister.onDestroy(this); + unregisterReceiver(mDictionaryDumpBroadcastReceiver); + PersonalizationDictionarySessionRegistrar.close(this); LatinImeLogger.commit(); LatinImeLogger.onDestroy(); - if (mInputUpdater != null) { - mInputUpdater.quitLooper(); - } + StatsUtils.onDestroy(); super.onDestroy(); } + @UsedForTesting + public void recycle() { + unregisterReceiver(mDictionaryPackInstallReceiver); + unregisterReceiver(mDictionaryDumpBroadcastReceiver); + unregisterReceiver(mConnectivityAndRingerModeChangeReceiver); + mInputLogic.recycle(); + } + @Override public void onConfigurationChanged(final Configuration conf) { // If orientation changed while predicting, commit the change - if (mDisplayOrientation != conf.orientation) { - mDisplayOrientation = conf.orientation; + final SettingsValues settingsValues = mSettings.getCurrent(); + if (settingsValues.mDisplayOrientation != conf.orientation) { mHandler.startOrientationChanging(); - mConnection.beginBatchEdit(); - commitTyped(LastComposedWord.NOT_A_SEPARATOR); - mConnection.finishComposingText(); - mConnection.endBatchEdit(); - if (isShowingOptionDialog()) { - mOptionsDialog.dismiss(); - } - } - PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf); + mInputLogic.mConnection.beginBatchEdit(); + mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR); + mInputLogic.mConnection.finishComposingText(); + mInputLogic.mConnection.endBatchEdit(); + } + final DistracterFilter distracterFilter = createDistracterFilter(); + PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf, + mInputLogic.mSuggest.mDictionaryFacilitator, distracterFilter); super.onConfigurationChanged(conf); } @@ -760,8 +695,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen .findViewById(android.R.id.extractArea); mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view); - if (mSuggestionStripView != null) + if (hasSuggestionStripView()) { mSuggestionStripView.setListener(this, view); + } if (LatinImeLogger.sVISUALDEBUG) { mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); } @@ -834,29 +770,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + ", word caps = " + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); } + Log.i(TAG, "Starting input. Cursor position = " + + editorInfo.initialSelStart + "," + editorInfo.initialSelEnd); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); } if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { - Log.w(TAG, "Deprecated private IME option specified: " - + editorInfo.privateImeOptions); + Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); } if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { - Log.w(TAG, "Deprecated private IME option specified: " - + editorInfo.privateImeOptions); + Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); } - final PackageInfo packageInfo = - TargetPackageInfoGetterTask.getCachedPackageInfo(editorInfo.packageName); - mAppWorkAroundsUtils.setPackageInfo(packageInfo); - if (null == packageInfo) { - new TargetPackageInfoGetterTask(this /* context */, this /* listener */) - .execute(editorInfo.packageName); - } - LatinImeLogger.onStartInputView(editorInfo); // In landscape mode, this method gets called without the input view being created. if (mainKeyboardView == null) { @@ -878,57 +806,53 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); - mApplicationSpecifiedCompletions = null; // The app calling setText() has the effect of clearing the composing // span, so we should reset our state unconditionally, even if restarting is true. - mEnteredText = null; - resetComposingState(true /* alsoResetLastComposedWord */); - mDeleteCount = 0; - mSpaceState = SPACE_STATE_NONE; - mRecapitalizeStatus.deactivate(); - mCurrentlyPressedHardwareKeys.clear(); + mInputLogic.startInput(restarting, editorInfo); // Note: the following does a round-trip IPC on the main thread: be careful final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - final Suggest suggest = mSuggest; - if (null != suggest && null != currentLocale && !currentLocale.equals(suggest.mLocale)) { - initSuggest(); + final Suggest suggest = mInputLogic.mSuggest; + if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) { + // TODO: Do this automatically. + resetSuggest(); } - if (mSuggestionStripView != null) { - // This will set the punctuation suggestions if next word suggestion is off; - // otherwise it will clear the suggestion strip. - setPunctuationSuggestions(); - } - mSuggestedWords = SuggestedWords.EMPTY; - // Sometimes, while rotating, for some reason the framework tells the app we are not - // connected to it and that means we can't refresh the cache. In this case, schedule a - // refresh later. + // TODO[IL]: Can the following be moved to InputLogic#startInput? final boolean canReachInputConnection; - if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(editorInfo.initialSelStart, + if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess( + editorInfo.initialSelStart, editorInfo.initialSelEnd, false /* shouldFinishComposition */)) { + // Sometimes, while rotating, for some reason the framework tells the app we are not + // connected to it and that means we can't refresh the cache. In this case, schedule a + // refresh later. // We try resetting the caches up to 5 times before giving up. mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */); // mLastSelection{Start,End} are reset later in this method, don't need to do it here canReachInputConnection = false; } else { - if (isDifferentTextField) { - mHandler.postResumeSuggestions(); - } + // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best + // effort to work around this bug. + mInputLogic.mConnection.tryFixLyingCursorPosition(); + mHandler.postResumeSuggestions(); canReachInputConnection = true; } + if (isDifferentTextField || + !currentSettingsValues.hasSameOrientation(getResources().getConfiguration())) { + loadSettings(); + } if (isDifferentTextField) { mainKeyboardView.closing(); - loadSettings(); currentSettingsValues = mSettings.getCurrent(); - if (suggest != null && currentSettingsValues.mCorrectionEnabled) { + if (currentSettingsValues.mCorrectionEnabled) { suggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold); } - switcher.loadKeyboard(editorInfo, currentSettingsValues); + switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); if (!canReachInputConnection) { // If we can't reach the input connection, we will call loadKeyboard again later, // so we need to save its state now. The call will be done in #retryResetCaches. @@ -937,26 +861,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else if (restarting) { // TODO: Come up with a more comprehensive way to reset the keyboard layout when // a keyboard layout set doesn't get reloaded in this method. - switcher.resetKeyboardStateToAlphabet(); + switcher.resetKeyboardStateToAlphabet(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); // In apps like Talk, we come here when the text is sent and the field gets emptied and // we need to re-evaluate the shift state, but not the whole layout which would be // disruptive. // Space state must be updated before calling updateShiftState - switcher.updateShiftState(); + switcher.requestUpdatingShiftState(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); } - setSuggestionStripShownInternal( - isSuggestionsStripVisible(), /* needsInputViewShown */ false); - - mLastSelectionStart = editorInfo.initialSelStart; - mLastSelectionEnd = editorInfo.initialSelEnd; - // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying - // so we try using some heuristics to find out about these and fix them. - tryFixLyingCursorPosition(); + // This will set the punctuation suggestions if next word suggestion is off; + // otherwise it will clear the suggestion strip. + setNeutralSuggestionStrip(); mHandler.cancelUpdateSuggestionStrip(); - mHandler.cancelDoubleSpacePeriodTimer(); - mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable); + mainKeyboardView.setMainDictionaryAvailability( + suggest.mDictionaryFacilitator.hasInitializedMainDictionary()); mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn, currentSettingsValues.mKeyPreviewPopupDismissDelay); mainKeyboardView.setSlidingKeyInputPreviewEnabled( @@ -966,76 +887,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen currentSettingsValues.mGestureTrailEnabled, currentSettingsValues.mGestureFloatingPreviewTextEnabled); - initPersonalizationDebugSettings(currentSettingsValues); - if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } - /** - * Try to get the text from the editor to expose lies the framework may have been - * telling us. Concretely, when the device rotates, the frameworks tells us about where the - * cursor used to be initially in the editor at the time it first received the focus; this - * may be completely different from the place it is upon rotation. Since we don't have any - * means to get the real value, try at least to ask the text view for some characters and - * detect the most damaging cases: when the cursor position is declared to be much smaller - * than it really is. - */ - private void tryFixLyingCursorPosition() { - final CharSequence textBeforeCursor = - mConnection.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); - if (null == textBeforeCursor) { - mLastSelectionStart = mLastSelectionEnd = NOT_A_CURSOR_POSITION; - } else { - final int textLength = textBeforeCursor.length(); - if (textLength > mLastSelectionStart - || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE - && mLastSelectionStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { - // It should not be possible to have only one of those variables be - // NOT_A_CURSOR_POSITION, so if they are equal, either the selection is zero-sized - // (simple cursor, no selection) or there is no cursor/we don't know its pos - final boolean wasEqual = mLastSelectionStart == mLastSelectionEnd; - mLastSelectionStart = textLength; - // We can't figure out the value of mLastSelectionEnd :( - // But at least if it's smaller than mLastSelectionStart something is wrong, - // and if they used to be equal we also don't want to make it look like there is a - // selection. - if (wasEqual || mLastSelectionStart > mLastSelectionEnd) { - mLastSelectionEnd = mLastSelectionStart; - } - } - } - } - - // Initialization of personalization debug settings. This must be called inside - // onStartInputView. - private void initPersonalizationDebugSettings(SettingsValues currentSettingsValues) { - if (mUseOnlyPersonalizationDictionaryForDebug - != currentSettingsValues.mUseOnlyPersonalizationDictionaryForDebug) { - // Only for debug - initSuggest(); - mUseOnlyPersonalizationDictionaryForDebug = - currentSettingsValues.mUseOnlyPersonalizationDictionaryForDebug; - } - - if (mBoostPersonalizationDictionaryForDebug != - currentSettingsValues.mBoostPersonalizationDictionaryForDebug) { - // Only for debug - mBoostPersonalizationDictionaryForDebug = - currentSettingsValues.mBoostPersonalizationDictionaryForDebug; - if (mBoostPersonalizationDictionaryForDebug) { - UserHistoryForgettingCurveUtils.boostMaxFreqForDebug(); - } else { - UserHistoryForgettingCurveUtils.resetMaxFreqForDebug(); - } - } - } - - // Callback for the TargetPackageInfoGetterTask - @Override - public void onTargetPackageInfoKnown(final PackageInfo info) { - mAppWorkAroundsUtils.setPackageInfo(info); - } - @Override public void onWindowHidden() { super.onWindowHidden(); @@ -1062,12 +916,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Remove pending messages related to update suggestions mHandler.cancelUpdateSuggestionStrip(); // Should do the following in onFinishInputInternal but until JB MR2 it's not called :( - if (mWordComposer.isComposingWord()) mConnection.finishComposingText(); - resetComposingState(true /* alsoResetLastComposedWord */); + mInputLogic.finishInput(); // Notify ResearchLogger if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput, mLastSelectionStart, - mLastSelectionEnd, getCurrentInputConnection()); + ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput); } } @@ -1078,104 +930,38 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, composingSpanEnd); if (DEBUG) { - Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart - + ", ose=" + oldSelEnd - + ", lss=" + mLastSelectionStart - + ", lse=" + mLastSelectionEnd - + ", nss=" + newSelStart - + ", nse=" + newSelEnd - + ", cs=" + composingSpanStart - + ", ce=" + composingSpanEnd); + Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + ", ose=" + oldSelEnd + + ", nss=" + newSelStart + ", nse=" + newSelEnd + + ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd); } if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - final boolean expectingUpdateSelectionFromLogger = - ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection(); - ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, + ResearchLogger.latinIME_onUpdateSelection(oldSelStart, oldSelEnd, oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, - composingSpanEnd, mExpectingUpdateSelection, - expectingUpdateSelectionFromLogger, mConnection); - if (expectingUpdateSelectionFromLogger) { - // TODO: Investigate. Quitting now sounds wrong - we won't do the resetting work - return; - } + composingSpanEnd, mInputLogic.mConnection); } - final boolean selectionChanged = mLastSelectionStart != newSelStart - || mLastSelectionEnd != newSelEnd; - - // if composingSpanStart and composingSpanEnd are -1, it means there is no composing - // span in the view - we can use that to narrow down whether the cursor was moved - // by us or not. If we are composing a word but there is no composing span, then - // we know for sure the cursor moved while we were composing and we should reset - // the state. TODO: rescind this policy: the framework never removes the composing - // span on its own accord while editing. This test is useless. - final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; - // If the keyboard is not visible, we don't need to do all the housekeeping work, as it // will be reset when the keyboard shows up anyway. // TODO: revisit this when LatinIME supports hardware keyboards. // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown(). // TODO: find a better way to simulate actual execution. - if (isInputViewShown() && !mExpectingUpdateSelection - && !mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart)) { - // 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 noComposingSpan to further reduce the impact. - - // TODO: the following is probably better done in resetEntireInputState(). - // it should only happen when the cursor moved, and the very purpose of the - // test below is to narrow down whether this happened or not. Likewise with - // the call to updateShiftState. - // 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; - - // TODO: is it still necessary to test for composingSpan related stuff? - final boolean selectionChangedOrSafeToReset = selectionChanged - || (!mWordComposer.isComposingWord()) || noComposingSpan; - final boolean hasOrHadSelection = (oldSelStart != oldSelEnd - || newSelStart != newSelEnd); - final int moveAmount = newSelStart - oldSelStart; - if (selectionChangedOrSafeToReset && (hasOrHadSelection - || !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) { - // If we are composing a word and moving the cursor, we would want to set a - // suggestion span for recorrection to work correctly. Unfortunately, that - // would involve the keyboard committing some new text, which would move the - // cursor back to where it was. Latin IME could then fix the position of the cursor - // again, but the asynchronous nature of the calls results in this wreaking havoc - // with selection on double tap and the like. - // Another option would be to send suggestions each time we set the composing - // text, but that is probably too expensive to do, so we decided to leave things - // as is. - resetEntireInputState(newSelStart); - } else { - // resetEntireInputState calls resetCachesUponCursorMove, but with the second - // argument as true. But in all cases where we don't reset the entire input state, - // we still want to tell the rich input connection about the new cursor position so - // that it can update its caches. - mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, - false /* shouldFinishComposition */); - } - - // We moved the cursor. If we are touching a word, we need to resume suggestion, - // unless suggestions are off. - if (isSuggestionsStripVisible()) { - mHandler.postResumeSuggestions(); - } - // Reset the last recapitalization. - mRecapitalizeStatus.deactivate(); - mKeyboardSwitcher.updateShiftState(); + if (isInputViewShown() && + mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) { + mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); } - mExpectingUpdateSelection = false; - // Make a note of the cursor position - mLastSelectionStart = newSelStart; - mLastSelectionEnd = newSelEnd; mSubtypeState.currentSubtypeUsed(); } + @Override + public void onUpdateCursor(Rect rect) { + if (DEBUG) { + Log.i(TAG, "onUpdateCursor:" + rect.toShortString()); + } + super.onUpdateCursor(rect); + } + /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides @@ -1186,7 +972,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen */ @Override public void onExtractedTextClicked() { - if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested()) { + return; + } super.onExtractedTextClicked(); } @@ -1202,7 +990,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen */ @Override public void onExtractedCursorMovement(final int dx, final int dy) { - if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested()) { + return; + } super.onExtractedCursorMovement(dx, dy); } @@ -1217,7 +1007,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } if (TRACE) Debug.stopMethodTracing(); - if (mOptionsDialog != null && mOptionsDialog.isShowing()) { + if (isShowingOptionDialog()) { mOptionsDialog.dismiss(); mOptionsDialog = null; } @@ -1234,58 +1024,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } } - if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; + if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) { + return; + } if (applicationSpecifiedCompletions == null) { - clearSuggestionStrip(); + setNeutralSuggestionStrip(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onDisplayCompletions(null); } return; } - mApplicationSpecifiedCompletions = - CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( applicationSpecifiedCompletions); - final SuggestedWords suggestedWords = new SuggestedWords( - applicationSuggestedWords, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - false /* isPunctuationSuggestions */, - false /* isObsoleteSuggestions */, - false /* isPrediction */); - // When in fullscreen mode, show completions generated by the application - final boolean isAutoCorrection = false; - setSuggestedWords(suggestedWords, isAutoCorrection); - setAutoCorrectionIndicator(isAutoCorrection); - setSuggestionStripShown(true); + final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords, + null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */, + false /* isObsoleteSuggestions */, false /* isPrediction */); + // When in fullscreen mode, show completions generated by the application forcibly + setSuggestedWords(suggestedWords, true /* isSuggestionStripVisible */); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); } } - private void setSuggestionStripShownInternal(final boolean shown, - final boolean needsInputViewShown) { - // TODO: Modify this if we support suggestions with hard keyboard - if (onEvaluateInputViewShown() && mSuggestionStripView != null) { - final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes(); - final boolean shouldShowSuggestions = shown - && (needsInputViewShown ? inputViewShown : true); - if (isFullscreenMode()) { - mSuggestionStripView.setVisibility( - shouldShowSuggestions ? View.VISIBLE : View.GONE); - } else { - mSuggestionStripView.setVisibility( - shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); - } - } - } - - private void setSuggestionStripShown(final boolean shown) { - setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); - } - private int getAdjustedBackingViewHeight() { final int currentHeight = mKeyPreviewBackingView.getHeight(); if (currentHeight > 0) { @@ -1317,7 +1079,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onComputeInsets(final InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView(); - if (visibleKeyboardView == null || mSuggestionStripView == null) { + if (visibleKeyboardView == null || !hasSuggestionStripView()) { return; } final int adjustedBackingHeight = getAdjustedBackingViewHeight(); @@ -1353,9 +1115,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean onEvaluateFullscreenMode() { - // Reread resource value here, because this method is called by framework anytime as needed. - final boolean isFullscreenModeAllowed = - Settings.readUseFullscreenMode(getResources()); + // Reread resource value here, because this method is called by the framework as needed. + final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI // implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI @@ -1378,138 +1139,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); } - // This will reset the whole input state to the starting state. It will clear - // the composing word, reset the last composed word, tell the inputconnection about it. - private void resetEntireInputState(final int newCursorPosition) { - final boolean shouldFinishComposition = mWordComposer.isComposingWord(); - resetComposingState(true /* alsoResetLastComposedWord */); - final SettingsValues settingsValues = mSettings.getCurrent(); - if (settingsValues.mBigramPredictionEnabled) { - clearSuggestionStrip(); - } else { - setSuggestedWords(settingsValues.mSuggestPuncList, false); - } - mConnection.resetCachesUponCursorMoveAndReturnSuccess(newCursorPosition, - shouldFinishComposition); + private int getCurrentAutoCapsState() { + return mInputLogic.getCurrentAutoCapsState(mSettings.getCurrent()); } - private void resetComposingState(final boolean alsoResetLastComposedWord) { - mWordComposer.reset(); - if (alsoResetLastComposedWord) - mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + private int getCurrentRecapitalizeState() { + return mInputLogic.getCurrentRecapitalizeState(); } - private void commitTyped(final String separatorString) { - if (!mWordComposer.isComposingWord()) return; - final String typedWord = mWordComposer.getTypedWord(); - if (typedWord.length() > 0) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); - } - commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, - separatorString); - } - } - - // Called from the KeyboardSwitcher which needs to know auto caps state to display - // the right layout. - public int getCurrentAutoCapsState() { - final SettingsValues currentSettingsValues = mSettings.getCurrent(); - if (!currentSettingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; - - final EditorInfo ei = getCurrentInputEditorInfo(); - if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; - final int inputType = ei.inputType; - // Warning: this depends on mSpaceState, which may not be the most current value. If - // mSpaceState gets updated later, whoever called this may need to be told about it. - return mConnection.getCursorCapsMode(inputType, currentSettingsValues, - SPACE_STATE_PHANTOM == mSpaceState); - } - - public int getCurrentRecapitalizeState() { - if (!mRecapitalizeStatus.isActive() - || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { - // Not recapitalizing at the moment - return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; - } - return mRecapitalizeStatus.getCurrentMode(); - } - - // Factor in auto-caps and manual caps and compute the current caps mode. - private int getActualCapsMode() { - final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode(); - if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; - final int auto = getCurrentAutoCapsState(); - if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { - return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; - } - if (0 != auto) return WordComposer.CAPS_MODE_AUTO_SHIFTED; - return WordComposer.CAPS_MODE_OFF; - } - - private void swapSwapperAndSpace() { - final CharSequence lastTwo = mConnection.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) == Constants.CODE_SPACE) { - mConnection.deleteSurroundingText(2, 0); - final String text = lastTwo.charAt(1) + " "; - mConnection.commitText(text, 1); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); - } - mKeyboardSwitcher.updateShiftState(); - } + public Locale getCurrentSubtypeLocale() { + return mSubtypeSwitcher.getCurrentSubtypeLocale(); } - private boolean maybeDoubleSpacePeriod() { - final SettingsValues currentSettingsValues = mSettings.getCurrent(); - if (!currentSettingsValues.mUseDoubleSpacePeriod) return false; - if (!mHandler.isAcceptingDoubleSpacePeriod()) return false; - // We only do this when we see two spaces and an accepted code point before the cursor. - // The code point may be a surrogate pair but the two spaces may not, so we need 4 chars. - final CharSequence lastThree = mConnection.getTextBeforeCursor(4, 0); - if (null == lastThree) return false; - final int length = lastThree.length(); - if (length < 3) return false; - if (lastThree.charAt(length - 1) != Constants.CODE_SPACE) return false; - if (lastThree.charAt(length - 2) != Constants.CODE_SPACE) return false; - // We know there are spaces in pos -1 and -2, and we have at least three chars. - // If we have only three chars, isSurrogatePairs can't return true as charAt(1) is a space, - // so this is fine. - final int firstCodePoint = - Character.isSurrogatePair(lastThree.charAt(0), lastThree.charAt(1)) ? - Character.codePointAt(lastThree, 0) : lastThree.charAt(length - 3); - if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) { - mHandler.cancelDoubleSpacePeriodTimer(); - mConnection.deleteSurroundingText(2, 0); - final String textToInsert = new String( - new int[] { currentSettingsValues.mSentenceSeparator, Constants.CODE_SPACE }, - 0, 2); - mConnection.commitText(textToInsert, 1); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, - false /* isBatchMode */); - } - mKeyboardSwitcher.updateShiftState(); - return true; + /** + * @param codePoints code points to get coordinates for. + * @return x,y coordinates for this keyboard, as a flattened array. + */ + public int[] getCoordinatesForCurrentKeyboard(final int[] codePoints) { + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); + if (null == keyboard) { + return CoordinateUtils.newCoordinateArray(codePoints.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } else { + return keyboard.getCoordinates(codePoints); } - return false; - } - - private static boolean canBeFollowedByDoubleSpacePeriod(final int codePoint) { - // TODO: Check again whether there really ain't a better way to check this. - // TODO: This should probably be language-dependant... - return Character.isLetterOrDigit(codePoint) - || codePoint == Constants.CODE_SINGLE_QUOTE - || codePoint == Constants.CODE_DOUBLE_QUOTE - || codePoint == Constants.CODE_CLOSING_PARENTHESIS - || codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET - || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET - || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET - || codePoint == Constants.CODE_PLUS - || codePoint == Constants.CODE_PERCENT - || Character.getType(codePoint) == Character.OTHER_SYMBOL; } // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is @@ -1521,16 +1174,38 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return; } final String wordToEdit; - if (CapsModeUtils.isAutoCapsMode(mLastComposedWord.mCapitalizedMode)) { - wordToEdit = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); + if (CapsModeUtils.isAutoCapsMode(mInputLogic.mLastComposedWord.mCapitalizedMode)) { + wordToEdit = word.toLowerCase(getCurrentSubtypeLocale()); } else { wordToEdit = word; } - mUserDictionary.addWordToUserDictionary(wordToEdit); + mInputLogic.mSuggest.mDictionaryFacilitator.addWordToUserDictionary( + this /* context */, wordToEdit); } - private void onSettingsKeyPressed() { - if (isShowingOptionDialog()) return; + // Callback for the {@link SuggestionStripView}, to call when the important notice strip is + // pressed. + @Override + public void showImportantNoticeContents() { + showOptionDialog(new ImportantNoticeDialog(this /* context */, this /* listener */)); + } + + // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener} + @Override + public void onClickSettingsOfImportantNoticeDialog(final int nextVersion) { + launchSettings(); + } + + // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener} + @Override + public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion) { + setNeutralSuggestionStrip(); + } + + public void displaySettingsDialog() { + if (isShowingOptionDialog()) { + return; + } showSubtypeSelectorAndSettings(); } @@ -1552,408 +1227,103 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mOptionsDialog != null && mOptionsDialog.isShowing(); } - private void performEditorAction(final int actionId) { - mConnection.performEditorAction(actionId); - } - // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. - private void handleLanguageSwitchKey() { + public void switchToNextSubtype() { final IBinder token = getWindow().getWindow().getAttributes().token; - if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) { + if (shouldSwitchToOtherInputMethods()) { mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */); return; } mSubtypeState.switchSubtype(token, mRichImm); } - private void sendDownUpKeyEvent(final int code) { - final long eventTime = SystemClock.uptimeMillis(); - mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); - mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); - } - - private void sendKeyCodePoint(final int code) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_sendKeyCodePoint(code); - } - // TODO: Remove this special handling of digit letters. - // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. - if (code >= '0' && code <= '9') { - sendDownUpKeyEvent(code - '0' + KeyEvent.KEYCODE_0); - return; - } - - if (Constants.CODE_ENTER == code && mAppWorkAroundsUtils.isBeforeJellyBean()) { - // Backward compatibility mode. Before Jelly bean, the keyboard would simulate - // a hardware keyboard event on pressing enter or delete. This is bad for many - // reasons (there are race conditions with commits) but some applications are - // relying on this behavior so we continue to support it for older apps. - sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER); - } else { - mConnection.commitText(StringUtils.newSingleCodePointString(code), 1); - } - } - // Implementation of {@link KeyboardActionListener}. @Override - public void onCodeInput(final int primaryCode, final int x, final int y) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); - } - final long when = SystemClock.uptimeMillis(); - if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { - mDeleteCount = 0; - } - mLastKeyTime = when; - mConnection.beginBatchEdit(); - final KeyboardSwitcher switcher = mKeyboardSwitcher; - // 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; - if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; - - // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. - if (primaryCode != Constants.CODE_SPACE) { - mHandler.cancelDoubleSpacePeriodTimer(); - } - - boolean didAutoCorrect = false; - switch (primaryCode) { - case Constants.CODE_DELETE: - mSpaceState = SPACE_STATE_NONE; - handleBackspace(spaceState); - LatinImeLogger.logOnDelete(x, y); - break; - case Constants.CODE_SHIFT: - // Note: Calling back to the keyboard on Shift key is handled in - // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. - final Keyboard currentKeyboard = switcher.getKeyboard(); + public void onCodeInput(final int codePoint, final int x, final int y, + final boolean isKeyRepeat) { + final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); + // x and y include some padding, but everything down the line (especially native + // code) needs the coordinates in the keyboard frame. + // TODO: We should reconsider which coordinate system should be used to represent + // keyboard event. Also we should pull this up -- LatinIME has no business doing + // this transformation, it should be done already before calling onCodeInput. + final int keyX = mainKeyboardView.getKeyX(x); + final int keyY = mainKeyboardView.getKeyY(y); + final int codeToSend; + if (Constants.CODE_SHIFT == codePoint) { + // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for + // alphabetic shift and shift while in symbol layout. + final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard(); if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) { - // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for - // alphabetic shift and shift while in symbol layout. - handleRecapitalize(); - } - break; - case Constants.CODE_CAPSLOCK: - // Note: Changing keyboard to shift lock state is handled in - // {@link KeyboardSwitcher#onCodeInput(int)}. - break; - case Constants.CODE_SWITCH_ALPHA_SYMBOL: - // Note: Calling back to the keyboard on symbol key is handled in - // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. - break; - case Constants.CODE_SETTINGS: - onSettingsKeyPressed(); - break; - case Constants.CODE_SHORTCUT: - mSubtypeSwitcher.switchToShortcutIME(this); - break; - case Constants.CODE_ACTION_NEXT: - performEditorAction(EditorInfo.IME_ACTION_NEXT); - break; - case Constants.CODE_ACTION_PREVIOUS: - performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); - break; - case Constants.CODE_LANGUAGE_SWITCH: - handleLanguageSwitchKey(); - break; - case Constants.CODE_EMOJI: - // Note: Switching emoji keyboard is being handled in - // {@link KeyboardState#onCodeInput(int,int)}. - break; - case Constants.CODE_ENTER: - final EditorInfo editorInfo = getCurrentInputEditorInfo(); - final int imeOptionsActionId = - InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo); - if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) { - // Either we have an actionLabel and we should performEditorAction with actionId - // regardless of its value. - performEditorAction(editorInfo.actionId); - } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) { - // We didn't have an actionLabel, but we had another action to execute. - // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast, - // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it - // means there should be an action and the app didn't bother to set a specific - // code for it - presumably it only handles one. It does not have to be treated - // in any specific way: anything that is not IME_ACTION_NONE should be sent to - // performEditorAction. - performEditorAction(imeOptionsActionId); + codeToSend = codePoint; } else { - // No action label, and the action from imeOptions is NONE: this is a regular - // enter key that should input a carriage return. - didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState); + codeToSend = Constants.CODE_SYMBOL_SHIFT; } - break; - case Constants.CODE_SHIFT_ENTER: - didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState); - break; - default: - didAutoCorrect = handleNonSpecialCharacter(primaryCode, x, y, spaceState); - break; - } - switcher.onCodeInput(primaryCode); - // Reset after any single keystroke, except shift, capslock, and symbol-shift - if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT - && primaryCode != Constants.CODE_CAPSLOCK - && primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) - mLastComposedWord.deactivate(); - if (Constants.CODE_DELETE != primaryCode) { - mEnteredText = null; + } else { + codeToSend = codePoint; } - mConnection.endBatchEdit(); - } - - private boolean handleNonSpecialCharacter(final int primaryCode, final int x, final int y, - final int spaceState) { - mSpaceState = SPACE_STATE_NONE; - final boolean didAutoCorrect; - final SettingsValues settingsValues = mSettings.getCurrent(); - if (settingsValues.isWordSeparator(primaryCode) - || Character.getType(primaryCode) == Character.OTHER_SYMBOL) { - didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); + if (Constants.CODE_SHORTCUT == codePoint) { + mSubtypeSwitcher.switchToShortcutIME(this); + // Still call the *#onCodeInput methods for readability. + } + final Event event = createSoftwareKeypressEvent(codeToSend, keyX, keyY, isKeyRepeat); + final InputTransaction completeInputTransaction = + mInputLogic.onCodeInput(mSettings.getCurrent(), event, + mKeyboardSwitcher.getKeyboardShiftMode(), mHandler); + updateStateAfterInputTransaction(completeInputTransaction); + mKeyboardSwitcher.onCodeInput(codePoint, getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); + } + + // A helper method to split the code point and the key code. Ultimately, they should not be + // squashed into the same variable, and this method should be removed. + private static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX, + final int keyY, final boolean isKeyRepeat) { + final int keyCode; + final int codePoint; + if (keyCodeOrCodePoint <= 0) { + keyCode = keyCodeOrCodePoint; + codePoint = Event.NOT_A_CODE_POINT; } else { - didAutoCorrect = false; - if (SPACE_STATE_PHANTOM == spaceState) { - if (settingsValues.mIsInternal) { - if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { - LatinImeLoggerUtils.onAutoCorrection( - "", mWordComposer.getTypedWord(), " ", mWordComposer); - } - } - if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { - // If we are in the middle of a recorrection, we need to commit the recorrection - // first so that we can insert the character at the current cursor position. - resetEntireInputState(mLastSelectionStart); - } else { - commitTyped(LastComposedWord.NOT_A_SEPARATOR); - } - } - final int keyX, keyY; - final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); - if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { - keyX = x; - keyY = y; - } else { - keyX = Constants.NOT_A_COORDINATE; - keyY = Constants.NOT_A_COORDINATE; - } - handleCharacter(primaryCode, keyX, keyY, spaceState); + keyCode = Event.NOT_A_KEY_CODE; + codePoint = keyCodeOrCodePoint; } - mExpectingUpdateSelection = true; - return didAutoCorrect; + return Event.createSoftwareKeypressEvent(codePoint, keyCode, keyX, keyY, isKeyRepeat); } // Called from PointerTracker through the KeyboardActionListener interface @Override public void onTextInput(final String rawText) { - mConnection.beginBatchEdit(); - if (mWordComposer.isComposingWord()) { - commitCurrentAutoCorrection(rawText); - } else { - resetComposingState(true /* alsoResetLastComposedWord */); - } - mHandler.postUpdateSuggestionStrip(); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS - && ResearchLogger.RESEARCH_KEY_OUTPUT_TEXT.equals(rawText)) { - ResearchLogger.getInstance().onResearchKeySelected(this); - return; - } - final String text = specificTldProcessingOnTextInput(rawText); - if (SPACE_STATE_PHANTOM == mSpaceState) { - promotePhantomSpace(); - } - mConnection.commitText(text, 1); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */); - } - mConnection.endBatchEdit(); - // Space state must be updated before calling updateShiftState - mSpaceState = SPACE_STATE_NONE; - mKeyboardSwitcher.updateShiftState(); - mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT); - mEnteredText = text; + // TODO: have the keyboard pass the correct key code when we need it. + final Event event = Event.createSoftwareTextEvent(rawText, Event.NOT_A_KEY_CODE); + mInputLogic.onTextInput(mSettings.getCurrent(), event, mHandler); + mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); + mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT, getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); } @Override public void onStartBatchInput() { - mInputUpdater.onStartBatchInput(); - mHandler.cancelUpdateSuggestionStrip(); - mConnection.beginBatchEdit(); - final SettingsValues settingsValues = mSettings.getCurrent(); - if (mWordComposer.isComposingWord()) { - if (settingsValues.mIsInternal) { - if (mWordComposer.isBatchMode()) { - LatinImeLoggerUtils.onAutoCorrection( - "", mWordComposer.getTypedWord(), " ", mWordComposer); - } - } - final int wordComposerSize = mWordComposer.size(); - // Since isComposingWord() is true, the size is at least 1. - if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { - // If we are in the middle of a recorrection, we need to commit the recorrection - // first so that we can insert the batch input at the current cursor position. - resetEntireInputState(mLastSelectionStart); - } else if (wordComposerSize <= 1) { - // We auto-correct the previous (typed, not gestured) string iff it's one character - // long. The reason for this is, even in the middle of gesture typing, you'll still - // tap one-letter words and you want them auto-corrected (typically, "i" in English - // should become "I"). However for any longer word, we assume that the reason for - // tapping probably is that the word you intend to type is not in the dictionary, - // so we do not attempt to correct, on the assumption that if that was a dictionary - // word, the user would probably have gestured instead. - commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR); - } else { - commitTyped(LastComposedWord.NOT_A_SEPARATOR); - } - mExpectingUpdateSelection = true; - } - final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); - if (Character.isLetterOrDigit(codePointBeforeCursor) - || settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) { - mSpaceState = SPACE_STATE_PHANTOM; - } - mConnection.endBatchEdit(); - mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); + mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); } - static final class InputUpdater implements Handler.Callback { - private final Handler mHandler; - private final LatinIME mLatinIme; - private final Object mLock = new Object(); - private boolean mInBatchInput; // synchronized using {@link #mLock}. - - InputUpdater(final LatinIME latinIme) { - final HandlerThread handlerThread = new HandlerThread( - InputUpdater.class.getSimpleName()); - handlerThread.start(); - mHandler = new Handler(handlerThread.getLooper(), this); - mLatinIme = latinIme; - } - - private static final int MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 1; - private static final int MSG_GET_SUGGESTED_WORDS = 2; - - @Override - public boolean handleMessage(final Message msg) { - // TODO: straighten message passing - we don't need two kinds of messages calling - // each other. - switch (msg.what) { - case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: - updateBatchInput((InputPointers)msg.obj, msg.arg2 /* sequenceNumber */); - break; - case MSG_GET_SUGGESTED_WORDS: - mLatinIme.getSuggestedWords(msg.arg1 /* sessionId */, - msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj); - break; - } - return true; - } - - // Run in the UI thread. - public void onStartBatchInput() { - synchronized (mLock) { - mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); - mInBatchInput = true; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); - } - } - - // Run in the Handler thread. - private void updateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { - synchronized (mLock) { - if (!mInBatchInput) { - // Batch input has ended or canceled while the message was being delivered. - return; - } - - getSuggestedWordsGestureLocked(batchPointers, sequenceNumber, - new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(final SuggestedWords suggestedWords) { - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - suggestedWords, false /* dismissGestureFloatingPreviewText */); - } - }); - } - } - - // Run in the UI thread. - public void onUpdateBatchInput(final InputPointers batchPointers, - final int sequenceNumber) { - if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { - return; - } - mHandler.obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, 0 /* arg1 */, - sequenceNumber /* arg2 */, batchPointers /* obj */).sendToTarget(); - } - - public void onCancelBatchInput() { - synchronized (mLock) { - mInBatchInput = false; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( - SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); - } - } - - // Run in the UI thread. - public void onEndBatchInput(final InputPointers batchPointers) { - synchronized(mLock) { - getSuggestedWordsGestureLocked(batchPointers, SuggestedWords.NOT_A_SEQUENCE_NUMBER, - new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(final SuggestedWords suggestedWords) { - mInBatchInput = false; - mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWords, - true /* dismissGestureFloatingPreviewText */); - mLatinIme.mHandler.onEndBatchInput(suggestedWords); - } - }); - } - } - - // {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to - // be synchronized. - private void getSuggestedWordsGestureLocked(final InputPointers batchPointers, - final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { - mLatinIme.mWordComposer.setBatchInputPointers(batchPointers); - mLatinIme.getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_GESTURE, - sequenceNumber, new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(SuggestedWords suggestedWords) { - final int suggestionCount = suggestedWords.size(); - if (suggestionCount <= 1) { - final String mostProbableSuggestion = (suggestionCount == 0) ? null - : suggestedWords.getWord(0); - callback.onGetSuggestedWords( - mLatinIme.getOlderSuggestions(mostProbableSuggestion)); - } - callback.onGetSuggestedWords(suggestedWords); - } - }); - } + @Override + public void onUpdateBatchInput(final InputPointers batchPointers) { + mInputLogic.onUpdateBatchInput(mSettings.getCurrent(), batchPointers, mKeyboardSwitcher); + } - public void getSuggestedWords(final int sessionId, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) { - mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback) - .sendToTarget(); - } + @Override + public void onEndBatchInput(final InputPointers batchPointers) { + mInputLogic.onEndBatchInput(batchPointers); + } - void quitLooper() { - mHandler.removeMessages(MSG_GET_SUGGESTED_WORDS); - mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); - mHandler.getLooper().quit(); - } + @Override + public void onCancelBatchInput() { + mInputLogic.onCancelBatchInput(mHandler); } - // This method must run in UI Thread. + // This method must run on the UI Thread. private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, final boolean dismissGestureFloatingPreviewText) { showSuggestionStrip(suggestedWords); @@ -1964,107 +1334,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - /* The sequence number member is only used in onUpdateBatchInput. It is increased each time - * auto-commit happens. The reason we need this is, when auto-commit happens we trim the - * input pointers that are held in a singleton, and to know how much to trim we rely on the - * results of the suggestion process that is held in mSuggestedWords. - * However, the suggestion process is asynchronous, and sometimes we may enter the - * onUpdateBatchInput method twice without having recomputed suggestions yet, or having - * received new suggestions generated from not-yet-trimmed input pointers. In this case, the - * mIndexOfTouchPointOfSecondWords member will be out of date, and we must not use it lest we - * remove an unrelated number of pointers (possibly even more than are left in the input - * pointers, leading to a crash). - * To avoid that, we increase the sequence number each time we auto-commit and trim the - * input pointers, and we do not use any suggested words that have been generated with an - * earlier sequence number. - */ - private int mAutoCommitSequenceNumber = 1; - @Override - public void onUpdateBatchInput(final InputPointers batchPointers) { - if (mSettings.getCurrent().mPhraseGestureEnabled) { - final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate(); - // If these suggested words have been generated with out of date input pointers, then - // we skip auto-commit (see comments above on the mSequenceNumber member). - if (null != candidate && mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) { - if (candidate.mSourceDict.shouldAutoCommit(candidate)) { - final String[] commitParts = candidate.mWord.split(" ", 2); - batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord); - promotePhantomSpace(); - mConnection.commitText(commitParts[0], 0); - mSpaceState = SPACE_STATE_PHANTOM; - mKeyboardSwitcher.updateShiftState(); - mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); - ++mAutoCommitSequenceNumber; - } - } - } - mInputUpdater.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber); - } - - // This method must run in UI Thread. - public void onEndBatchInputAsyncInternal(final SuggestedWords suggestedWords) { - final String batchInputText = suggestedWords.isEmpty() - ? null : suggestedWords.getWord(0); - if (TextUtils.isEmpty(batchInputText)) { - return; - } - mConnection.beginBatchEdit(); - if (SPACE_STATE_PHANTOM == mSpaceState) { - promotePhantomSpace(); - } - if (mSettings.getCurrent().mPhraseGestureEnabled) { - // Find the last space - final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1; - if (0 != indexOfLastSpace) { - mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1); - showSuggestionStrip(suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture()); - } - final String lastWord = batchInputText.substring(indexOfLastSpace); - mWordComposer.setBatchInputWord(lastWord); - mConnection.setComposingText(lastWord, 1); - } else { - mWordComposer.setBatchInputWord(batchInputText); - mConnection.setComposingText(batchInputText, 1); - } - mExpectingUpdateSelection = true; - mConnection.endBatchEdit(); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords); - } - // Space state must be updated before calling updateShiftState - mSpaceState = SPACE_STATE_PHANTOM; - mKeyboardSwitcher.updateShiftState(); - } - - @Override - public void onEndBatchInput(final InputPointers batchPointers) { - mInputUpdater.onEndBatchInput(batchPointers); - } - - private String specificTldProcessingOnTextInput(final String text) { - if (text.length() <= 1 || text.charAt(0) != Constants.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; - // TODO: use getCodePointBeforeCursor instead to improve performance and simplify the code - final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0); - if (lastOne != null && lastOne.length() == 1 - && lastOne.charAt(0) == Constants.CODE_PERIOD) { - return text.substring(1); - } else { - return text; - } - } - // Called from PointerTracker through the KeyboardActionListener interface @Override public void onFinishSlidingInput() { // User finished sliding input. - mKeyboardSwitcher.onFinishSlidingInput(); + mKeyboardSwitcher.onFinishSlidingInput(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); } // Called from PointerTracker through the KeyboardActionListener interface @@ -2074,476 +1349,85 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Nothing to do so far. } - @Override - public void onCancelBatchInput() { - mInputUpdater.onCancelBatchInput(); - } - - private void handleBackspace(final int spaceState) { - // We revert these in this method if the deletion doesn't happen. - mDeleteCount++; - mExpectingUpdateSelection = true; - - // In many cases, we may have to put the keyboard in auto-shift state again. However - // we want to wait a few milliseconds before doing it to avoid the keyboard flashing - // during key repeat. - mHandler.postUpdateShiftState(); - - if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { - // If we are in the middle of a recorrection, we need to commit the recorrection - // first so that we can remove the character at the current cursor position. - resetEntireInputState(mLastSelectionStart); - // When we exit this if-clause, mWordComposer.isComposingWord() will return false. - } - if (mWordComposer.isComposingWord()) { - if (mWordComposer.isBatchMode()) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - final String word = mWordComposer.getTypedWord(); - ResearchLogger.latinIME_handleBackspace_batch(word, 1); - } - final String rejectedSuggestion = mWordComposer.getTypedWord(); - mWordComposer.reset(); - mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion); - } else { - mWordComposer.deleteLast(); - } - mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); - mHandler.postUpdateSuggestionStrip(); - if (!mWordComposer.isComposingWord()) { - // If we just removed the last character, auto-caps mode may have changed so we - // need to re-evaluate. - mKeyboardSwitcher.updateShiftState(); - } - } else { - final SettingsValues currentSettings = mSettings.getCurrent(); - if (mLastComposedWord.canRevertCommit()) { - if (currentSettings.mIsInternal) { - LatinImeLoggerUtils.onAutoCorrectionCancellation(); - } - revertCommit(); - return; - } - if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(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. - mConnection.deleteSurroundingText(mEnteredText.length(), 0); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_handleBackspace_cancelTextInput(mEnteredText); - } - mEnteredText = null; - // 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 (SPACE_STATE_DOUBLE == spaceState) { - mHandler.cancelDoubleSpacePeriodTimer(); - if (mConnection.revertDoubleSpacePeriod()) { - // 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 (mConnection.revertSwapPunctuation()) { - // Likewise - return; - } - } - - // No cancelling of commit/double space/swap: we have a regular backspace. - // We should backspace one char and restart suggestion if at the end of a word. - if (mLastSelectionStart != mLastSelectionEnd) { - // If there is a selection, remove it. - final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; - mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); - // Reset mLastSelectionEnd to mLastSelectionStart. This is what is supposed to - // happen, and if it's wrong, the next call to onUpdateSelection will correct it, - // but we want to set it right away to avoid it being used with the wrong values - // later (typically, in a subsequent press on backspace). - mLastSelectionEnd = mLastSelectionStart; - mConnection.deleteSurroundingText(numCharsDeleted, 0); - } else { - // There is no selection, just delete one character. - if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { - // This should never happen. - Log.e(TAG, "Backspace when we don't know the selection position"); - } - if (mAppWorkAroundsUtils.isBeforeJellyBean() || - currentSettings.mInputAttributes.isTypeNull()) { - // There are two possible reasons to send a key event: either the field has - // type TYPE_NULL, in which case the keyboard should send events, or we are - // running in backward compatibility mode. Before Jelly bean, the keyboard - // would simulate a hardware keyboard event on pressing enter or delete. This - // is bad for many reasons (there are race conditions with commits) but some - // applications are relying on this behavior so we continue to support it for - // older apps, so we retain this behavior if the app has target SDK < JellyBean. - sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); - } - } else { - final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); - if (codePointBeforeCursor == Constants.NOT_A_CODE) { - // Nothing to delete before the cursor. We have to revert the deletion - // states that were updated at the beginning of this method. - mDeleteCount--; - mExpectingUpdateSelection = false; - return; - } - final int lengthToDelete = - Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1; - mConnection.deleteSurroundingText(lengthToDelete, 0); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - final int codePointBeforeCursorToDeleteAgain = - mConnection.getCodePointBeforeCursor(); - if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) { - final int lengthToDeleteAgain = Character.isSupplementaryCodePoint( - codePointBeforeCursorToDeleteAgain) ? 2 : 1; - mConnection.deleteSurroundingText(lengthToDeleteAgain, 0); - } - } - } - } - if (currentSettings.isSuggestionsRequested(mDisplayOrientation) - && currentSettings.mCurrentLanguageHasSpaces) { - restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); - } - // We just removed a character. We need to update the auto-caps state. - mKeyboardSwitcher.updateShiftState(); - } - } - - /* - * Strip a trailing space if necessary and returns whether it's a swap weak space situation. - */ - private boolean maybeStripSpace(final int code, - final int spaceState, final boolean isFromSuggestionStrip) { - if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { - mConnection.removeTrailingSpace(); + private boolean isSuggestionStripVisible() { + if (!hasSuggestionStripView()) { return false; } - if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState) - && isFromSuggestionStrip) { - final SettingsValues currentSettings = mSettings.getCurrent(); - if (currentSettings.isUsuallyPrecededBySpace(code)) return false; - if (currentSettings.isUsuallyFollowedBySpace(code)) return true; - mConnection.removeTrailingSpace(); - } - return false; - } - - private void handleCharacter(final int primaryCode, final int x, - final int y, final int spaceState) { - // TODO: refactor this method to stop flipping isComposingWord around all the time, and - // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter - // which has the same name as other handle* methods but is not the same. - boolean isComposingWord = mWordComposer.isComposingWord(); - - // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. - // See onStartBatchInput() to see how to do it. - final SettingsValues currentSettings = mSettings.getCurrent(); - if (SPACE_STATE_PHANTOM == spaceState && !currentSettings.isWordConnector(primaryCode)) { - if (isComposingWord) { - // Sanity check - throw new RuntimeException("Should not be composing here"); - } - promotePhantomSpace(); - } - - if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { - // If we are in the middle of a recorrection, we need to commit the recorrection - // first so that we can insert the character at the current cursor position. - resetEntireInputState(mLastSelectionStart); - isComposingWord = false; - } - // We want to find out whether to start composing a new word with this character. If so, - // we need to reset the composing state and switch isComposingWord. The order of the - // tests is important for good performance. - // We only start composing if we're not already composing. - if (!isComposingWord - // We only start composing if this is a word code point. Essentially that means it's a - // a letter or a word connector. - && currentSettings.isWordCodePoint(primaryCode) - // We never go into composing state if suggestions are not requested. - && currentSettings.isSuggestionsRequested(mDisplayOrientation) && - // In languages with spaces, we only start composing a word when we are not already - // touching a word. In languages without spaces, the above conditions are sufficient. - (!mConnection.isCursorTouchingWord(currentSettings) - || !currentSettings.mCurrentLanguageHasSpaces)) { - // Reset entirely the composing state anyway, then start composing a new word unless - // the character is a single quote or a dash. The idea here is, single quote and dash - // are not separators and they should be treated as normal characters, except in the - // first position where they should not start composing a word. - isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode - && Constants.CODE_DASH != 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 */); - } - if (isComposingWord) { - final int keyX, keyY; - if (Constants.isValidCoordinate(x) && Constants.isValidCoordinate(y)) { - final KeyDetector keyDetector = - mKeyboardSwitcher.getMainKeyboardView().getKeyDetector(); - keyX = keyDetector.getTouchX(x); - keyY = keyDetector.getTouchY(y); - } else { - keyX = x; - keyY = y; - } - mWordComposer.add(primaryCode, keyX, keyY); - // If it's the first letter, make note of auto-caps state - if (mWordComposer.size() == 1) { - mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); - } - mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); - } else { - final boolean swapWeakSpace = maybeStripSpace(primaryCode, - spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); - - sendKeyCodePoint(primaryCode); - - if (swapWeakSpace) { - swapSwapperAndSpace(); - mSpaceState = SPACE_STATE_WEAK; - } - // In case the "add to dictionary" hint was still displayed. - if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); - } - mHandler.postUpdateSuggestionStrip(); - if (currentSettings.mIsInternal) { - LatinImeLoggerUtils.onNonSeparator((char)primaryCode, x, y); - } - } - - private void handleRecapitalize() { - if (mLastSelectionStart == mLastSelectionEnd) return; // No selection - // If we have a recapitalize in progress, use it; otherwise, create a new one. - if (!mRecapitalizeStatus.isActive() - || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { - final CharSequence selectedText = - mConnection.getSelectedText(0 /* flags, 0 for no styles */); - if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection - final SettingsValues currentSettings = mSettings.getCurrent(); - mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd, - selectedText.toString(), currentSettings.mLocale, - currentSettings.mWordSeparators); - // We trim leading and trailing whitespace. - mRecapitalizeStatus.trim(); - // Trimming the object may have changed the length of the string, and we need to - // reposition the selection handles accordingly. As this result in an IPC call, - // only do it if it's actually necessary, in other words if the recapitalize status - // is not set at the same place as before. - if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { - mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); - mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); - } + if (mSuggestionStripView.isShowingAddToDictionaryHint()) { + return true; } - mConnection.finishComposingText(); - mRecapitalizeStatus.rotate(); - final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; - mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); - mConnection.deleteSurroundingText(numCharsDeleted, 0); - mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); - mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); - mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); - mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); - // Match the keyboard to the new state. - mKeyboardSwitcher.updateShiftState(); - } - - // Returns true if we do an autocorrection, false otherwise. - private boolean handleSeparator(final int primaryCode, final int x, final int y, - final int spaceState) { - boolean didAutoCorrect = false; final SettingsValues currentSettings = mSettings.getCurrent(); - // We avoid sending spaces in languages without spaces if we were composing. - final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == primaryCode - && !currentSettings.mCurrentLanguageHasSpaces && mWordComposer.isComposingWord(); - if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { - // If we are in the middle of a recorrection, we need to commit the recorrection - // first so that we can insert the separator at the current cursor position. - resetEntireInputState(mLastSelectionStart); - } - if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing - if (currentSettings.mCorrectionEnabled) { - final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR - : StringUtils.newSingleCodePointString(primaryCode); - commitCurrentAutoCorrection(separator); - didAutoCorrect = true; - } else { - commitTyped(StringUtils.newSingleCodePointString(primaryCode)); - } - } - - final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState, - Constants.SUGGESTION_STRIP_COORDINATE == x); - - if (SPACE_STATE_PHANTOM == spaceState && - currentSettings.isUsuallyPrecededBySpace(primaryCode)) { - promotePhantomSpace(); - } - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); - } - - if (!shouldAvoidSendingCode) { - sendKeyCodePoint(primaryCode); + if (null == currentSettings) { + return false; } - - if (Constants.CODE_SPACE == primaryCode) { - if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) { - if (maybeDoubleSpacePeriod()) { - mSpaceState = SPACE_STATE_DOUBLE; - } else if (!isShowingPunctuationList()) { - mSpaceState = SPACE_STATE_WEAK; - } - } - - mHandler.startDoubleSpacePeriodTimer(); - mHandler.postUpdateSuggestionStrip(); - } else { - if (swapWeakSpace) { - swapSwapperAndSpace(); - mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; - } else if (SPACE_STATE_PHANTOM == spaceState - && currentSettings.isUsuallyFollowedBySpace(primaryCode)) { - // 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. - // The case is a little different if the separator is a space stripper. Such a - // separator does not normally need a space on the right (that's the difference - // between swappers and strippers), so we should not stay in phantom space state if - // the separator is a stripper. Hence the additional test above. - 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(); + if (ImportantNoticeUtils.shouldShowImportantNotice(this, + currentSettings.mInputAttributes)) { + return true; } - if (currentSettings.mIsInternal) { - LatinImeLoggerUtils.onSeparator((char)primaryCode, x, y); + if (!currentSettings.isSuggestionStripVisible()) { + return false; } - - mKeyboardSwitcher.updateShiftState(); - return didAutoCorrect; - } - - private CharSequence getTextWithUnderline(final String text) { - return mIsAutoCorrectionIndicatorOn - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) - : text; - } - - private void handleClose() { - // TODO: Verify that words are logged properly when IME is closed. - commitTyped(LastComposedWord.NOT_A_SEPARATOR); - requestHideSelf(0); - final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); - if (mainKeyboardView != null) { - mainKeyboardView.closing(); + if (currentSettings.isApplicationSpecifiedCompletionsOn()) { + return true; } + return currentSettings.isSuggestionsRequested(); } - // TODO: make this private - // Outside LatinIME, only used by the test suite. - @UsedForTesting - boolean isShowingPunctuationList() { - if (mSuggestedWords == null) return false; - return mSettings.getCurrent().mSuggestPuncList == mSuggestedWords; + public boolean hasSuggestionStripView() { + return null != mSuggestionStripView; } - private boolean isSuggestionsStripVisible() { - final SettingsValues currentSettings = mSettings.getCurrent(); - if (mSuggestionStripView == null) - return false; - if (mSuggestionStripView.isShowingAddToDictionaryHint()) - return true; - if (null == currentSettings) - return false; - if (!currentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation)) - return false; - if (currentSettings.isApplicationSpecifiedCompletionsOn()) - return true; - return currentSettings.isSuggestionsRequested(mDisplayOrientation); - } - - private void clearSuggestionStrip() { - setSuggestedWords(SuggestedWords.EMPTY, false); - setAutoCorrectionIndicator(false); + @Override + public boolean isShowingAddToDictionaryHint() { + return hasSuggestionStripView() && mSuggestionStripView.isShowingAddToDictionaryHint(); } - private void setSuggestedWords(final SuggestedWords words, final boolean isAutoCorrection) { - mSuggestedWords = words; - if (mSuggestionStripView != null) { - mSuggestionStripView.setSuggestions(words); - mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); + @Override + public void dismissAddToDictionaryHint() { + if (!hasSuggestionStripView()) { + return; } + mSuggestionStripView.dismissAddToDictionaryHint(); } - private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { - // Put a blue underline to a word in TextView which will be auto-corrected. - if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator - && mWordComposer.isComposingWord()) { - mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; - final CharSequence textWithUnderline = - getTextWithUnderline(mWordComposer.getTypedWord()); - // TODO: when called from an updateSuggestionStrip() call that results from a posted - // message, this is called outside any batch edit. Potentially, this may result in some - // janky flickering of the screen, although the display speed makes it unlikely in - // the practice. - mConnection.setComposingText(textWithUnderline, 1); + // TODO[IL]: Define a clear interface for this + public void setSuggestedWords(final SuggestedWords suggestedWords, + final boolean isSuggestionStripVisible) { + mInputLogic.setSuggestedWords(suggestedWords); + // TODO: Modify this when we support suggestions with hard keyboard + if (!hasSuggestionStripView()) { + return; } - } - - private void updateSuggestionStrip() { - mHandler.cancelUpdateSuggestionStrip(); - final SettingsValues currentSettings = mSettings.getCurrent(); - - // Check if we have a suggestion engine attached. - if (mSuggest == null - || !currentSettings.isSuggestionsRequested(mDisplayOrientation)) { - if (mWordComposer.isComposingWord()) { - Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " - + "requested!"); - } + mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); + if (!onEvaluateInputViewShown()) { return; } - - if (!mWordComposer.isComposingWord() && !currentSettings.mBigramPredictionEnabled) { - setPunctuationSuggestions(); + if (!isSuggestionStripVisible) { + mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); return; } + mSuggestionStripView.setVisibility(View.VISIBLE); - final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>(); - getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING, - SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(final SuggestedWords suggestedWords) { - holder.set(suggestedWords); - } - } - ); - - // This line may cause the current thread to wait. - final SuggestedWords suggestedWords = holder.get(null, GET_SUGGESTED_WORDS_TIMEOUT); - if (suggestedWords != null) { - showSuggestionStrip(suggestedWords); + final SettingsValues currentSettings = mSettings.getCurrent(); + final boolean showSuggestions; + if (SuggestedWords.EMPTY == suggestedWords || suggestedWords.isPunctuationSuggestions() + || !currentSettings.isSuggestionsRequested()) { + showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle( + currentSettings.mInputAttributes); + } else { + showSuggestions = true; + } + if (showSuggestions) { + mSuggestionStripView.setSuggestions(suggestedWords, + SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); } } - private void getSuggestedWords(final int sessionId, final int sequenceNumber, + // TODO[IL]: Move this out of LatinIME. + public void getSuggestedWords(final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); - final Suggest suggest = mSuggest; - if (keyboard == null || suggest == null) { + if (keyboard == null) { callback.onGetSuggestedWords(SuggestedWords.EMPTY); return; } @@ -2552,528 +1436,83 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // should just skip whitespace if any, so 1. final SettingsValues currentSettings = mSettings.getCurrent(); final int[] additionalFeaturesOptions = currentSettings.mAdditionalFeaturesSettingValues; - final String prevWord; - if (currentSettings.mCurrentLanguageHasSpaces) { - // If we are typing in a language with spaces we can just look up the previous - // word from textview. - prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators, - mWordComposer.isComposingWord() ? 2 : 1); - } else { - prevWord = LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null - : mLastComposedWord.mCommittedWord; - } - suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(), - currentSettings.mBlockPotentiallyOffensive, currentSettings.mCorrectionEnabled, - additionalFeaturesOptions, sessionId, sequenceNumber, callback); - } - - private void getSuggestedWordsOrOlderSuggestionsAsync(final int sessionId, - final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { - mInputUpdater.getSuggestedWords(sessionId, sequenceNumber, - new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(SuggestedWords suggestedWords) { - callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions( - mWordComposer.getTypedWord(), suggestedWords)); - } - }); - } - - private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, - final SuggestedWords suggestedWords) { - // TODO: consolidate this into getSuggestedWords - // We update the suggestion strip only when we have some suggestions to show, i.e. when - // the suggestion count is > 1; else, we leave the old suggestions, with the typed word - // replaced with the new one. However, when the word is a dictionary word, or when the - // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the - // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to - // revert to suggestions - although it is unclear how we can come here if it's displayed. - if (suggestedWords.size() > 1 || typedWord.length() <= 1 - || suggestedWords.mTypedWordValid || null == mSuggestionStripView - || mSuggestionStripView.isShowingAddToDictionaryHint()) { - return suggestedWords; - } else { - return getOlderSuggestions(typedWord); - } - } - private SuggestedWords getOlderSuggestions(final String typedWord) { - SuggestedWords previousSuggestedWords = mSuggestedWords; - if (previousSuggestedWords == mSettings.getCurrent().mSuggestPuncList) { - previousSuggestedWords = SuggestedWords.EMPTY; - } - if (typedWord == null) { - return previousSuggestedWords; + if (DEBUG) { + if (mInputLogic.mWordComposer.isComposingWord() + || mInputLogic.mWordComposer.isBatchMode()) { + final String previousWord + = mInputLogic.mWordComposer.getPreviousWordForSuggestion(); + // TODO: this is for checking consistency with older versions. Remove this when + // we are confident this is stable. + // We're checking the previous word in the text field against the memorized previous + // word. If we are composing a word we should have the second word before the cursor + // memorized, otherwise we should have the first. + final CharSequence rereadPrevWord = mInputLogic.getNthPreviousWordForSuggestion( + currentSettings.mSpacingAndPunctuations, + mInputLogic.mWordComposer.isComposingWord() ? 2 : 1); + if (!TextUtils.equals(previousWord, rereadPrevWord)) { + throw new RuntimeException("Unexpected previous word: " + + previousWord + " <> " + rereadPrevWord); + } + } } - final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = - SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, - previousSuggestedWords); - return new SuggestedWords(typedWordAndPreviousSuggestions, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - false /* isPunctuationSuggestions */, - true /* isObsoleteSuggestions */, - false /* isPrediction */); + mInputLogic.mSuggest.getSuggestedWords(mInputLogic.mWordComposer, + mInputLogic.mWordComposer.getPreviousWordForSuggestion(), + keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive, + currentSettings.mCorrectionEnabled, additionalFeaturesOptions, sessionId, + sequenceNumber, callback); } - private void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) { - if (suggestedWords.isEmpty()) return; + @Override + public void showSuggestionStrip(final SuggestedWords sourceSuggestedWords) { + final SuggestedWords suggestedWords = + sourceSuggestedWords.isEmpty() ? SuggestedWords.EMPTY : sourceSuggestedWords; final String autoCorrection; if (suggestedWords.mWillAutoCorrect) { autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION); } else { // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD) // because it may differ from mWordComposer.mTypedWord. - autoCorrection = typedWord; - } - mWordComposer.setAutoCorrection(autoCorrection); - } - - private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords, - final String typedWord) { - if (suggestedWords.isEmpty()) { - // No auto-correction is available, clear the cached values. - AccessibilityUtils.getInstance().setAutoCorrection(null, null); - clearSuggestionStrip(); - return; - } - setAutoCorrection(suggestedWords, typedWord); - final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); - setSuggestedWords(suggestedWords, isAutoCorrection); - setAutoCorrectionIndicator(isAutoCorrection); - setSuggestionStripShown(isSuggestionsStripVisible()); - // An auto-correction is available, cache it in accessibility code so - // we can be speak it if the user touches a key that will insert it. - AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, typedWord); - } - - private void showSuggestionStrip(final SuggestedWords suggestedWords) { - if (suggestedWords.isEmpty()) { - clearSuggestionStrip(); - return; + autoCorrection = sourceSuggestedWords.mTypedWord; } - showSuggestionStripWithTypedWord(suggestedWords, - suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD)); - } - - private void commitCurrentAutoCorrection(final String separator) { - // Complete any pending suggestions query first - if (mHandler.hasPendingUpdateSuggestions()) { - updateSuggestionStrip(); - } - final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); - final String typedWord = mWordComposer.getTypedWord(); - final String autoCorrection = (typedAutoCorrection != null) - ? typedAutoCorrection : typedWord; - if (autoCorrection != null) { - if (TextUtils.isEmpty(typedWord)) { - throw new RuntimeException("We have an auto-correction but the typed word " - + "is empty? Impossible! I must commit suicide."); - } - if (mSettings.isInternal()) { - LatinImeLoggerUtils.onAutoCorrection( - typedWord, autoCorrection, separator, mWordComposer); - } - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - final SuggestedWords suggestedWords = mSuggestedWords; - ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, - separator, mWordComposer.isBatchMode(), suggestedWords); - } - mExpectingUpdateSelection = true; - commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, - separator); - if (!typedWord.equals(autoCorrection)) { - // This will make the correction flash for a short while as a visual clue - // to the user that auto-correction happened. It has no other effect; in particular - // note that this won't affect the text inside the text field AT ALL: it only makes - // the segment of text starting at the supplied index and running for the length - // of the auto-correction flash. At this moment, the "typedWord" argument is - // ignored by TextView. - mConnection.commitCorrection( - new CorrectionInfo(mLastSelectionEnd - typedWord.length(), - typedWord, autoCorrection)); - } + if (SuggestedWords.EMPTY == suggestedWords) { + setNeutralSuggestionStrip(); + } else { + mInputLogic.mWordComposer.setAutoCorrection(autoCorrection); + setSuggestedWords(suggestedWords, isSuggestionStripVisible()); } + // Cache the auto-correction in accessibility code so we can speak it if the user + // touches a key that will insert it. + AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords, + sourceSuggestedWords.mTypedWord); } // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} // interface @Override public void pickSuggestionManually(final int index, final SuggestedWordInfo suggestionInfo) { - final SuggestedWords suggestedWords = mSuggestedWords; - final String suggestion = suggestionInfo.mWord; - // 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, index, suggestedWords); - // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. - final int primaryCode = suggestion.charAt(0); - onCodeInput(primaryCode, - Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, - false /* isBatchMode */, suggestedWords.mIsPrediction); - } - return; - } - - mConnection.beginBatchEdit(); - final SettingsValues currentSettings = mSettings.getCurrent(); - if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0 - // In the batch input mode, a manually picked suggested word should just replace - // the current batch input text and there is no need for a phantom space. - && !mWordComposer.isBatchMode()) { - final int firstChar = Character.codePointAt(suggestion, 0); - if (!currentSettings.isWordSeparator(firstChar) - || currentSettings.isUsuallyPrecededBySpace(firstChar)) { - promotePhantomSpace(); - } - } - - if (currentSettings.isApplicationSpecifiedCompletionsOn() - && mApplicationSpecifiedCompletions != null - && index >= 0 && index < mApplicationSpecifiedCompletions.length) { - mSuggestedWords = SuggestedWords.EMPTY; - if (mSuggestionStripView != null) { - mSuggestionStripView.clear(); - } - mKeyboardSwitcher.updateShiftState(); - resetComposingState(true /* alsoResetLastComposedWord */); - final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; - mConnection.commitCompletion(completionInfo); - mConnection.endBatchEdit(); - return; - } - - // We need to log before we commit, because the word composer will store away the user - // typed word. - final String replacedWord = mWordComposer.getTypedWord(); - LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords); - mExpectingUpdateSelection = true; - commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, - LastComposedWord.NOT_A_SEPARATOR); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, - mWordComposer.isBatchMode(), suggestionInfo.mScore, suggestionInfo.mKind, - suggestionInfo.mSourceDict.mDictType); - } - mConnection.endBatchEdit(); - // Don't allow cancellation of manual pick - mLastComposedWord.deactivate(); - // Space state must be updated before calling updateShiftState - mSpaceState = SPACE_STATE_PHANTOM; - mKeyboardSwitcher.updateShiftState(); - - // We should show the "Touch again to save" hint if the user pressed the first entry - // AND it's in none of our current dictionaries (main, user or otherwise). - // Please note that if mSuggest is null, it means that everything is off: suggestion - // and correction, so we shouldn't try to show the hint - final Suggest suggest = mSuggest; - final boolean showingAddToDictionaryHint = - (SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind - || SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind) - && suggest != null - // If the suggestion is not in the dictionary, the hint should be shown. - && !AutoCorrectionUtils.isValidWord(suggest, suggestion, true); - - if (currentSettings.mIsInternal) { - LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); - } - if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { - mSuggestionStripView.showAddToDictionaryHint( - suggestion, currentSettings.mHintToSaveText); - } else { - // If we're not showing the "Touch again to save", then update the suggestion strip. - mHandler.postUpdateSuggestionStrip(); - } - } - - /** - * Commits the chosen word to the text field and saves it for later retrieval. - */ - private void commitChosenWord(final String chosenWord, final int commitType, - final String separatorString) { - final SuggestedWords suggestedWords = mSuggestedWords; - mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( - this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); - // Add the word to the user history dictionary - final String prevWord = addToUserHistoryDictionary(chosenWord); - // 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#didCommitTypedWord by string equality of the remembered - // strings. - mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord, separatorString, - prevWord); - } - - private void setPunctuationSuggestions() { - final SettingsValues currentSettings = mSettings.getCurrent(); - if (currentSettings.mBigramPredictionEnabled) { - clearSuggestionStrip(); - } else { - setSuggestedWords(currentSettings.mSuggestPuncList, false); - } - setAutoCorrectionIndicator(false); - setSuggestionStripShown(isSuggestionsStripVisible()); - } - - private String addToUserHistoryDictionary(final String suggestion) { - if (TextUtils.isEmpty(suggestion)) return null; - final Suggest suggest = mSuggest; - if (suggest == null) return null; - - // If correction is not enabled, we don't add words to the user history dictionary. - // That's to avoid unintended additions in some sensitive fields, or fields that - // expect to receive non-words. - final SettingsValues currentSettings = mSettings.getCurrent(); - if (!currentSettings.mCorrectionEnabled) return null; - - final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; - if (userHistoryDictionary == null) return null; - - final String prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators, 2); - final String secondWord; - if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { - secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); - } else { - secondWord = suggestion; - } - // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". - // We don't add words with 0-frequency (assuming they would be profanity etc.). - final int maxFreq = AutoCorrectionUtils.getMaxFrequency( - suggest.getUnigramDictionaries(), suggestion); - if (maxFreq == 0) return null; - userHistoryDictionary.addToDictionary(prevWord, secondWord, maxFreq > 0); - return prevWord; - } - - private boolean isResumableWord(final String word, final SettingsValues settings) { - final int firstCodePoint = word.codePointAt(0); - return settings.isWordCodePoint(firstCodePoint) - && Constants.CODE_SINGLE_QUOTE != firstCodePoint - && Constants.CODE_DASH != firstCodePoint; - } - - /** - * Check if the cursor is touching a word. If so, restart suggestions on this word, else - * do nothing. - */ - private void restartSuggestionsOnWordTouchedByCursor() { - // HACK: We may want to special-case some apps that exhibit bad behavior in case of - // recorrection. This is a temporary, stopgap measure that will be removed later. - // TODO: remove this. - if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return; - // A simple way to test for support from the TextView. - if (!isSuggestionsStripVisible()) return; - // Recorrection is not supported in languages without spaces because we don't know - // how to segment them yet. - if (!mSettings.getCurrent().mCurrentLanguageHasSpaces) return; - // If the cursor is not touching a word, or if there is a selection, return right away. - if (mLastSelectionStart != mLastSelectionEnd) return; - // If we don't know the cursor location, return. - if (mLastSelectionStart < 0) return; - final SettingsValues currentSettings = mSettings.getCurrent(); - if (!mConnection.isCursorTouchingWord(currentSettings)) return; - final TextRange range = mConnection.getWordRangeAtCursor(currentSettings.mWordSeparators, - 0 /* additionalPrecedingWordsCount */); - if (null == range) return; // Happens if we don't have an input connection at all - if (range.length() <= 0) return; // Race condition. No text to resume on, so bail out. - // If for some strange reason (editor bug or so) we measure the text before the cursor as - // longer than what the entire text is supposed to be, the safe thing to do is bail out. - final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor(); - if (numberOfCharsInWordBeforeCursor > mLastSelectionStart) return; - final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); - final String typedWord = range.mWord.toString(); - if (!isResumableWord(typedWord, currentSettings)) return; - int i = 0; - for (final SuggestionSpan span : range.getSuggestionSpansAtWord()) { - for (final String s : span.getSuggestions()) { - ++i; - if (!TextUtils.equals(s, typedWord)) { - suggestions.add(new SuggestedWordInfo(s, - SuggestionStripView.MAX_SUGGESTIONS - i, - SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE - /* autoCommitFirstWordConfidence */)); - } - } - } - mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard()); - mWordComposer.setCursorPositionWithinWord( - typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); - mConnection.setComposingRegion( - mLastSelectionStart - numberOfCharsInWordBeforeCursor, - mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor()); - if (suggestions.isEmpty()) { - // We come here if there weren't any suggestion spans on this word. We will try to - // compute suggestions for it instead. - mInputUpdater.getSuggestedWords(Suggest.SESSION_TYPING, - SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords( - final SuggestedWords suggestedWordsIncludingTypedWord) { - final SuggestedWords suggestedWords; - if (suggestedWordsIncludingTypedWord.size() > 1) { - // We were able to compute new suggestions for this word. - // Remove the typed word, since we don't want to display it in this - // case. The #getSuggestedWordsExcludingTypedWord() method sets - // willAutoCorrect to false. - suggestedWords = suggestedWordsIncludingTypedWord - .getSuggestedWordsExcludingTypedWord(); - } else { - // No saved suggestions, and we were unable to compute any good one - // either. Rather than displaying an empty suggestion strip, we'll - // display the original word alone in the middle. - // Since there is only one word, willAutoCorrect is false. - suggestedWords = suggestedWordsIncludingTypedWord; - } - // We need to pass typedWord because mWordComposer.mTypedWord may - // differ from typedWord. - unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip( - suggestedWords, typedWord); - }}); - } else { - // We found suggestion spans in the word. We'll create the SuggestedWords out of - // them, and make willAutoCorrect false. - final SuggestedWords suggestedWords = new SuggestedWords(suggestions, - true /* typedWordValid */, false /* willAutoCorrect */, - false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, - false /* isPrediction */); - // We need to pass typedWord because mWordComposer.mTypedWord may differ from typedWord. - unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords, typedWord); - } - } - - public void unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip( - final SuggestedWords suggestedWords, final String typedWord) { - // Note that it's very important here that suggestedWords.mWillAutoCorrect is false. - // We never want to auto-correct on a resumed suggestion. Please refer to the three places - // above in restartSuggestionsOnWordTouchedByCursor() where suggestedWords is affected. - // We also need to unset mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching - // the text to adapt it. - // TODO: remove mIsAutoCorrectionIndicatorOn (see comment on definition) - mIsAutoCorrectionIndicatorOn = false; - mHandler.showSuggestionStripWithTypedWord(suggestedWords, typedWord); - } - - /** - * 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 CharSequence word = - mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); - if (null != word) { - final String wordString = word.toString(); - restartSuggestionsOnWordBeforeCursor(wordString); - // TODO: Handle the case where the user manually moves the cursor and then backs up over - // a separator. In that case, the current log unit should not be uncommitted. - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.getInstance().uncommitCurrentLogUnit(wordString, - true /* dumpCurrentLogUnit */); - } - } + final InputTransaction completeInputTransaction = mInputLogic.onPickSuggestionManually( + mSettings.getCurrent(), index, suggestionInfo, + mKeyboardSwitcher.getKeyboardShiftMode(), mHandler); + updateStateAfterInputTransaction(completeInputTransaction); } - private void restartSuggestionsOnWordBeforeCursor(final String word) { - mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); - final int length = word.length(); - mConnection.deleteSurroundingText(length, 0); - mConnection.setComposingText(word, 1); - mHandler.postUpdateSuggestionStrip(); - } - - /** - * Retry resetting caches in the rich input connection. - * - * When the editor can't be accessed we can't reset the caches, so we schedule a retry. - * This method handles the retry, and re-schedules a new retry if we still can't access. - * We only retry up to 5 times before giving up. - * - * @param tryResumeSuggestions Whether we should resume suggestions or not. - * @param remainingTries How many times we may try again before giving up. - */ - private void retryResetCaches(final boolean tryResumeSuggestions, final int remainingTries) { - if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(mLastSelectionStart, false)) { - if (0 < remainingTries) { - mHandler.postResetCaches(tryResumeSuggestions, remainingTries - 1); - return; - } - // If remainingTries is 0, we should stop waiting for new tries, but it's still - // better to load the keyboard (less things will be broken). - } - tryFixLyingCursorPosition(); - mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent()); - if (tryResumeSuggestions) mHandler.postResumeSuggestions(); - } - - private void revertCommit() { - final String previousWord = mLastComposedWord.mPrevWord; - final String originallyTypedWord = mLastComposedWord.mTypedWord; - final String committedWord = mLastComposedWord.mCommittedWord; - final int cancelLength = committedWord.length(); - // We want java chars, not codepoints for the following. - final int separatorLength = mLastComposedWord.mSeparatorString.length(); - // TODO: should we check our saved separator against the actual contents of the text view? - final int deleteLength = cancelLength + separatorLength; - if (DEBUG) { - if (mWordComposer.isComposingWord()) { - throw new RuntimeException("revertCommit, but we are composing a word"); - } - final CharSequence wordBeforeCursor = - mConnection.getTextBeforeCursor(deleteLength, 0) - .subSequence(0, cancelLength); - if (!TextUtils.equals(committedWord, wordBeforeCursor)) { - throw new RuntimeException("revertCommit check failed: we thought we were " - + "reverting \"" + committedWord - + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); - } - } - mConnection.deleteSurroundingText(deleteLength, 0); - if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { - mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord); - } - final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString; - if (mSettings.getCurrent().mCurrentLanguageHasSpaces) { - // For languages with spaces, we revert to the typed string, but the cursor is still - // after the separator so we don't resume suggestions. If the user wants to correct - // the word, they have to press backspace again. - mConnection.commitText(stringToCommit, 1); - } else { - // For languages without spaces, we revert the typed string but the cursor is flush - // with the typed word, so we need to resume suggestions right away. - mWordComposer.setComposingWord(stringToCommit, mKeyboardSwitcher.getKeyboard()); - mConnection.setComposingText(stringToCommit, 1); - } - if (mSettings.isInternal()) { - LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString, - Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); - } - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord, - mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString); + @Override + public void showAddToDictionaryHint(final String word) { + if (!hasSuggestionStripView()) { + return; } - // Don't restart suggestion yet. We'll restart if the user deletes the - // separator. - mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; - // We have a separator between the word and the cursor: we should show predictions. - mHandler.postUpdateSuggestionStrip(); + mSuggestionStripView.showAddToDictionaryHint(word); } - // This essentially inserts a space, and that's it. - public void promotePhantomSpace() { + // This will show either an empty suggestion strip (if prediction is enabled) or + // punctuation suggestions (if it's disabled). + @Override + public void setNeutralSuggestionStrip() { final SettingsValues currentSettings = mSettings.getCurrent(); - if (currentSettings.shouldInsertSpacesAutomatically() - && currentSettings.mCurrentLanguageHasSpaces - && !mConnection.textBeforeCursorLooksLikeURL()) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_promotePhantomSpace(); - } - sendKeyCodePoint(Constants.CODE_SPACE); - } + final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled + ? SuggestedWords.EMPTY : currentSettings.mSpacingAndPunctuations.mSuggestPuncList; + setSuggestedWords(neutralSuggestions, isSuggestionStripVisible()); } // TODO: Make this private @@ -3089,18 +1528,41 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen loadSettings(); if (mKeyboardSwitcher.getMainKeyboardView() != null) { // Reload keyboard because the current language has been changed. - mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent()); + mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent(), + getCurrentAutoCapsState(), getCurrentRecapitalizeState()); + } + } + + /** + * After an input transaction has been executed, some state must be updated. This includes + * the shift state of the keyboard and suggestions. This method looks at the finished + * inputTransaction to find out what is necessary and updates the state accordingly. + * @param inputTransaction The transaction that has been executed. + */ + private void updateStateAfterInputTransaction(final InputTransaction inputTransaction) { + switch (inputTransaction.getRequiredShiftUpdate()) { + case InputTransaction.SHIFT_UPDATE_LATER: + mHandler.postUpdateShiftState(); + break; + case InputTransaction.SHIFT_UPDATE_NOW: + mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); + break; + default: // SHIFT_NO_UPDATE + } + if (inputTransaction.requiresUpdateSuggestions()) { + mHandler.postUpdateSuggestionStrip(); } } private void hapticAndAudioFeedback(final int code, final int repeatCount) { final MainKeyboardView keyboardView = mKeyboardSwitcher.getMainKeyboardView(); - if (keyboardView != null && keyboardView.isInSlidingKeyInput()) { - // No need to feedback while sliding input. + if (keyboardView != null && keyboardView.isInDraggingFinger()) { + // No need to feedback while finger is dragging. return; } if (repeatCount > 0) { - if (code == Constants.CODE_DELETE && !mConnection.canDeleteCharacters()) { + if (code == Constants.CODE_DELETE && !mInputLogic.mConnection.canDeleteCharacters()) { // No need to feedback when repeat delete key will have no effect. return; } @@ -3124,7 +1586,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onPressKey(final int primaryCode, final int repeatCount, final boolean isSinglePointer) { - mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer); + mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer, getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); hapticAndAudioFeedback(primaryCode, repeatCount); } @@ -3132,40 +1595,41 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // press matching call is {@link #onPressKey(int,int,boolean)} above. @Override public void onReleaseKey(final int primaryCode, final boolean withSliding) { - mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); + mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding, getCurrentAutoCapsState(), + getCurrentRecapitalizeState()); + } - // If accessibility is on, ensure the user receives keyboard state updates. - if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { - switch (primaryCode) { - case Constants.CODE_SHIFT: - AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); - break; - case Constants.CODE_SWITCH_ALPHA_SYMBOL: - AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); - break; - } - } + private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) { + final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId); + if (null != decoder) return decoder; + // TODO: create the decoder according to the specification + final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId); + mHardwareEventDecoders.put(deviceId, newDecoder); + return newDecoder; } // Hooks for hardware keyboard @Override - public boolean onKeyDown(final int keyCode, final KeyEvent event) { - if (!ProductionFlag.IS_HARDWARE_KEYBOARD_SUPPORTED) return super.onKeyDown(keyCode, event); - // onHardwareKeyEvent, like onKeyDown returns true if it handled the event, false if - // it doesn't know what to do with it and leave it to the application. For example, - // hardware key events for adjusting the screen's brightness are passed as is. - if (mEventInterpreter.onHardwareKeyEvent(event)) { - final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); - mCurrentlyPressedHardwareKeys.add(keyIdentifier); + public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { + if (!ProductionFlag.IS_HARDWARE_KEYBOARD_SUPPORTED) { + return super.onKeyDown(keyCode, keyEvent); + } + final Event event = getHardwareKeyEventDecoder( + keyEvent.getDeviceId()).decodeHardwareKey(keyEvent); + // If the event is not handled by LatinIME, we just pass it to the parent implementation. + // If it's handled, we return true because we did handle it. + if (event.isHandled()) { + mInputLogic.onCodeInput(mSettings.getCurrent(), event, + mKeyboardSwitcher.getKeyboardShiftMode(), mHandler); return true; } - return super.onKeyDown(keyCode, event); + return super.onKeyDown(keyCode, keyEvent); } @Override public boolean onKeyUp(final int keyCode, final KeyEvent event) { final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); - if (mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { + if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { return true; } return super.onKeyUp(keyCode, event); @@ -3177,7 +1641,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // boolean onKeyMultiple(final int keyCode, final int count, final KeyEvent event); // receive ringer mode change and network state change. - private BroadcastReceiver mReceiver = new BroadcastReceiver() { + private BroadcastReceiver mConnectivityAndRingerModeChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); @@ -3190,17 +1654,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen }; private void launchSettings() { - handleClose(); + mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR); + requestHideSelf(0); + final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); + if (mainKeyboardView != null) { + mainKeyboardView.closing(); + } launchSubActivity(SettingsActivity.class); } - public void launchKeyboardedDialogActivity(final Class<? extends Activity> activityClass) { - // Put the text in the attached EditText into a safe, saved state before switching to a - // new activity that will also use the soft keyboard. - commitTyped(LastComposedWord.NOT_A_SEPARATOR); - launchSubActivity(activityClass); - } - private void launchSubActivity(final Class<? extends Activity> activityClass) { Intent intent = new Intent(); intent.setClass(LatinIME.this, activityClass); @@ -3215,9 +1677,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final CharSequence[] items = new CharSequence[] { // TODO: Should use new string "Select active input modes". getString(R.string.language_selection_title), - getString(ApplicationUtils.getAcitivityTitleResId(this, SettingsActivity.class)), + getString(ApplicationUtils.getActivityTitleResId(this, SettingsActivity.class)), }; - final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + final OnClickListener listener = new OnClickListener() { @Override public void onClick(DialogInterface di, int position) { di.dismiss(); @@ -3226,8 +1688,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final Intent intent = IntentUtils.getInputLanguageSelectionIntent( mRichImm.getInputMethodIdOfThisIme(), Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_CLEAR_TOP); + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); break; case 1: @@ -3236,21 +1698,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } }; - final AlertDialog.Builder builder = new AlertDialog.Builder(this) - .setItems(items, listener) - .setTitle(title); - showOptionDialog(builder.create()); + final AlertDialog.Builder builder = new AlertDialog.Builder( + DialogUtils.getPlatformDialogThemeContext(this)); + builder.setItems(items, listener).setTitle(title); + final AlertDialog dialog = builder.create(); + dialog.setCancelable(true /* cancelable */); + dialog.setCanceledOnTouchOutside(true /* cancelable */); + showOptionDialog(dialog); } - public void showOptionDialog(final AlertDialog dialog) { + // TODO: Move this method out of {@link LatinIME}. + private void showOptionDialog(final AlertDialog dialog) { final IBinder windowToken = mKeyboardSwitcher.getMainKeyboardView().getWindowToken(); if (windowToken == null) { return; } - dialog.setCancelable(true); - dialog.setCanceledOnTouchOutside(true); - final Window window = dialog.getWindow(); final WindowManager.LayoutParams lp = window.getAttributes(); lp.token = windowToken; @@ -3264,31 +1727,48 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // TODO: can this be removed somehow without breaking the tests? @UsedForTesting - /* package for test */ String getFirstSuggestedWord() { - return mSuggestedWords.size() > 0 ? mSuggestedWords.getWord(0) : null; + /* package for test */ SuggestedWords getSuggestedWordsForTest() { + // You may not use this method for anything else than debug + return DEBUG ? mInputLogic.mSuggestedWords : null; } // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. @UsedForTesting - /* package for test */ boolean isCurrentlyWaitingForMainDictionary() { - return mSuggest.isCurrentlyWaitingForMainDictionary(); + /* package for test */ void waitForLoadingDictionaries(final long timeout, final TimeUnit unit) + throws InterruptedException { + mInputLogic.mSuggest.mDictionaryFacilitator.waitForLoadingDictionariesForTesting( + timeout, unit); } - // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. + // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. @UsedForTesting - /* package for test */ boolean hasMainDictionary() { - return mSuggest.hasMainDictionary(); + /* package for test */ void replaceDictionariesForTest(final Locale locale) { + final SettingsValues settingsValues = mSettings.getCurrent(); + mInputLogic.mSuggest.mDictionaryFacilitator.resetDictionaries(this, locale, + settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, + false /* forceReloadMainDictionary */, this /* listener */); } - // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. + // DO NOT USE THIS for any other purpose than testing. @UsedForTesting - /* package for test */ void replaceMainDictionaryForTest(final Locale locale) { - mSuggest.resetMainDict(this, locale, null); + /* package for test */ void clearPersonalizedDictionariesForTest() { + mInputLogic.mSuggest.mDictionaryFacilitator.clearUserHistoryDictionary(); + mInputLogic.mSuggest.mDictionaryFacilitator.clearPersonalizationDictionary(); + } + + public void dumpDictionaryForDebug(final String dictName) { + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + if (dictionaryFacilitator.getLocale() == null) { + resetSuggest(); + } + mInputLogic.mSuggest.mDictionaryFacilitator.dumpDictionaryForDebug(dictName); } public void debugDumpStateAndCrashWithException(final String context) { - final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString()); - s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) + final SettingsValues settingsValues = mSettings.getCurrent(); + final StringBuilder s = new StringBuilder(settingsValues.toString()); + s.append("\nAttributes : ").append(settingsValues.mInputAttributes) .append("\nContext : ").append(context); throw new RuntimeException(s.toString()); } @@ -3299,17 +1779,37 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final Printer p = new PrintWriterPrinter(fout); p.println("LatinIME state :"); + p.println(" VersionCode = " + ApplicationUtils.getVersionCode(this)); + p.println(" VersionName = " + ApplicationUtils.getVersionName(this)); final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; p.println(" Keyboard mode = " + keyboardMode); final SettingsValues settingsValues = mSettings.getCurrent(); - p.println(" mIsSuggestionsSuggestionsRequested = " - + settingsValues.isSuggestionsRequested(mDisplayOrientation)); - p.println(" mCorrectionEnabled=" + settingsValues.mCorrectionEnabled); - p.println(" isComposingWord=" + mWordComposer.isComposingWord()); - p.println(" mSoundOn=" + settingsValues.mSoundOn); - p.println(" mVibrateOn=" + settingsValues.mVibrateOn); - p.println(" mKeyPreviewPopupOn=" + settingsValues.mKeyPreviewPopupOn); - p.println(" inputAttributes=" + settingsValues.mInputAttributes); + p.println(settingsValues.dump()); + // TODO: Dump all settings values + } + + public boolean shouldSwitchToOtherInputMethods() { + // TODO: Revisit here to reorganize the settings. Probably we can/should use different + // strategy once the implementation of + // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well. + final boolean fallbackValue = mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList; + final IBinder token = getWindow().getWindow().getAttributes().token; + if (token == null) { + return fallbackValue; + } + return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue); + } + + public boolean shouldShowLanguageSwitchKey() { + // TODO: Revisit here to reorganize the settings. Probably we can/should use different + // strategy once the implementation of + // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well. + final boolean fallbackValue = mSettings.getCurrent().isLanguageSwitchKeyEnabled(); + final IBinder token = getWindow().getWindow().getAttributes().token; + if (token == null) { + return fallbackValue; + } + return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue); } } diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java new file mode 100644 index 000000000..4911bcdf6 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014 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.internal.KeySpecParser; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * The extended {@link SuggestedWords} class to represent punctuation suggestions. + * + * Each punctuation specification string is the key specification that can be parsed by + * {@link KeySpecParser}. + */ +public final class PunctuationSuggestions extends SuggestedWords { + private PunctuationSuggestions(final ArrayList<SuggestedWordInfo> punctuationsList) { + super(punctuationsList, + null /* rawSuggestions */, + false /* typedWordValid */, + false /* hasAutoCorrectionCandidate */, + false /* isObsoleteSuggestions */, + false /* isPrediction */); + } + + /** + * Create new instance of {@link PunctuationSuggestions} from the array of punctuation key + * specifications. + * + * @param punctuationSpecs The array of punctuation key specifications. + * @return The {@link PunctuationSuggestions} object. + */ + public static PunctuationSuggestions newPunctuationSuggestions( + final String[] punctuationSpecs) { + final ArrayList<SuggestedWordInfo> puncuationsList = CollectionUtils.newArrayList(); + for (final String puncSpec : punctuationSpecs) { + puncuationsList.add(newHardCodedWordInfo(puncSpec)); + } + return new PunctuationSuggestions(puncuationsList); + } + + /** + * {@inheritDoc} + * Note that {@link super#getWord(int)} returns a punctuation key specification text. + * The suggested punctuation should be gotten by parsing the key specification. + */ + @Override + public String getWord(final int index) { + final String keySpec = super.getWord(index); + final int code = KeySpecParser.getCode(keySpec); + return (code == Constants.CODE_OUTPUT_TEXT) + ? KeySpecParser.getOutputText(keySpec) + : StringUtils.newSingleCodePointString(code); + } + + /** + * {@inheritDoc} + * Note that {@link super#getWord(int)} returns a punctuation key specification text. + * The displayed text should be gotten by parsing the key specification. + */ + @Override + public String getLabel(final int index) { + final String keySpec = super.getWord(index); + return KeySpecParser.getLabel(keySpec); + } + + /** + * {@inheritDoc} + * Note that {@link #getWord(int)} returns a suggested punctuation. We should create a + * {@link SuggestedWordInfo} object that represents a hard coded word. + */ + @Override + public SuggestedWordInfo getInfo(final int index) { + return newHardCodedWordInfo(getWord(index)); + } + + /** + * The predicator to tell whether this object represents punctuation suggestions. + * @return true if this object represents punctuation suggestions. + */ + @Override + public boolean isPunctuationSuggestions() { + return true; + } + + @Override + public String toString() { + return "PunctuationSuggestions: " + + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray()); + } + + private static SuggestedWordInfo newHardCodedWordInfo(final String keySpec) { + return new SuggestedWordInfo(keySpec, SuggestedWordInfo.MAX_SCORE, + SuggestedWordInfo.KIND_HARDCODED, + Dictionary.DICTIONARY_HARDCODED, + SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, + SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */); + } +} diff --git a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java index 68505ce38..9f61d6c37 100644 --- a/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ReadOnlyBinaryDictionary.java @@ -51,20 +51,21 @@ public final class ReadOnlyBinaryDictionary extends Dictionary { @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, 0 /* sessionId */); + additionalFeaturesOptions, 0 /* sessionId */, inOutLanguageWeight); } @Override public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, - final int sessionId) { + final int sessionId, final float[] inOutLanguageWeight) { if (mLock.readLock().tryLock()) { try { return mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo, - blockOffensiveWords, additionalFeaturesOptions); + blockOffensiveWords, additionalFeaturesOptions, inOutLanguageWeight); } finally { mLock.readLock().unlock(); } diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 673d1b4c2..606bb775e 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -27,7 +27,7 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethod.latin.settings.SettingsValues; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.CapsModeUtils; import com.android.inputmethod.latin.utils.DebugLogUtils; import com.android.inputmethod.latin.utils.SpannableStringUtils; @@ -35,7 +35,7 @@ import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import com.android.inputmethod.research.ResearchLogger; -import java.util.Locale; +import java.util.Arrays; import java.util.regex.Pattern; /** @@ -57,14 +57,19 @@ public final class RichInputConnection { private static final int INVALID_CURSOR_POSITION = -1; /** - * This variable contains an expected value for the cursor position. This is where the - * cursor may end up after all the keyboard-triggered updates have passed. We keep this to - * compare it to the actual cursor position to guess whether the move was caused by a - * keyboard command or not. - * It's not really the cursor position: the cursor may not be there yet, and it's also expected - * there be cases where it never actually comes to be there. + * This variable contains an expected value for the selection start position. This is where the + * cursor or selection start may end up after all the keyboard-triggered updates have passed. We + * keep this to compare it to the actual selection start to guess whether the move was caused by + * a keyboard command or not. + * It's not really the selection start position: the selection start may not be there yet, and + * in some cases, it may never arrive there. */ - private int mExpectedCursorPosition = INVALID_CURSOR_POSITION; // in chars, not code points + private int mExpectedSelStart = INVALID_CURSOR_POSITION; // in chars, not code points + /** + * The expected selection end. Only differs from mExpectedSelStart if a non-empty selection is + * expected. The same caveats as mExpectedSelStart apply. + */ + private int mExpectedSelEnd = INVALID_CURSOR_POSITION; // in chars, not code points /** * This contains the committed text immediately preceding the cursor and the composing * text if any. It is refreshed when the cursor moves by calling upon the TextView. @@ -93,7 +98,7 @@ public final class RichInputConnection { final ExtractedText et = mIC.getExtractedText(r, 0); final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); - final StringBuilder internal = new StringBuilder().append(mCommittedTextBeforeComposingText) + final StringBuilder internal = new StringBuilder(mCommittedTextBeforeComposingText) .append(mComposingText); if (null == et || null == beforeCursor) return; final int actualLength = Math.min(beforeCursor.length(), internal.length()); @@ -103,16 +108,16 @@ public final class RichInputConnection { final String reference = (beforeCursor.length() <= actualLength) ? beforeCursor.toString() : beforeCursor.subSequence(beforeCursor.length() - actualLength, beforeCursor.length()).toString(); - if (et.selectionStart != mExpectedCursorPosition + if (et.selectionStart != mExpectedSelStart || !(reference.equals(internal.toString()))) { - final String context = "Expected cursor position = " + mExpectedCursorPosition - + "\nActual cursor position = " + et.selectionStart + final String context = "Expected selection start = " + mExpectedSelStart + + "\nActual selection start = " + et.selectionStart + "\nExpected text = " + internal.length() + " " + internal + "\nActual text = " + reference.length() + " " + reference; ((LatinIME)mParent).debugDumpStateAndCrashWithException(context); } else { Log.e(TAG, DebugLogUtils.getStackTrace(2)); - Log.e(TAG, "Exp <> Actual : " + mExpectedCursorPosition + " <> " + et.selectionStart); + Log.e(TAG, "Exp <> Actual : " + mExpectedSelStart + " <> " + et.selectionStart); } } @@ -150,16 +155,38 @@ public final class RichInputConnection { * data, so we empty the cache and note that we don't know the new cursor position, and we * return false so that the caller knows about this and can retry later. * - * @param newCursorPosition The new position of the cursor, as received from the system. - * @param shouldFinishComposition Whether we should finish the composition in progress. + * @param newSelStart the new position of the selection start, as received from the system. + * @param newSelEnd the new position of the selection end, as received from the system. + * @param shouldFinishComposition whether we should finish the composition in progress. * @return true if we were able to connect to the editor successfully, false otherwise. When * this method returns false, the caches could not be correctly refreshed so they were only * reset: the caller should try again later to return to normal operation. */ - public boolean resetCachesUponCursorMoveAndReturnSuccess(final int newCursorPosition, - final boolean shouldFinishComposition) { - mExpectedCursorPosition = newCursorPosition; + public boolean resetCachesUponCursorMoveAndReturnSuccess(final int newSelStart, + final int newSelEnd, final boolean shouldFinishComposition) { + mExpectedSelStart = newSelStart; + mExpectedSelEnd = newSelEnd; mComposingText.setLength(0); + final boolean didReloadTextSuccessfully = reloadTextCache(); + if (!didReloadTextSuccessfully) { + Log.d(TAG, "Will try to retrieve text later."); + return false; + } + if (null != mIC && shouldFinishComposition) { + mIC.finishComposingText(); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.richInputConnection_finishComposingText(); + } + } + return true; + } + + /** + * Reload the cached text from the InputConnection. + * + * @return true if successful + */ + private boolean reloadTextCache() { mCommittedTextBeforeComposingText.setLength(0); mIC = mParent.getCurrentInputConnection(); // Call upon the inputconnection directly since our own method is using the cache, and @@ -169,27 +196,12 @@ public final class RichInputConnection { if (null == textBeforeCursor) { // For some reason the app thinks we are not connected to it. This looks like a // framework bug... Fall back to ground state and return false. - mExpectedCursorPosition = INVALID_CURSOR_POSITION; - Log.e(TAG, "Unable to connect to the editor to retrieve text... will retry later"); + mExpectedSelStart = INVALID_CURSOR_POSITION; + mExpectedSelEnd = INVALID_CURSOR_POSITION; + Log.e(TAG, "Unable to connect to the editor to retrieve text."); return false; } mCommittedTextBeforeComposingText.append(textBeforeCursor); - final int lengthOfTextBeforeCursor = textBeforeCursor.length(); - if (lengthOfTextBeforeCursor > newCursorPosition - || (lengthOfTextBeforeCursor < Constants.EDITOR_CONTENTS_CACHE_SIZE - && newCursorPosition < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { - // newCursorPosition may be lying -- when rotating the device (probably a framework - // bug). If we have less chars than we asked for, then we know how many chars we have, - // and if we got more than newCursorPosition says, then we know it was lying. In both - // cases the length is more reliable - mExpectedCursorPosition = lengthOfTextBeforeCursor; - } - if (null != mIC && shouldFinishComposition) { - mIC.finishComposingText(); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.richInputConnection_finishComposingText(); - } - } return true; } @@ -204,6 +216,9 @@ public final class RichInputConnection { public void finishComposingText() { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); + // TODO: this is not correct! The cursor is not necessarily after the composing text. + // In the practice right now this is only called when input ends so it will be reset so + // it works, but it's wrong and should be fixed. mCommittedTextBeforeComposingText.append(mComposingText); mComposingText.setLength(0); if (null != mIC) { @@ -218,7 +233,11 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); mCommittedTextBeforeComposingText.append(text); - mExpectedCursorPosition += text.length() - mComposingText.length(); + // TODO: the following is exceedingly error-prone. Right now when the cursor is in the + // middle of the composing word mComposingText only holds the part of the composing text + // that is before the cursor, so this actually works, but it's terribly confusing. Fix this. + mExpectedSelStart += text.length() - mComposingText.length(); + mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); if (null != mIC) { mIC.commitText(text, i); @@ -226,12 +245,11 @@ public final class RichInputConnection { } public CharSequence getSelectedText(final int flags) { - if (null == mIC) return null; - return mIC.getSelectedText(flags); + return (null == mIC) ? null : mIC.getSelectedText(flags); } public boolean canDeleteCharacters() { - return mExpectedCursorPosition > 0; + return mExpectedSelStart > 0; } /** @@ -245,12 +263,12 @@ public final class RichInputConnection { * American English, it's just the most common set of rules for English). * * @param inputType a mask of the caps modes to test for. - * @param settingsValues the values of the settings to use for locale and separators. + * @param spacingAndPunctuations the values of the settings to use for locale and separators. * @param hasSpaceBefore if we should consider there should be a space after the string. * @return the caps modes that should be on as a set of bits */ - public int getCursorCapsMode(final int inputType, final SettingsValues settingsValues, - final boolean hasSpaceBefore) { + public int getCursorCapsMode(final int inputType, + final SpacingAndPunctuations spacingAndPunctuations, final boolean hasSpaceBefore) { mIC = mParent.getCurrentInputConnection(); if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF; if (!TextUtils.isEmpty(mComposingText)) { @@ -268,23 +286,22 @@ public final class RichInputConnection { // heavy pressing of delete, for example DEFAULT_TEXT_CACHE_SIZE - 5 times or so. // getCapsMode should be updated to be able to return a "not enough info" result so that // we can get more context only when needed. - if (TextUtils.isEmpty(mCommittedTextBeforeComposingText) && 0 != mExpectedCursorPosition) { - final CharSequence textBeforeCursor = getTextBeforeCursor( - Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); - if (!TextUtils.isEmpty(textBeforeCursor)) { - mCommittedTextBeforeComposingText.append(textBeforeCursor); + if (TextUtils.isEmpty(mCommittedTextBeforeComposingText) && 0 != mExpectedSelStart) { + if (!reloadTextCache()) { + Log.w(TAG, "Unable to connect to the editor. " + + "Setting caps mode without knowing text."); } } // This never calls InputConnection#getCapsMode - in fact, it's a static method that // never blocks or initiates IPC. return CapsModeUtils.getCapsMode(mCommittedTextBeforeComposingText, inputType, - settingsValues, hasSpaceBefore); + spacingAndPunctuations, hasSpaceBefore); } public int getCodePointBeforeCursor() { - if (mCommittedTextBeforeComposingText.length() < 1) return Constants.NOT_A_CODE; - return Character.codePointBefore(mCommittedTextBeforeComposingText, - mCommittedTextBeforeComposingText.length()); + final int length = mCommittedTextBeforeComposingText.length(); + if (length < 1) return Constants.NOT_A_CODE; + return Character.codePointBefore(mCommittedTextBeforeComposingText, length); } public CharSequence getTextBeforeCursor(final int n, final int flags) { @@ -295,8 +312,8 @@ public final class RichInputConnection { // However, if we don't have an expected cursor position, then we should always // go fetch the cache again (as it happens, INVALID_CURSOR_POSITION < 0, so we need to // test for this explicitly) - if (INVALID_CURSOR_POSITION != mExpectedCursorPosition - && (cachedLength >= n || cachedLength >= mExpectedCursorPosition)) { + if (INVALID_CURSOR_POSITION != mExpectedSelStart + && (cachedLength >= n || cachedLength >= mExpectedSelStart)) { final StringBuilder s = new StringBuilder(mCommittedTextBeforeComposingText); // We call #toString() here to create a temporary object. // In some situations, this method is called on a worker thread, and it's possible @@ -312,20 +329,19 @@ public final class RichInputConnection { return s; } mIC = mParent.getCurrentInputConnection(); - if (null != mIC) { - return mIC.getTextBeforeCursor(n, flags); - } - return null; + return (null == mIC) ? null : mIC.getTextBeforeCursor(n, flags); } public CharSequence getTextAfterCursor(final int n, final int flags) { mIC = mParent.getCurrentInputConnection(); - if (null != mIC) return mIC.getTextAfterCursor(n, flags); - return null; + return (null == mIC) ? null : mIC.getTextAfterCursor(n, flags); } public void deleteSurroundingText(final int beforeLength, final int afterLength) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); + // TODO: the following is incorrect if the cursor is not immediately after the composition. + // Right now we never come here in this case because we reset the composing state before we + // come here in this case, but we need to fix this. final int remainingChars = mComposingText.length() - beforeLength; if (remainingChars >= 0) { mComposingText.setLength(remainingChars); @@ -336,10 +352,14 @@ public final class RichInputConnection { + remainingChars, 0); mCommittedTextBeforeComposingText.setLength(len); } - if (mExpectedCursorPosition > beforeLength) { - mExpectedCursorPosition -= beforeLength; + if (mExpectedSelStart > beforeLength) { + mExpectedSelStart -= beforeLength; + mExpectedSelEnd -= beforeLength; } else { - mExpectedCursorPosition = 0; + // There are fewer characters before the cursor in the buffer than we are being asked to + // delete. Only delete what is there, and update the end with the amount deleted. + mExpectedSelEnd -= mExpectedSelStart; + mExpectedSelStart = 0; } if (null != mIC) { mIC.deleteSurroundingText(beforeLength, afterLength); @@ -373,7 +393,8 @@ public final class RichInputConnection { switch (keyEvent.getKeyCode()) { case KeyEvent.KEYCODE_ENTER: mCommittedTextBeforeComposingText.append("\n"); - mExpectedCursorPosition += 1; + mExpectedSelStart += 1; + mExpectedSelEnd = mExpectedSelStart; break; case KeyEvent.KEYCODE_DEL: if (0 == mComposingText.length()) { @@ -385,18 +406,24 @@ public final class RichInputConnection { } else { mComposingText.delete(mComposingText.length() - 1, mComposingText.length()); } - if (mExpectedCursorPosition > 0) mExpectedCursorPosition -= 1; + if (mExpectedSelStart > 0 && mExpectedSelStart == mExpectedSelEnd) { + // TODO: Handle surrogate pairs. + mExpectedSelStart -= 1; + } + mExpectedSelEnd = mExpectedSelStart; break; case KeyEvent.KEYCODE_UNKNOWN: if (null != keyEvent.getCharacters()) { mCommittedTextBeforeComposingText.append(keyEvent.getCharacters()); - mExpectedCursorPosition += keyEvent.getCharacters().length(); + mExpectedSelStart += keyEvent.getCharacters().length(); + mExpectedSelEnd = mExpectedSelStart; } break; default: - final String text = new String(new int[] { keyEvent.getUnicodeChar() }, 0, 1); + final String text = StringUtils.newSingleCodePointString(keyEvent.getUnicodeChar()); mCommittedTextBeforeComposingText.append(text); - mExpectedCursorPosition += text.length(); + mExpectedSelStart += text.length(); + mExpectedSelEnd = mExpectedSelStart; break; } } @@ -415,8 +442,12 @@ public final class RichInputConnection { getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE + (end - start), 0); mCommittedTextBeforeComposingText.setLength(0); if (!TextUtils.isEmpty(textBeforeCursor)) { + // The cursor is not necessarily at the end of the composing text, but we have its + // position in mExpectedSelStart and mExpectedSelEnd. In this case we want the start + // of the text, so we should use mExpectedSelStart. In other words, the composing + // text starts (mExpectedSelStart - start) characters before the end of textBeforeCursor final int indexOfStartOfComposingText = - Math.max(textBeforeCursor.length() - (end - start), 0); + Math.max(textBeforeCursor.length() - (mExpectedSelStart - start), 0); mComposingText.append(textBeforeCursor.subSequence(indexOfStartOfComposingText, textBeforeCursor.length())); mCommittedTextBeforeComposingText.append( @@ -430,10 +461,12 @@ public final class RichInputConnection { public void setComposingText(final CharSequence text, final int newCursorPosition) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); - mExpectedCursorPosition += text.length() - mComposingText.length(); + mExpectedSelStart += text.length() - mComposingText.length(); + mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); mComposingText.append(text); - // TODO: support values of i != 1. At this time, this is never called with i != 1. + // TODO: support values of newCursorPosition != 1. At this time, this is never called with + // newCursorPosition != 1. if (null != mIC) { mIC.setComposingText(text, newCursorPosition); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { @@ -443,19 +476,35 @@ public final class RichInputConnection { if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); } - public void setSelection(final int start, final int end) { + /** + * Set the selection of the text editor. + * + * Calls through to {@link InputConnection#setSelection(int, int)}. + * + * @param start the character index where the selection should start. + * @param end the character index where the selection should end. + * @return Returns true on success, false on failure: either the input connection is no longer + * valid when setting the selection or when retrieving the text cache at that point, or + * invalid arguments were passed. + */ + public boolean setSelection(final int start, final int end) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); + if (start < 0 || end < 0) { + return false; + } + mExpectedSelStart = start; + mExpectedSelEnd = end; if (null != mIC) { - mIC.setSelection(start, end); + final boolean isIcValid = mIC.setSelection(start, end); + if (!isIcValid) { + return false; + } if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.richInputConnection_setSelection(start, end); } } - mExpectedCursorPosition = start; - mCommittedTextBeforeComposingText.setLength(0); - mCommittedTextBeforeComposingText.append( - getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0)); + return reloadTextCache(); } public void commitCorrection(final CorrectionInfo correctionInfo) { @@ -476,7 +525,8 @@ public final class RichInputConnection { // text should never be null, but just in case, it's better to insert nothing than to crash if (null == text) text = ""; mCommittedTextBeforeComposingText.append(text); - mExpectedCursorPosition += text.length() - mComposingText.length(); + mExpectedSelStart += text.length() - mComposingText.length(); + mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); if (null != mIC) { mIC.commitCompletion(completionInfo); @@ -488,7 +538,8 @@ public final class RichInputConnection { } @SuppressWarnings("unused") - public String getNthPreviousWord(final String sentenceSeperators, final int n) { + public String getNthPreviousWord(final SpacingAndPunctuations spacingAndPunctuations, + final int n) { mIC = mParent.getCurrentInputConnection(); if (null == mIC) return null; final CharSequence prev = getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0); @@ -496,6 +547,9 @@ public final class RichInputConnection { final int checkLength = LOOKBACK_CHARACTER_NUM - 1; final String reference = prev.length() <= checkLength ? prev.toString() : prev.subSequence(prev.length() - checkLength, prev.length()).toString(); + // TODO: right now the following works because mComposingText holds the part of the + // composing text that is before the cursor, but this is very confusing. We should + // fix it. final StringBuilder internal = new StringBuilder() .append(mCommittedTextBeforeComposingText).append(mComposingText); if (internal.length() > checkLength) { @@ -507,11 +561,11 @@ public final class RichInputConnection { } } } - return getNthPreviousWord(prev, sentenceSeperators, n); + return getNthPreviousWord(prev, spacingAndPunctuations, n); } - private static boolean isSeparator(int code, String sep) { - return sep.indexOf(code) != -1; + private static boolean isSeparator(final int code, final int[] sortedSeparators) { + return Arrays.binarySearch(sortedSeparators, code) >= 0; } // Get the nth word before cursor. n = 1 retrieves the word immediately before the cursor, @@ -531,7 +585,7 @@ public final class RichInputConnection { // (n = 2) "abc |" -> null // (n = 2) "abc. def|" -> null public static String getNthPreviousWord(final CharSequence prev, - final String sentenceSeperators, final int n) { + final SpacingAndPunctuations spacingAndPunctuations, final int n) { if (prev == null) return null; final String[] w = spaceRegex.split(prev); @@ -543,35 +597,36 @@ public final class RichInputConnection { // If ends in a separator, return null final char lastChar = nthPrevWord.charAt(length - 1); - if (sentenceSeperators.contains(String.valueOf(lastChar))) return null; + if (spacingAndPunctuations.isWordSeparator(lastChar) + || spacingAndPunctuations.isWordConnector(lastChar)) return null; return nthPrevWord; } /** - * @param separators characters which may separate words + * @param sortedSeparators a sorted array of code points which may separate words * @return the word that surrounds the cursor, including up to one trailing * separator. For example, if the field contains "he|llo world", where | * represents the cursor, then "hello " will be returned. */ - public CharSequence getWordAtCursor(String separators) { + public CharSequence getWordAtCursor(final int[] sortedSeparators) { // getWordRangeAtCursor returns null if the connection is null - TextRange r = getWordRangeAtCursor(separators, 0); + final TextRange r = getWordRangeAtCursor(sortedSeparators, 0); return (r == null) ? null : r.mWord; } /** * Returns the text surrounding the cursor. * - * @param sep a string of characters that split words. + * @param sortedSeparators a sorted array of code points that split words. * @param additionalPrecedingWordsCount the number of words before the current word that should * be included in the returned range * @return a range containing the text surrounding the cursor */ - public TextRange getWordRangeAtCursor(final String sep, + public TextRange getWordRangeAtCursor(final int[] sortedSeparators, final int additionalPrecedingWordsCount) { mIC = mParent.getCurrentInputConnection(); - if (mIC == null || sep == null) { + if (mIC == null) { return null; } final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, @@ -590,7 +645,7 @@ public final class RichInputConnection { while (true) { // see comments below for why this is guaranteed to halt while (startIndexInBefore > 0) { final int codePoint = Character.codePointBefore(before, startIndexInBefore); - if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) { + if (isStoppingAtWhitespace == isSeparator(codePoint, sortedSeparators)) { break; // inner loop } --startIndexInBefore; @@ -611,7 +666,7 @@ public final class RichInputConnection { int endIndexInAfter = -1; while (++endIndexInAfter < after.length()) { final int codePoint = Character.codePointAt(after, endIndexInAfter); - if (isSeparator(codePoint, sep)) { + if (isSeparator(codePoint, sortedSeparators)) { break; } if (Character.isSupplementaryCodePoint(codePoint)) { @@ -619,27 +674,50 @@ public final class RichInputConnection { } } + final boolean hasUrlSpans = + SpannableStringUtils.hasUrlSpans(before, startIndexInBefore, before.length()) + || SpannableStringUtils.hasUrlSpans(after, 0, endIndexInAfter); // We don't use TextUtils#concat because it copies all spans without respect to their // nature. If the text includes a PARAGRAPH span and it has been split, then // TextUtils#concat will crash when it tries to concat both sides of it. return new TextRange( SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(before, after), - startIndexInBefore, before.length() + endIndexInAfter, before.length()); + startIndexInBefore, before.length() + endIndexInAfter, before.length(), + hasUrlSpans); } - public boolean isCursorTouchingWord(final SettingsValues settingsValues) { - final int codePointBeforeCursor = getCodePointBeforeCursor(); - if (Constants.NOT_A_CODE != codePointBeforeCursor - && !settingsValues.isWordSeparator(codePointBeforeCursor) - && !settingsValues.isWordConnector(codePointBeforeCursor)) { + public boolean isCursorTouchingWord(final SpacingAndPunctuations spacingAndPunctuations) { + if (isCursorFollowedByWordCharacter(spacingAndPunctuations)) { + // If what's after the cursor is a word character, then we're touching a word. return true; } + final String textBeforeCursor = mCommittedTextBeforeComposingText.toString(); + int indexOfCodePointInJavaChars = textBeforeCursor.length(); + int consideredCodePoint = 0 == indexOfCodePointInJavaChars ? Constants.NOT_A_CODE + : textBeforeCursor.codePointBefore(indexOfCodePointInJavaChars); + // Search for the first non word-connector char + if (spacingAndPunctuations.isWordConnector(consideredCodePoint)) { + indexOfCodePointInJavaChars -= Character.charCount(consideredCodePoint); + consideredCodePoint = 0 == indexOfCodePointInJavaChars ? Constants.NOT_A_CODE + : textBeforeCursor.codePointBefore(indexOfCodePointInJavaChars); + } + return !(Constants.NOT_A_CODE == consideredCodePoint + || spacingAndPunctuations.isWordSeparator(consideredCodePoint) + || spacingAndPunctuations.isWordConnector(consideredCodePoint)); + } + + public boolean isCursorFollowedByWordCharacter( + final SpacingAndPunctuations spacingAndPunctuations) { final CharSequence after = getTextAfterCursor(1, 0); - if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0)) - && !settingsValues.isWordConnector(after.charAt(0))) { - return true; + if (TextUtils.isEmpty(after)) { + return false; + } + final int codePointAfterCursor = Character.codePointAt(after, 0); + if (spacingAndPunctuations.isWordSeparator(codePointAfterCursor) + || spacingAndPunctuations.isWordConnector(codePointAfterCursor)) { + return false; } - return false; + return true; } public void removeTrailingSpace() { @@ -655,45 +733,6 @@ public final class RichInputConnection { return TextUtils.equals(text, beforeText); } - /* (non-javadoc) - * Returns the word before the cursor if the cursor is at the end of a word, null otherwise - */ - public CharSequence getWordBeforeCursorIfAtEndOfWord(final SettingsValues settings) { - // 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 = getTextAfterCursor(1, 0); - if (!TextUtils.isEmpty(textAfterCursor) - && !settings.isWordSeparator(textAfterCursor.charAt(0))) return null; - - // 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 = getWordAtCursor(settings.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) && Constants.CODE_SINGLE_QUOTE == word.charAt(0)) { - word = word.subSequence(1, word.length()); - } - if (TextUtils.isEmpty(word)) return null; - // Find the last code point of the string - final int lastCodePoint = Character.codePointBefore(word, word.length()); - // If for some reason the text field contains non-unicode binary data, or if the - // charsequence is exactly one char long and the contents is a low surrogate, return null. - if (!Character.isDefined(lastCodePoint)) return null; - // 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. - if (settings.isWordSeparator(lastCodePoint)) return null; - final char firstChar = word.charAt(0); // we just tested that word is not empty - if (word.length() == 1 && !Character.isLetter(firstChar)) return null; - - // We don't restart suggestion if the first character is not a letter, because we don't - // start composing when the first character is not a letter. - if (!Character.isLetter(firstChar)) return null; - - return word; - } - public boolean revertDoubleSpacePeriod() { if (DEBUG_BATCH_NESTING) checkBatchEdit(); // Here we test whether we indeed have a period and a space before us. This should not @@ -758,20 +797,30 @@ public final class RichInputConnection { * this update and not the ones in-between. This is almost impossible to achieve even trying * very very hard. * - * @param oldSelStart The value of the old cursor position in the update. - * @param newSelStart The value of the new cursor position in the update. + * @param oldSelStart The value of the old selection in the update. + * @param newSelStart The value of the new selection in the update. + * @param oldSelEnd The value of the old selection end in the update. + * @param newSelEnd The value of the new selection end in the update. * @return whether this is a belated expected update or not. */ - public boolean isBelatedExpectedUpdate(final int oldSelStart, final int newSelStart) { - // If this is an update that arrives at our expected position, it's a belated update. - if (newSelStart == mExpectedCursorPosition) return true; - // If this is an update that moves the cursor from our expected position, it must be - // an explicit move. - if (oldSelStart == mExpectedCursorPosition) return false; - // The following returns true if newSelStart is between oldSelStart and - // mCurrentCursorPosition. We assume that if the updated position is between the old - // position and the expected position, then it must be a belated update. - return (newSelStart - oldSelStart) * (mExpectedCursorPosition - newSelStart) >= 0; + public boolean isBelatedExpectedUpdate(final int oldSelStart, final int newSelStart, + final int oldSelEnd, final int newSelEnd) { + // This update is "belated" if we are expecting it. That is, mExpectedSelStart and + // mExpectedSelEnd match the new values that the TextView is updating TO. + if (mExpectedSelStart == newSelStart && mExpectedSelEnd == newSelEnd) return true; + // This update is not belated if mExpectedSelStart and mExpectedSelEnd match the old + // values, and one of newSelStart or newSelEnd is updated to a different value. In this + // case, it is likely that something other than the IME has moved the selection endpoint + // to the new value. + if (mExpectedSelStart == oldSelStart && mExpectedSelEnd == oldSelEnd + && (oldSelStart != newSelStart || oldSelEnd != newSelEnd)) return false; + // If neither of the above two cases hold, then the system may be having trouble keeping up + // with updates. If 1) the selection is a cursor, 2) newSelStart is between oldSelStart + // and mExpectedSelStart, and 3) newSelEnd is between oldSelEnd and mExpectedSelEnd, then + // assume a belated update. + return (newSelStart == newSelEnd) + && (newSelStart - oldSelStart) * (mExpectedSelStart - newSelStart) >= 0 + && (newSelEnd - oldSelEnd) * (mExpectedSelEnd - newSelEnd) >= 0; } /** @@ -784,4 +833,65 @@ public final class RichInputConnection { public boolean textBeforeCursorLooksLikeURL() { return StringUtils.lastPartLooksLikeURL(mCommittedTextBeforeComposingText); } + + /** + * Looks at the text just before the cursor to find out if we are inside a double quote. + * + * As with #textBeforeCursorLooksLikeURL, this is dependent on how much text we have cached. + * However this won't be a concrete problem in most situations, as the cache is almost always + * long enough for this use. + */ + public boolean isInsideDoubleQuoteOrAfterDigit() { + return StringUtils.isInsideDoubleQuoteOrAfterDigit(mCommittedTextBeforeComposingText); + } + + /** + * Try to get the text from the editor to expose lies the framework may have been + * telling us. Concretely, when the device rotates, the frameworks tells us about where the + * cursor used to be initially in the editor at the time it first received the focus; this + * may be completely different from the place it is upon rotation. Since we don't have any + * means to get the real value, try at least to ask the text view for some characters and + * detect the most damaging cases: when the cursor position is declared to be much smaller + * than it really is. + */ + public void tryFixLyingCursorPosition() { + final CharSequence textBeforeCursor = getTextBeforeCursor( + Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); + if (null == textBeforeCursor) { + mExpectedSelStart = mExpectedSelEnd = Constants.NOT_A_CURSOR_POSITION; + } else { + final int textLength = textBeforeCursor.length(); + if (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE + && (textLength > mExpectedSelStart + || mExpectedSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { + // It should not be possible to have only one of those variables be + // NOT_A_CURSOR_POSITION, so if they are equal, either the selection is zero-sized + // (simple cursor, no selection) or there is no cursor/we don't know its pos + final boolean wasEqual = mExpectedSelStart == mExpectedSelEnd; + mExpectedSelStart = textLength; + // We can't figure out the value of mLastSelectionEnd :( + // But at least if it's smaller than mLastSelectionStart something is wrong, + // and if they used to be equal we also don't want to make it look like there is a + // selection. + if (wasEqual || mExpectedSelStart > mExpectedSelEnd) { + mExpectedSelEnd = mExpectedSelStart; + } + } + } + } + + public int getExpectedSelectionStart() { + return mExpectedSelStart; + } + + public int getExpectedSelectionEnd() { + return mExpectedSelEnd; + } + + /** + * @return whether there is a selection currently active. + */ + public boolean hasSelection() { + return mExpectedSelEnd != mExpectedSelStart; + } } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 6b6bbf3a7..64cc562c8 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -20,6 +20,7 @@ import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; import android.content.Context; import android.content.SharedPreferences; +import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; import android.util.Log; @@ -50,7 +51,7 @@ public final class RichInputMethodManager { private static final RichInputMethodManager sInstance = new RichInputMethodManager(); private InputMethodManagerCompatWrapper mImmWrapper; - private InputMethodInfo mInputMethodInfoOfThisIme; + private InputMethodInfoCache mInputMethodInfoCache; final HashMap<InputMethodInfo, List<InputMethodSubtype>> mSubtypeListCacheWithImplicitlySelectedSubtypes = CollectionUtils.newHashMap(); final HashMap<InputMethodInfo, List<InputMethodSubtype>> @@ -83,7 +84,8 @@ public final class RichInputMethodManager { return; } mImmWrapper = new InputMethodManagerCompatWrapper(context); - mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context); + mInputMethodInfoCache = new InputMethodInfoCache( + mImmWrapper.mImm, context.getPackageName()); // Initialize additional subtypes. SubtypeLocaleUtils.init(context); @@ -99,20 +101,10 @@ public final class RichInputMethodManager { return mImmWrapper.mImm; } - private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) { - final String packageName = context.getPackageName(); - for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) { - if (imi.getPackageName().equals(packageName)) { - return imi; - } - } - throw new RuntimeException("Input method id for " + packageName + " not found."); - } - public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList( boolean allowsImplicitlySelectedSubtypes) { - return getEnabledInputMethodSubtypeList(mInputMethodInfoOfThisIme, - allowsImplicitlySelectedSubtypes); + return getEnabledInputMethodSubtypeList( + getInputMethodInfoOfThisIme(), allowsImplicitlySelectedSubtypes); } public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { @@ -153,10 +145,10 @@ public final class RichInputMethodManager { private boolean switchToNextInputMethodAndSubtype(final IBinder token) { final InputMethodManager imm = mImmWrapper.mImm; final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); - final int currentIndex = getImiIndexInList(mInputMethodInfoOfThisIme, enabledImis); + final int currentIndex = getImiIndexInList(getInputMethodInfoOfThisIme(), enabledImis); if (currentIndex == INDEX_NOT_FOUND) { Log.w(TAG, "Can't find current IME in enabled IMEs: IME package=" - + mInputMethodInfoOfThisIme.getPackageName()); + + getInputMethodInfoOfThisIme().getPackageName()); return false; } final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis); @@ -213,16 +205,45 @@ public final class RichInputMethodManager { return true; } + private static class InputMethodInfoCache { + private final InputMethodManager mImm; + private final String mImePackageName; + + private InputMethodInfo mCachedValue; + + public InputMethodInfoCache(final InputMethodManager imm, final String imePackageName) { + mImm = imm; + mImePackageName = imePackageName; + } + + public synchronized InputMethodInfo get() { + if (mCachedValue != null) { + return mCachedValue; + } + for (final InputMethodInfo imi : mImm.getInputMethodList()) { + if (imi.getPackageName().equals(mImePackageName)) { + mCachedValue = imi; + return imi; + } + } + throw new RuntimeException("Input method id for " + mImePackageName + " not found."); + } + + public synchronized void clear() { + mCachedValue = null; + } + } + public InputMethodInfo getInputMethodInfoOfThisIme() { - return mInputMethodInfoOfThisIme; + return mInputMethodInfoCache.get(); } public String getInputMethodIdOfThisIme() { - return mInputMethodInfoOfThisIme.getId(); + return getInputMethodInfoOfThisIme().getId(); } public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) { - return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype); + return checkIfSubtypeBelongsToImeAndEnabled(getInputMethodInfoOfThisIme(), subtype); } public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( @@ -258,7 +279,7 @@ public final class RichInputMethodManager { } public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) { - return getSubtypeIndexInIme(subtype, mInputMethodInfoOfThisIme) != INDEX_NOT_FOUND; + return getSubtypeIndexInIme(subtype, getInputMethodInfoOfThisIme()) != INDEX_NOT_FOUND; } private static int getSubtypeIndexInIme(final InputMethodSubtype subtype, @@ -286,7 +307,8 @@ public final class RichInputMethodManager { public boolean hasMultipleEnabledSubtypesInThisIme( final boolean shouldIncludeAuxiliarySubtypes) { - final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme); + final List<InputMethodInfo> imiList = Collections.singletonList( + getInputMethodInfoOfThisIme()); return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); } @@ -340,7 +362,7 @@ public final class RichInputMethodManager { public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString, final String keyboardLayoutSetName) { - final InputMethodInfo myImi = mInputMethodInfoOfThisIme; + final InputMethodInfo myImi = getInputMethodInfoOfThisIme(); final int count = myImi.getSubtypeCount(); for (int i = 0; i < count; i++) { final InputMethodSubtype subtype = myImi.getSubtypeAt(i); @@ -355,13 +377,14 @@ public final class RichInputMethodManager { public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) { mImmWrapper.mImm.setInputMethodAndSubtype( - token, mInputMethodInfoOfThisIme.getId(), subtype); + token, getInputMethodIdOfThisIme(), subtype); } public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) { mImmWrapper.mImm.setAdditionalInputMethodSubtypes( - mInputMethodInfoOfThisIme.getId(), subtypes); - // Clear the cache so that we go read the subtypes again next time. + getInputMethodIdOfThisIme(), subtypes); + // Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of + // subtypes again next time. clearSubtypeCaches(); } @@ -382,5 +405,26 @@ public final class RichInputMethodManager { public void clearSubtypeCaches() { mSubtypeListCacheWithImplicitlySelectedSubtypes.clear(); mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear(); + mInputMethodInfoCache.clear(); + } + + public boolean shouldOfferSwitchingToNextInputMethod(final IBinder binder, + boolean defaultValue) { + // Use the default value instead on Jelly Bean MR2 and previous, where + // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} isn't yet available. + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2) { + return defaultValue; + } + // Use the default value instead on KitKat as well, where + // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is still just a stub to + // return true always. + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { + // Make sure this is actually KitKat. + // TODO: Consider to remove this check once the *next* version becomes available. + if (Build.VERSION.CODENAME.equals("REL")) { + return defaultValue; + } + } + return mImmWrapper.shouldOfferSwitchingToNextInputMethod(binder); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index cd9c89f04..021133945 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -32,12 +32,17 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; +import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; public final class SubtypeSwitcher { private static boolean DBG = LatinImeLogger.sDBG; @@ -49,47 +54,42 @@ public final class SubtypeSwitcher { private /* final */ Resources mResources; private /* final */ ConnectivityManager mConnectivityManager; - private final NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage(); + private final LanguageOnSpacebarHelper mLanguageOnSpacebarHelper = + new LanguageOnSpacebarHelper(); private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; private InputMethodSubtype mNoLanguageSubtype; private InputMethodSubtype mEmojiSubtype; private boolean mIsNetworkConnected; + private static final String KEYBOARD_MODE = "keyboard"; // Dummy no language QWERTY subtype. See {@link R.xml.method}. - private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE = new InputMethodSubtype( - R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark, - SubtypeLocaleUtils.NO_LANGUAGE, "keyboard", "KeyboardLayoutSet=" - + SubtypeLocaleUtils.QWERTY - + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE - + ",EnabledWhenDefaultIsNotAsciiCapable," - + Constants.Subtype.ExtraValue.EMOJI_CAPABLE, - false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */); + private static final int SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE = 0xdde0bfd3; + private static final String EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE = + "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY + + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE = + InputMethodSubtypeCompatUtils.newInputMethodSubtype( + R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark, + SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE, + EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE, + false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */, + SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE); // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}. // Dummy Emoji subtype. See {@link R.xml.method}. - private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE = new InputMethodSubtype( - R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark, - SubtypeLocaleUtils.NO_LANGUAGE, "keyboard", "KeyboardLayoutSet=" - + SubtypeLocaleUtils.EMOJI + "," - + Constants.Subtype.ExtraValue.EMOJI_CAPABLE, - false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */); - - static final class NeedsToDisplayLanguage { - private int mEnabledSubtypeCount; - private boolean mIsSystemLanguageSameAsInputLanguage; - - public boolean getValue() { - return mEnabledSubtypeCount >= 2 || !mIsSystemLanguageSameAsInputLanguage; - } - - public void updateEnabledSubtypeCount(final int count) { - mEnabledSubtypeCount = count; - } - - public void updateIsSystemLanguageSameAsInputLanguage(final boolean isSame) { - mIsSystemLanguageSameAsInputLanguage = isSame; - } - } + private static final int SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE = 0xd78b2ed0; + private static final String EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE = + "KeyboardLayoutSet=" + SubtypeLocaleUtils.EMOJI + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE = + InputMethodSubtypeCompatUtils.newInputMethodSubtype( + R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark, + SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE, + EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE, + false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */, + SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE); public static SubtypeSwitcher getInstance() { return sInstance; @@ -128,7 +128,7 @@ public final class SubtypeSwitcher { public void updateParametersOnStartInputView() { final List<InputMethodSubtype> enabledSubtypesOfThisIme = mRichImm.getMyEnabledInputMethodSubtypeList(true); - mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size()); + mLanguageOnSpacebarHelper.updateEnabledSubtypes(enabledSubtypesOfThisIme); updateShortcutIME(); } @@ -177,7 +177,7 @@ public final class SubtypeSwitcher { final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); final boolean implicitlyEnabled = mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype); - mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage( + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage( sameLocale || (sameLanguage && implicitlyEnabled)); updateShortcutIME(); @@ -213,6 +213,7 @@ public final class SubtypeSwitcher { } public boolean isShortcutImeEnabled() { + updateShortcutIME(); if (mShortcutInputMethodInfo == null) { return false; } @@ -224,10 +225,13 @@ public final class SubtypeSwitcher { } public boolean isShortcutImeReady() { - if (mShortcutInputMethodInfo == null) + updateShortcutIME(); + if (mShortcutInputMethodInfo == null) { return false; - if (mShortcutSubtype == null) + } + if (mShortcutSubtype == null) { return true; + } if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) { return mIsNetworkConnected; } @@ -246,28 +250,53 @@ public final class SubtypeSwitcher { // Subtype Switching functions // ////////////////////////////////// - public boolean needsToDisplayLanguage(final Locale keyboardLocale) { - if (keyboardLocale.toString().equals(SubtypeLocaleUtils.NO_LANGUAGE)) { - return true; + public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) { + return mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(subtype); + } + + public boolean isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes() { + final Locale systemLocale = mResources.getConfiguration().locale; + final Set<InputMethodSubtype> enabledSubtypesOfEnabledImes = + new HashSet<InputMethodSubtype>(); + final InputMethodManager inputMethodManager = mRichImm.getInputMethodManager(); + final List<InputMethodInfo> enabledInputMethodInfoList = + inputMethodManager.getEnabledInputMethodList(); + for (final InputMethodInfo info : enabledInputMethodInfoList) { + final List<InputMethodSubtype> enabledSubtypes = + inputMethodManager.getEnabledInputMethodSubtypeList( + info, true /* allowsImplicitlySelectedSubtypes */); + if (enabledSubtypes.isEmpty()) { + // An IME with no subtypes is found. + return false; + } + enabledSubtypesOfEnabledImes.addAll(enabledSubtypes); } - if (!keyboardLocale.equals(getCurrentSubtypeLocale())) { - return false; + for (final InputMethodSubtype subtype : enabledSubtypesOfEnabledImes) { + if (!subtype.isAuxiliary() && !subtype.getLocale().isEmpty() + && !systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) { + return false; + } } - return mNeedsToDisplayLanguage.getValue(); + return true; } - private static Locale sForcedLocaleForTesting = null; + private static InputMethodSubtype sForcedSubtypeForTesting = null; @UsedForTesting - void forceLocale(final Locale locale) { - sForcedLocaleForTesting = locale; + void forceSubtype(final InputMethodSubtype subtype) { + sForcedSubtypeForTesting = subtype; } public Locale getCurrentSubtypeLocale() { - if (null != sForcedLocaleForTesting) return sForcedLocaleForTesting; + if (null != sForcedSubtypeForTesting) { + return LocaleUtils.constructLocaleFromString(sForcedSubtypeForTesting.getLocale()); + } return SubtypeLocaleUtils.getSubtypeLocale(getCurrentSubtype()); } public InputMethodSubtype getCurrentSubtype() { + if (null != sForcedSubtypeForTesting) { + return sForcedSubtypeForTesting; + } return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype()); } @@ -279,8 +308,8 @@ public final class SubtypeSwitcher { if (mNoLanguageSubtype != null) { return mNoLanguageSubtype; } - Log.w(TAG, "Can't find no lanugage with QWERTY subtype"); - Log.w(TAG, "No input method subtype found; return dummy subtype: " + Log.w(TAG, "Can't find any language with QWERTY subtype"); + Log.w(TAG, "No input method subtype found; returning dummy subtype: " + DUMMY_NO_LANGUAGE_SUBTYPE); return DUMMY_NO_LANGUAGE_SUBTYPE; } @@ -293,8 +322,9 @@ public final class SubtypeSwitcher { if (mEmojiSubtype != null) { return mEmojiSubtype; } - Log.w(TAG, "Can't find Emoji subtype"); - Log.w(TAG, "No input method subtype found; return dummy subtype: " + DUMMY_EMOJI_SUBTYPE); + Log.w(TAG, "Can't find emoji subtype"); + Log.w(TAG, "No input method subtype found; returning dummy subtype: " + + DUMMY_EMOJI_SUBTYPE); return DUMMY_EMOJI_SUBTYPE; } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 0a4c7a55d..db0a8a81c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -16,28 +16,20 @@ package com.android.inputmethod.latin; -import android.content.Context; -import android.preference.PreferenceManager; import android.text.TextUtils; -import android.util.Log; -import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.event.Event; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.personalization.PersonalizationDictionary; -import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary; -import com.android.inputmethod.latin.personalization.UserHistoryDictionary; -import com.android.inputmethod.latin.settings.Settings; +import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; -import com.android.inputmethod.latin.utils.BoundedTreeSet; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.SuggestionResults; import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; import java.util.Locale; -import java.util.concurrent.ConcurrentHashMap; /** * This class loads a dictionary and provides a list of suggestions for a given sequence of @@ -60,153 +52,17 @@ public final class Suggest { // Close to -2**31 private static final int SUPPRESS_SUGGEST_THRESHOLD = -2000000000; - public static final int MAX_SUGGESTIONS = 18; - - public interface SuggestInitializationListener { - public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable); - } - private static final boolean DBG = LatinImeLogger.sDBG; - - private final ConcurrentHashMap<String, Dictionary> mDictionaries = - CollectionUtils.newConcurrentHashMap(); - private HashSet<String> mOnlyDictionarySetForDebug = null; - private Dictionary mMainDictionary; - private ContactsBinaryDictionary mContactsDict; - @UsedForTesting - private boolean mIsCurrentlyWaitingForMainDictionary = false; + public final DictionaryFacilitatorForSuggest mDictionaryFacilitator = + new DictionaryFacilitatorForSuggest(); private float mAutoCorrectionThreshold; - // Locale used for upper- and title-casing words - public final Locale mLocale; - - public Suggest(final Context context, final Locale locale, - final SuggestInitializationListener listener) { - initAsynchronously(context, locale, listener); - mLocale = locale; - // initialize a debug flag for the personalization - if (Settings.readUseOnlyPersonalizationDictionaryForDebug( - PreferenceManager.getDefaultSharedPreferences(context))) { - mOnlyDictionarySetForDebug = new HashSet<String>(); - mOnlyDictionarySetForDebug.add(Dictionary.TYPE_PERSONALIZATION); - mOnlyDictionarySetForDebug.add(Dictionary.TYPE_PERSONALIZATION_PREDICTION_IN_JAVA); - } - } - - @UsedForTesting - Suggest(final AssetFileAddress[] dictionaryList, final Locale locale) { - final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(dictionaryList, - false /* useFullEditDistance */, locale); - mLocale = locale; - mMainDictionary = mainDict; - addOrReplaceDictionaryInternal(Dictionary.TYPE_MAIN, mainDict); - } - - private void initAsynchronously(final Context context, final Locale locale, - final SuggestInitializationListener listener) { - resetMainDict(context, locale, listener); - } - - private void addOrReplaceDictionaryInternal(final String key, final Dictionary dict) { - if (mOnlyDictionarySetForDebug != null && !mOnlyDictionarySetForDebug.contains(key)) { - Log.w(TAG, "Ignore add " + key + " dictionary for debug."); - return; - } - addOrReplaceDictionary(mDictionaries, key, dict); - } - - private static void addOrReplaceDictionary( - final ConcurrentHashMap<String, Dictionary> dictionaries, - final String key, final Dictionary dict) { - final Dictionary oldDict = (dict == null) - ? dictionaries.remove(key) - : dictionaries.put(key, dict); - if (oldDict != null && dict != oldDict) { - oldDict.close(); - } - } - - public void resetMainDict(final Context context, final Locale locale, - final SuggestInitializationListener listener) { - mIsCurrentlyWaitingForMainDictionary = true; - mMainDictionary = null; - if (listener != null) { - listener.onUpdateMainDictionaryAvailability(hasMainDictionary()); - } - new Thread("InitializeBinaryDictionary") { - @Override - public void run() { - final DictionaryCollection newMainDict = - DictionaryFactory.createMainDictionaryFromManager(context, locale); - addOrReplaceDictionaryInternal(Dictionary.TYPE_MAIN, newMainDict); - mMainDictionary = newMainDict; - if (listener != null) { - listener.onUpdateMainDictionaryAvailability(hasMainDictionary()); - } - mIsCurrentlyWaitingForMainDictionary = false; - } - }.start(); - } - - // The main dictionary could have been loaded asynchronously. Don't cache the return value - // of this method. - public boolean hasMainDictionary() { - return null != mMainDictionary && mMainDictionary.isInitialized(); - } - - @UsedForTesting - public boolean isCurrentlyWaitingForMainDictionary() { - return mIsCurrentlyWaitingForMainDictionary; + public Locale getLocale() { + return mDictionaryFacilitator.getLocale(); } - public Dictionary getMainDictionary() { - return mMainDictionary; - } - - public ContactsBinaryDictionary getContactsDictionary() { - return mContactsDict; - } - - public ConcurrentHashMap<String, Dictionary> getUnigramDictionaries() { - return mDictionaries; - } - - /** - * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted - * before the main dictionary, if set. This refers to the system-managed user dictionary. - */ - public void setUserDictionary(final UserBinaryDictionary userDictionary) { - addOrReplaceDictionaryInternal(Dictionary.TYPE_USER, userDictionary); - } - - /** - * Sets an optional contacts dictionary resource to be loaded. It is also possible to remove - * the contacts dictionary by passing null to this method. In this case no contacts dictionary - * won't be used. - */ - public void setContactsDictionary(final ContactsBinaryDictionary contactsDictionary) { - mContactsDict = contactsDictionary; - addOrReplaceDictionaryInternal(Dictionary.TYPE_CONTACTS, contactsDictionary); - } - - public void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) { - addOrReplaceDictionaryInternal(Dictionary.TYPE_USER_HISTORY, userHistoryDictionary); - } - - public void setPersonalizationPredictionDictionary( - final PersonalizationPredictionDictionary personalizationPredictionDictionary) { - addOrReplaceDictionaryInternal(Dictionary.TYPE_PERSONALIZATION_PREDICTION_IN_JAVA, - personalizationPredictionDictionary); - } - - public void setPersonalizationDictionary( - final PersonalizationDictionary personalizationDictionary) { - addOrReplaceDictionaryInternal(Dictionary.TYPE_PERSONALIZATION, - personalizationDictionary); - } - - public void setAutoCorrectionThreshold(float threshold) { + public void setAutoCorrectionThreshold(final float threshold) { mAutoCorrectionThreshold = threshold; } @@ -239,47 +95,53 @@ public final class Suggest { final int[] additionalFeaturesOptions, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); - final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, - MAX_SUGGESTIONS); - final String typedWord = wordComposer.getTypedWord(); final String consideredWord = trailingSingleQuotesCount > 0 ? typedWord.substring(0, typedWord.length() - trailingSingleQuotesCount) : typedWord; LatinImeLogger.onAddSuggestedWord(typedWord, Dictionary.TYPE_USER_TYPED); - final WordComposer wordComposerForLookup; - if (trailingSingleQuotesCount > 0) { - wordComposerForLookup = new WordComposer(wordComposer); - for (int i = trailingSingleQuotesCount - 1; i >= 0; --i) { - wordComposerForLookup.deleteLast(); - } + final ArrayList<SuggestedWordInfo> rawSuggestions; + if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) { + rawSuggestions = CollectionUtils.newArrayList(); } else { - wordComposerForLookup = wordComposer; - } - - for (final String key : mDictionaries.keySet()) { - final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getSuggestions(wordComposerForLookup, - prevWordForBigram, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions)); + rawSuggestions = null; } + final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( + wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords, + additionalFeaturesOptions, SESSION_TYPING, rawSuggestions); + final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); + final boolean isAllUpperCase = wordComposer.isAllUpperCase(); + final String firstSuggestion; final String whitelistedWord; - if (suggestionsSet.isEmpty()) { - whitelistedWord = null; - } else if (SuggestedWordInfo.KIND_WHITELIST != suggestionsSet.first().mKind) { - whitelistedWord = null; + if (suggestionResults.isEmpty()) { + whitelistedWord = firstSuggestion = null; } else { - whitelistedWord = suggestionsSet.first().mWord; + final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo( + suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase, + isFirstCharCapitalized, trailingSingleQuotesCount); + firstSuggestion = firstSuggestedWordInfo.mWord; + if (SuggestedWordInfo.KIND_WHITELIST != firstSuggestedWordInfo.mKind) { + whitelistedWord = null; + } else { + whitelistedWord = firstSuggestion; + } } - // The word can be auto-corrected if it has a whitelist entry that is not itself, - // or if it's a 2+ characters non-word (i.e. it's not in the dictionary). + final boolean isPrediction = !wordComposer.isComposingWord(); + + // We allow auto-correction if we have a whitelisted word, or if the word is not a valid + // word of more than 1 char, except if the first suggestion is the same as the typed string + // because in this case if it's strong enough to auto-correct that will mistakenly designate + // the second candidate for auto-correction. + // TODO: stop relying on indices to find where is the auto-correction in the suggested + // words, and correct this test. final boolean allowsToBeAutoCorrected = (null != whitelistedWord - && !whitelistedWord.equals(consideredWord)) - || (consideredWord.length() > 1 && !AutoCorrectionUtils.isValidWord(this, - consideredWord, wordComposer.isFirstCharCapitalized())); + && !whitelistedWord.equals(typedWord)) + || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord( + consideredWord, wordComposer.isFirstCharCapitalized()) + && !typedWord.equals(firstSuggestion)); final boolean hasAutoCorrection; // TODO: using isCorrectionEnabled here is not very good. It's probably useless, because @@ -287,10 +149,11 @@ public final class Suggest { // same time, it feels wrong that the SuggestedWord object includes information about // the current settings. It may also be useful to know, when the setting is off, whether // the word *would* have been auto-corrected. - if (!isCorrectionEnabled || !allowsToBeAutoCorrected || !wordComposer.isComposingWord() - || suggestionsSet.isEmpty() || wordComposer.hasDigits() - || wordComposer.isMostlyCaps() || wordComposer.isResumed() || !hasMainDictionary() - || SuggestedWordInfo.KIND_SHORTCUT == suggestionsSet.first().mKind) { + if (!isCorrectionEnabled || !allowsToBeAutoCorrected || isPrediction + || suggestionResults.isEmpty() || wordComposer.hasDigits() + || wordComposer.isMostlyCaps() || wordComposer.isResumed() + || !mDictionaryFacilitator.hasInitializedMainDictionary() + || SuggestedWordInfo.KIND_SHORTCUT == suggestionResults.first().mKind) { // If we don't have a main dictionary, we never want to auto-correct. The reason for // this is, the user may have a contact whose name happens to match a valid word in // their language, and it will unexpectedly auto-correct. For example, if the user @@ -302,19 +165,17 @@ public final class Suggest { hasAutoCorrection = false; } else { hasAutoCorrection = AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold( - suggestionsSet.first(), consideredWord, mAutoCorrectionThreshold); + suggestionResults.first(), consideredWord, mAutoCorrectionThreshold); } final ArrayList<SuggestedWordInfo> suggestionsContainer = - CollectionUtils.newArrayList(suggestionsSet); + CollectionUtils.newArrayList(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); - final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); - final boolean isAllUpperCase = wordComposer.isAllUpperCase(); if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, mLocale, isAllUpperCase, isFirstCharCapitalized, + wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, trailingSingleQuotesCount); suggestionsContainer.set(i, transformedWordInfo); } @@ -342,15 +203,13 @@ public final class Suggest { suggestionsList = suggestionsContainer; } - callback.onGetSuggestedWords(new SuggestedWords(suggestionsList, + callback.onGetSuggestedWords(new SuggestedWords(suggestionsList, rawSuggestions, // TODO: this first argument is lying. If this is a whitelisted word which is an // actual word, it says typedWordValid = false, which looks wrong. We should either // rename the attribute or change the value. - !allowsToBeAutoCorrected /* typedWordValid */, + !isPrediction && !allowsToBeAutoCorrected /* typedWordValid */, hasAutoCorrection, /* willAutoCorrect */ - false /* isPunctuationSuggestions */, - false /* isObsoleteSuggestions */, - !wordComposer.isComposingWord() /* isPrediction */, sequenceNumber)); + false /* isObsoleteSuggestions */, isPrediction, sequenceNumber)); } // Retrieves suggestions for the batch input @@ -360,23 +219,21 @@ public final class Suggest { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { - final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, - MAX_SUGGESTIONS); - - // At second character typed, search the unigrams (scores being affected by bigrams) - for (final String key : mDictionaries.keySet()) { - final Dictionary dictionary = mDictionaries.get(key); - suggestionsSet.addAll(dictionary.getSuggestionsWithSessionId(wordComposer, - prevWordForBigram, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions, sessionId)); + final ArrayList<SuggestedWordInfo> rawSuggestions; + if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) { + rawSuggestions = CollectionUtils.newArrayList(); + } else { + rawSuggestions = null; } - - for (SuggestedWordInfo wordInfo : suggestionsSet) { + final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( + wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords, + additionalFeaturesOptions, sessionId, rawSuggestions); + for (SuggestedWordInfo wordInfo : suggestionResults) { LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict.mDictType); } final ArrayList<SuggestedWordInfo> suggestionsContainer = - CollectionUtils.newArrayList(suggestionsSet); + CollectionUtils.newArrayList(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); final boolean isFirstCharCapitalized = wordComposer.wasShiftedNoLock(); final boolean isAllUpperCase = wordComposer.isAllUpperCase(); @@ -384,7 +241,7 @@ public final class Suggest { for (int i = 0; i < suggestionsCount; ++i) { final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( - wordInfo, mLocale, isAllUpperCase, isFirstCharCapitalized, + wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized, 0 /* trailingSingleQuotesCount */); suggestionsContainer.set(i, transformedWordInfo); } @@ -407,10 +264,9 @@ public final class Suggest { // In the batch input mode, the most relevant suggested word should act as a "typed word" // (typedWordValid=true), not as an "auto correct word" (willAutoCorrect=false). - callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, + callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, rawSuggestions, true /* typedWordValid */, false /* willAutoCorrect */, - false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction */, sequenceNumber)); } @@ -427,12 +283,13 @@ public final class Suggest { // than i because we added the typed word to mSuggestions without touching mScores. for (int i = 0; i < suggestionsSize - 1; ++i) { final SuggestedWordInfo cur = suggestions.get(i + 1); - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( typedWord, cur.toString(), cur.mScore); final String scoreInfoString; if (normalizedScore > 0) { scoreInfoString = String.format( - Locale.ROOT, "%d (%4.2f)", cur.mScore, normalizedScore); + Locale.ROOT, "%d (%4.2f), %s", cur.mScore, normalizedScore, + cur.mSourceDict.mDictType); } else { scoreInfoString = Integer.toString(cur.mScore); } @@ -442,22 +299,6 @@ public final class Suggest { return suggestionsList; } - private static final class SuggestedWordInfoComparator - implements Comparator<SuggestedWordInfo> { - // This comparator ranks the word info with the higher frequency first. That's because - // that's the order we want our elements in. - @Override - public int compare(final SuggestedWordInfo o1, final SuggestedWordInfo o2) { - if (o1.mScore > o2.mScore) return -1; - if (o1.mScore < o2.mScore) return 1; - if (o1.mCodePointCount < o2.mCodePointCount) return -1; - if (o1.mCodePointCount > o2.mCodePointCount) return 1; - return o1.mWord.compareTo(o2.mWord); - } - } - private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator = - new SuggestedWordInfoComparator(); - /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo( final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase, final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) { @@ -481,13 +322,4 @@ public final class Suggest { wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord, wordInfo.mAutoCommitFirstWordConfidence); } - - public void close() { - final HashSet<Dictionary> dictionaries = CollectionUtils.newHashSet(); - dictionaries.addAll(mDictionaries.values()); - for (final Dictionary dictionary : dictionaries) { - dictionary.close(); - } - mMainDictionary = null; - } } diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 97c89dd4e..dc2c9fd0e 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -26,51 +26,71 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -public final class SuggestedWords { +public class SuggestedWords { public static final int INDEX_OF_TYPED_WORD = 0; public static final int INDEX_OF_AUTO_CORRECTION = 1; public static final int NOT_A_SEQUENCE_NUMBER = -1; + // The maximum number of suggestions available. + public static final int MAX_SUGGESTIONS = 18; + private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST = CollectionUtils.newArrayList(0); public static final SuggestedWords EMPTY = new SuggestedWords( - EMPTY_WORD_INFO_LIST, false, false, false, false, false); + EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false); + public final String mTypedWord; public final boolean mTypedWordValid; // Note: this INCLUDES cases where the word will auto-correct to itself. A good definition // of what this flag means would be "the top suggestion is strong enough to auto-correct", // whether this exactly matches the user entry or not. public final boolean mWillAutoCorrect; - public final boolean mIsPunctuationSuggestions; public final boolean mIsObsoleteSuggestions; public final boolean mIsPrediction; public final int mSequenceNumber; // Sequence number for auto-commit. - private final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList; + protected final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList; + public final ArrayList<SuggestedWordInfo> mRawSuggestions; public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, + final ArrayList<SuggestedWordInfo> rawSuggestions, final boolean typedWordValid, final boolean willAutoCorrect, - final boolean isPunctuationSuggestions, final boolean isObsoleteSuggestions, final boolean isPrediction) { - this(suggestedWordInfoList, typedWordValid, willAutoCorrect, isPunctuationSuggestions, + this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction, NOT_A_SEQUENCE_NUMBER); } public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, + final ArrayList<SuggestedWordInfo> rawSuggestions, + final boolean typedWordValid, + final boolean willAutoCorrect, + final boolean isObsoleteSuggestions, + final boolean isPrediction, + final int sequenceNumber) { + this(suggestedWordInfoList, rawSuggestions, + (suggestedWordInfoList.isEmpty() || isPrediction) ? null + : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord, + typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction, + sequenceNumber); + } + + public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, + final ArrayList<SuggestedWordInfo> rawSuggestions, + final String typedWord, final boolean typedWordValid, final boolean willAutoCorrect, - final boolean isPunctuationSuggestions, final boolean isObsoleteSuggestions, final boolean isPrediction, final int sequenceNumber) { mSuggestedWordInfoList = suggestedWordInfoList; + mRawSuggestions = rawSuggestions; mTypedWordValid = typedWordValid; mWillAutoCorrect = willAutoCorrect; - mIsPunctuationSuggestions = isPunctuationSuggestions; mIsObsoleteSuggestions = isObsoleteSuggestions; mIsPrediction = isPrediction; mSequenceNumber = sequenceNumber; + mTypedWord = typedWord; } public boolean isEmpty() { @@ -81,10 +101,32 @@ public final class SuggestedWords { return mSuggestedWordInfoList.size(); } + /** + * Get suggested word at <code>index</code>. + * @param index The index of the suggested word. + * @return The suggested word. + */ public String getWord(final int index) { return mSuggestedWordInfoList.get(index).mWord; } + /** + * Get displayed text at <code>index</code>. + * In RTL languages, the displayed text on the suggestion strip may be different from the + * suggested word that is returned from {@link #getWord(int)}. For example the displayed text + * of punctuation suggestion "(" should be ")". + * @param index The index of the text to display. + * @return The text to be displayed. + */ + public String getLabel(final int index) { + return mSuggestedWordInfoList.get(index).mWord; + } + + /** + * Get {@link SuggestedWordInfo} object at <code>index</code>. + * @param index The index of the {@link SuggestedWordInfo}. + * @return The {@link SuggestedWordInfo} object. + */ public SuggestedWordInfo getInfo(final int index) { return mSuggestedWordInfoList.get(index); } @@ -104,8 +146,12 @@ public final class SuggestedWords { return debugString; } - public boolean willAutoCorrect() { - return mWillAutoCorrect; + /** + * The predicator to tell whether this object represents punctuation suggestions. + * @return false if this object desn't represent punctuation suggestions. + */ + public boolean isPunctuationSuggestions() { + return false; } @Override @@ -114,7 +160,6 @@ public final class SuggestedWords { return "SuggestedWords:" + " mTypedWordValid=" + mTypedWordValid + " mWillAutoCorrect=" + mWillAutoCorrect - + " mIsPunctuationSuggestions=" + mIsPunctuationSuggestions + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray()); } @@ -122,15 +167,10 @@ public final class SuggestedWords { final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = CollectionUtils.newArrayList(); for (final CompletionInfo info : infos) { - if (info == null) continue; - final CharSequence text = info.getText(); - if (null == text) continue; - final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED, - Dictionary.DICTIONARY_APPLICATION_DEFINED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */); - result.add(suggestedWordInfo); + if (null == info || null == info.getText()) { + continue; + } + result.add(new SuggestedWordInfo(info)); } return result; } @@ -150,7 +190,7 @@ public final class SuggestedWords { for (int index = 1; index < previousSize; index++) { final SuggestedWordInfo prevWordInfo = previousSuggestions.getInfo(index); final String prevWord = prevWordInfo.mWord; - // Filter out duplicate suggestion. + // Filter out duplicate suggestions. if (!alreadySeen.contains(prevWord)) { suggestionsList.add(prevWordInfo); alreadySeen.add(prevWord); @@ -189,6 +229,9 @@ public final class SuggestedWords { public static final int KIND_FLAG_EXACT_MATCH = 0x40000000; public final String mWord; + // The completion info from the application. Null for suggestions that don't come from + // the application (including keyboard-computed ones, so this is almost always null) + public final CompletionInfo mApplicationSpecifiedCompletionInfo; public final int mScore; public final int mKind; // one of the KIND_* constants above public final int mCodePointCount; @@ -215,6 +258,7 @@ public final class SuggestedWords { final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord, final int autoCommitFirstWordConfidence) { mWord = word; + mApplicationSpecifiedCompletionInfo = null; mScore = score; mKind = kind; mSourceDict = sourceDict; @@ -223,6 +267,22 @@ public final class SuggestedWords { mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence; } + /** + * Create a new suggested word info from an application-specified completion. + * If the passed argument or its contained text is null, this throws a NPE. + * @param applicationSpecifiedCompletion The application-specified completion info. + */ + public SuggestedWordInfo(final CompletionInfo applicationSpecifiedCompletion) { + mWord = applicationSpecifiedCompletion.getText().toString(); + mApplicationSpecifiedCompletionInfo = applicationSpecifiedCompletion; + mScore = SuggestedWordInfo.MAX_SCORE; + mKind = SuggestedWordInfo.KIND_APP_DEFINED; + mSourceDict = Dictionary.DICTIONARY_APPLICATION_DEFINED; + mCodePointCount = StringUtils.codePointCount(mWord); + mIndexOfTouchPointOfSecondWord = SuggestedWordInfo.NOT_AN_INDEX; + mAutoCommitFirstWordConfidence = SuggestedWordInfo.NOT_A_CONFIDENCE; + } + public boolean isEligibleForAutoCommit() { return (KIND_CORRECTION == mKind && NOT_AN_INDEX != mIndexOfTouchPointOfSecondWord); } @@ -278,17 +338,21 @@ public final class SuggestedWords { // words from the member ArrayList as some other parties may expect the object to never change. public SuggestedWords getSuggestedWordsExcludingTypedWord() { final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList(); + String typedWord = null; for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) { final SuggestedWordInfo info = mSuggestedWordInfoList.get(i); if (SuggestedWordInfo.KIND_TYPED != info.mKind) { newSuggestions.add(info); + } else { + assert(null == typedWord); + typedWord = info.mWord; } } // We should never autocorrect, so we say the typed word is valid. Also, in this case, // no auto-correction should take place hence willAutoCorrect = false. - return new SuggestedWords(newSuggestions, true /* typedWordValid */, - false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions, - mIsPrediction); + return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord, + true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions, + mIsPrediction, NOT_A_SEQUENCE_NUMBER); } // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the @@ -306,8 +370,7 @@ public final class SuggestedWords { info.mSourceDict, SuggestedWordInfo.NOT_AN_INDEX, SuggestedWordInfo.NOT_A_CONFIDENCE)); } - return new SuggestedWords(newSuggestions, mTypedWordValid, - mWillAutoCorrect, mIsPunctuationSuggestions, mIsObsoleteSuggestions, - mIsPrediction); + return new SuggestedWords(newSuggestions, null /* rawSuggestions */, mTypedWordValid, + mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction); } } diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index 15b3d8d02..b21f30087 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -18,7 +18,6 @@ package com.android.inputmethod.latin; import android.content.ContentProviderClient; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; @@ -30,9 +29,9 @@ import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.compat.UserDictionaryCompatUtils; -import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; +import java.io.File; import java.util.Arrays; import java.util.Locale; @@ -75,24 +74,31 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final private String mLocale; final private boolean mAlsoUseMoreRestrictiveLocales; - public UserBinaryDictionary(final Context context, final String locale) { - this(context, locale, false); + public UserBinaryDictionary(final Context context, final Locale locale) { + this(context, locale, false /* alsoUseMoreRestrictiveLocales */, null /* dictFile */); } - public UserBinaryDictionary(final Context context, final String locale, - final boolean alsoUseMoreRestrictiveLocales) { - super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_USER, - false /* isUpdatable */); + public UserBinaryDictionary(final Context context, final Locale locale, final File dictFile) { + this(context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile); + } + + public UserBinaryDictionary(final Context context, final Locale locale, + final boolean alsoUseMoreRestrictiveLocales, final File dictFile) { + this(context, locale, alsoUseMoreRestrictiveLocales, dictFile, NAME); + } + + protected UserBinaryDictionary(final Context context, final Locale locale, + final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) { + super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile); if (null == locale) throw new NullPointerException(); // Catch the error earlier - if (SubtypeLocaleUtils.NO_LANGUAGE.equals(locale)) { + final String localeStr = locale.toString(); + if (SubtypeLocaleUtils.NO_LANGUAGE.equals(localeStr)) { // If we don't have a locale, insert into the "all locales" user dictionary. mLocale = USER_DICTIONARY_ALL_LANGUAGES; } else { - mLocale = locale; + mLocale = localeStr; } mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales; - // Perform a managed query. The Activity will handle closing and re-querying the cursor - // when needed. ContentResolver cres = context.getContentResolver(); mObserver = new ContentObserver(null) { @@ -108,12 +114,11 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { // devices. On older versions of the platform, the hook above will be called instead. @Override public void onChange(final boolean self, final Uri uri) { - setRequiresReload(true); + setNeedsToReload(); } }; cres.registerContentObserver(Words.CONTENT_URI, true, mObserver); - - loadDictionary(); + reloadDictionaryIfRequired(); } @Override @@ -126,7 +131,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } @Override - public void loadDictionaryAsync() { + public void loadInitialContentsLocked() { // Split the locale. For example "en" => ["en"], "de_DE" => ["de", "DE"], // "en_US_foo_bar_qux" => ["en", "US", "foo_bar_qux"] because of the limit of 3. // This is correct for locale processing. @@ -178,7 +183,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { try { cursor = mContext.getContentResolver().query( Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null); - addWords(cursor); + addWordsLocked(cursor); } catch (final SQLiteException e) { Log.e(TAG, "SQLiteException in the remote User dictionary process.", e); } finally { @@ -190,8 +195,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } } - public boolean isEnabled() { - final ContentResolver cr = mContext.getContentResolver(); + public static boolean isEnabled(final Context context) { + final ContentResolver cr = context.getContentResolver(); final ContentProviderClient client = cr.acquireContentProviderClient(Words.CONTENT_URI); if (client != null) { client.release(); @@ -204,18 +209,15 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { /** * Adds a word to the user dictionary and makes it persistent. * + * @param context the context + * @param locale the locale * @param word the word to add. If the word is capitalized, then the dictionary will * recognize it as a capitalized word when searched. */ - public synchronized void addWordToUserDictionary(final String word) { + public static void addWordToUserDictionary(final Context context, final Locale locale, + final String word) { // Update the user dictionary provider - final Locale locale; - if (USER_DICTIONARY_ALL_LANGUAGES == mLocale) { - locale = null; - } else { - locale = LocaleUtils.constructLocaleFromString(mLocale); - } - UserDictionaryCompatUtils.addWord(mContext, word, + UserDictionaryCompatUtils.addWord(context, word, HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY, null, locale); } @@ -232,7 +234,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } } - private void addWords(final Cursor cursor) { + private void addWordsLocked(final Cursor cursor) { final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; if (cursor == null) return; if (cursor.moveToFirst()) { @@ -246,12 +248,16 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency); // Safeguard against adding really long words. if (word.length() < MAX_WORD_LENGTH) { - super.addWord(word, null, adjustedFrequency, 0 /* shortcutFreq */, - false /* isNotAWord */); - } - if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) { - super.addWord(shortcut, word, adjustedFrequency, USER_DICT_SHORTCUT_FREQUENCY, - true /* isNotAWord */); + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addWordDynamicallyLocked(word, adjustedFrequency, null /* shortcutTarget */, + 0 /* shortcutFreq */, false /* isNotAWord */, + false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) { + runGCIfRequiredLocked(true /* mindsBlockByGC */); + addWordDynamicallyLocked(shortcut, adjustedFrequency, word, + USER_DICT_SHORTCUT_FREQUENCY, true /* isNotAWord */, + false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + } } cursor.moveToNext(); } @@ -259,12 +265,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } @Override - protected boolean hasContentChanged() { - return true; - } - - @Override - protected boolean needsToReloadBeforeWriting() { + protected boolean haveContentsChanged() { return true; } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 039dadc66..d755195f2 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,11 +16,14 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.event.CombinerChain; +import com.android.inputmethod.event.Event; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.StringUtils; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; /** * A place to store the currently composing word with information such as adjacent key codes as well @@ -37,17 +40,16 @@ public final class WordComposer { public static final int CAPS_MODE_AUTO_SHIFTED = 0x5; public static final int CAPS_MODE_AUTO_SHIFT_LOCKED = 0x7; - // An array of code points representing the characters typed so far. - // The array is limited to MAX_WORD_LENGTH code points, but mTypedWord extends past that - // and mCodePointSize can go past that. If mCodePointSize is greater than MAX_WORD_LENGTH, - // this just does not contain the associated code points past MAX_WORD_LENGTH. - private int[] mPrimaryKeyCodes; + private CombinerChain mCombinerChain; + + // The list of events that served to compose this string. + private final ArrayList<Event> mEvents; private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); - // This is the typed word, as a StringBuilder. This has the same contents as mPrimaryKeyCodes - // but under a StringBuilder representation for ease of use, depending on what is more useful - // at any given time. However this is not limited in size, while mPrimaryKeyCodes is limited - // to MAX_WORD_LENGTH code points. - private final StringBuilder mTypedWord; + // The previous word (before the composing word). Used as context for suggestions. May be null + // after resetting and before starting a new composing word, or when there is no context like + // at the start of text for example. It can also be set to null externally when the user + // enters a separator that does not let bigrams across, like a period or a comma. + private String mPreviousWordForSuggestion; private String mAutoCorrection; private boolean mIsResumed; private boolean mIsBatchMode; @@ -60,10 +62,10 @@ public final class WordComposer { private String mRejectedBatchModeSuggestion; // Cache these values for performance + private CharSequence mTypedWordCache; private int mCapsCount; private int mDigitsCount; private int mCapitalizedMode; - private int mTrailingSingleQuotesCount; // This is the number of code points entered so far. This is not limited to MAX_WORD_LENGTH. // In general, this contains the size of mPrimaryKeyCodes, except when this is greater than // MAX_WORD_LENGTH in which case mPrimaryKeyCodes only contain the first MAX_WORD_LENGTH @@ -77,79 +79,83 @@ public final class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; - mTypedWord = new StringBuilder(MAX_WORD_LENGTH); + mCombinerChain = new CombinerChain(); + mEvents = CollectionUtils.newArrayList(); mAutoCorrection = null; - mTrailingSingleQuotesCount = 0; mIsResumed = false; mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; - refreshSize(); - } - - public WordComposer(final WordComposer source) { - mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length); - mTypedWord = new StringBuilder(source.mTypedWord); - mInputPointers.copy(source.mInputPointers); - mCapsCount = source.mCapsCount; - mDigitsCount = source.mDigitsCount; - mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; - mCapitalizedMode = source.mCapitalizedMode; - mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; - mIsResumed = source.mIsResumed; - mIsBatchMode = source.mIsBatchMode; - mCursorPositionWithinWord = source.mCursorPositionWithinWord; - mRejectedBatchModeSuggestion = source.mRejectedBatchModeSuggestion; - refreshSize(); + mPreviousWordForSuggestion = null; + refreshTypedWordCache(); } /** * Clear out the keys registered so far. */ public void reset() { - mTypedWord.setLength(0); + mCombinerChain.reset(); + mEvents.clear(); mAutoCorrection = null; mCapsCount = 0; mDigitsCount = 0; mIsFirstCharCapitalized = false; - mTrailingSingleQuotesCount = 0; mIsResumed = false; mIsBatchMode = false; mCursorPositionWithinWord = 0; mRejectedBatchModeSuggestion = null; - refreshSize(); + mPreviousWordForSuggestion = null; + refreshTypedWordCache(); } - private final void refreshSize() { - mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length()); + private final void refreshTypedWordCache() { + mTypedWordCache = mCombinerChain.getComposingWordWithCombiningFeedback(); + mCodePointSize = Character.codePointCount(mTypedWordCache, 0, mTypedWordCache.length()); } /** * Number of keystrokes in the composing word. * @return the number of keystrokes */ - public final int size() { + // This may be made public if need be, but right now it's not used anywhere + /* package for tests */ int size() { return mCodePointSize; } - public final boolean isComposingWord() { - return size() > 0; - } + /** + * Copy the code points in the typed word to a destination array of ints. + * + * If the array is too small to hold the code points in the typed word, nothing is copied and + * -1 is returned. + * + * @param destination the array of ints. + * @return the number of copied code points. + */ + public int copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount( + final int[] destination) { + // lastIndex is exclusive + final int lastIndex = mTypedWordCache.length() - trailingSingleQuotesCount(); + if (lastIndex <= 0) { + // The string is empty or contains only single quotes. + return 0; + } - // TODO: make sure that the index should not exceed MAX_WORD_LENGTH - public int getCodeAt(int index) { - if (index >= MAX_WORD_LENGTH) { + // The following function counts the number of code points in the text range which begins + // at index 0 and extends to the character at lastIndex. + final int codePointSize = Character.codePointCount(mTypedWordCache, 0, lastIndex); + if (codePointSize > destination.length) { return -1; } - return mPrimaryKeyCodes[index]; + return StringUtils.copyCodePointsAndReturnCodePointCount(destination, mTypedWordCache, 0, + lastIndex, true /* downCase */); } - public int getCodeBeforeCursor() { - if (mCursorPositionWithinWord < 1 || mCursorPositionWithinWord > mPrimaryKeyCodes.length) { - return Constants.NOT_A_CODE; - } - return mPrimaryKeyCodes[mCursorPositionWithinWord - 1]; + public boolean isSingleLetter() { + return size() == 1; + } + + public final boolean isComposingWord() { + return size() > 0; } public InputPointers getInputPointers() { @@ -163,38 +169,47 @@ public final class WordComposer { } /** - * Add a new keystroke, with the pressed key's code point with the touch point coordinates. + * Process an input event. + * + * All input events should be supported, including software/hardware events, characters as well + * as deletions, multiple inputs and gestures. + * + * @param event the event to process. */ - public void add(final int primaryCode, final int keyX, final int keyY) { + public void processEvent(final Event event) { + final int primaryCode = event.mCodePoint; + final int keyX = event.mX; + final int keyY = event.mY; final int newIndex = size(); - mTypedWord.appendCodePoint(primaryCode); - refreshSize(); + mCombinerChain.processEvent(mEvents, event); + mEvents.add(event); + refreshTypedWordCache(); mCursorPositionWithinWord = mCodePointSize; - if (newIndex < MAX_WORD_LENGTH) { - mPrimaryKeyCodes[newIndex] = primaryCode >= Constants.CODE_SPACE - ? Character.toLowerCase(primaryCode) : primaryCode; - // In the batch input mode, the {@code mInputPointers} holds batch input points and - // shouldn't be overridden by the "typed key" coordinates - // (See {@link #setBatchInputWord}). - if (!mIsBatchMode) { - // TODO: Set correct pointer id and time - mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); - } + // We may have deleted the last one. + if (0 == mCodePointSize) { + mIsFirstCharCapitalized = false; } - mIsFirstCharCapitalized = isFirstCharCapitalized( - newIndex, primaryCode, mIsFirstCharCapitalized); - if (Character.isUpperCase(primaryCode)) mCapsCount++; - if (Character.isDigit(primaryCode)) mDigitsCount++; - if (Constants.CODE_SINGLE_QUOTE == primaryCode) { - ++mTrailingSingleQuotesCount; - } else { - mTrailingSingleQuotesCount = 0; + if (Constants.CODE_DELETE != event.mKeyCode) { + if (newIndex < MAX_WORD_LENGTH) { + // In the batch input mode, the {@code mInputPointers} holds batch input points and + // shouldn't be overridden by the "typed key" coordinates + // (See {@link #setBatchInputWord}). + if (!mIsBatchMode) { + // TODO: Set correct pointer id and time + mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); + } + } + mIsFirstCharCapitalized = isFirstCharCapitalized( + newIndex, primaryCode, mIsFirstCharCapitalized); + if (Character.isUpperCase(primaryCode)) mCapsCount++; + if (Character.isDigit(primaryCode)) mDigitsCount++; } mAutoCorrection = null; } public void setCursorPositionWithinWord(final int posWithinWord) { mCursorPositionWithinWord = posWithinWord; + // TODO: compute where that puts us inside the events } public boolean isCursorFrontOrMiddleOfComposingWord() { @@ -215,17 +230,12 @@ public final class WordComposer { * @return true if the cursor is still inside the composing word, false otherwise. */ public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) { + // TODO: should uncommit the composing feedback + mCombinerChain.reset(); int actualMoveAmountWithinWord = 0; int cursorPos = mCursorPositionWithinWord; - final int[] codePoints; - if (mCodePointSize >= MAX_WORD_LENGTH) { - // If we have more than MAX_WORD_LENGTH characters, we don't have everything inside - // mPrimaryKeyCodes. This should be rare enough that we can afford to just compute - // the array on the fly when this happens. - codePoints = StringUtils.toCodePointArray(mTypedWord.toString()); - } else { - codePoints = mPrimaryKeyCodes; - } + // TODO: Don't make that copy. We can do this directly from mTypedWordCache. + final int[] codePoints = StringUtils.toCodePointArray(mTypedWordCache); if (expectedMoveAmount >= 0) { // Moving the cursor forward for the expected amount or until the end of the word has // been reached, whichever comes first. @@ -261,78 +271,29 @@ public final class WordComposer { final int codePoint = Character.codePointAt(word, i); // We don't want to override the batch input points that are held in mInputPointers // (See {@link #add(int,int,int)}). - add(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); - } - } - - /** - * Add a dummy key by retrieving reasonable coordinates - */ - public void addKeyInfo(final int codePoint, final Keyboard keyboard) { - final int x, y; - final Key key; - if (keyboard != null && (key = keyboard.getKey(codePoint)) != null) { - x = key.getX() + key.getWidth() / 2; - y = key.getY() + key.getHeight() / 2; - } else { - x = Constants.NOT_A_COORDINATE; - y = Constants.NOT_A_COORDINATE; + processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); } - add(codePoint, x, y); } /** * 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. + * @param codePoints the code points to set as the composing word. + * @param coordinates the x, y coordinates of the key in the CoordinateUtils format + * @param previousWord the previous word, to use as context for suggestions. Can be null if + * the context is nil (typically, at start of text). */ - public void setComposingWord(final CharSequence word, final Keyboard keyboard) { + public void setComposingWord(final int[] codePoints, final int[] coordinates, + final CharSequence previousWord) { reset(); - final int length = word.length(); - for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { - final int codePoint = Character.codePointAt(word, i); - addKeyInfo(codePoint, keyboard); + final int length = codePoints.length; + for (int i = 0; i < length; ++i) { + processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], + CoordinateUtils.xFromArray(coordinates, i), + CoordinateUtils.yFromArray(coordinates, i))); } mIsResumed = true; - } - - /** - * Delete the last keystroke as a result of hitting backspace. - */ - public void deleteLast() { - final int size = size(); - if (size > 0) { - // 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 (Character.isDigit(lastChar)) mDigitsCount--; - refreshSize(); - } - // We may have deleted the last one. - if (0 == size()) { - mIsFirstCharCapitalized = false; - } - if (mTrailingSingleQuotesCount > 0) { - --mTrailingSingleQuotesCount; - } else { - int i = mTypedWord.length(); - while (i > 0) { - i = mTypedWord.offsetByCodePoints(i, -1); - if (Constants.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; - ++mTrailingSingleQuotesCount; - } - } - mCursorPositionWithinWord = mCodePointSize; - mAutoCorrection = null; + mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString(); } /** @@ -340,7 +301,11 @@ public final class WordComposer { * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { - return mTypedWord.toString(); + return mTypedWordCache.toString(); + } + + public String getPreviousWordForSuggestion() { + return mPreviousWordForSuggestion; } /** @@ -352,7 +317,12 @@ public final class WordComposer { } public int trailingSingleQuotesCount() { - return mTrailingSingleQuotesCount; + final int lastIndex = mTypedWordCache.length() - 1; + int i = lastIndex; + while (i >= 0 && mTypedWordCache.charAt(i) == Constants.CODE_SINGLE_QUOTE) { + --i; + } + return lastIndex - i; } /** @@ -388,18 +358,21 @@ public final class WordComposer { } /** - * Saves the caps mode at the start of composing. + * Saves the caps mode and the previous word at the start of composing. * - * WordComposer needs to know about this for several reasons. The first is, we need to know - * after the fact what the reason was, to register the correct form into the user history - * dictionary: if the word was automatically capitalized, we should insert it in all-lower - * case but if it's a manual pressing of shift, then it should be inserted as is. + * WordComposer needs to know about the caps mode for several reasons. The first is, we need + * to know after the fact what the reason was, to register the correct form into the user + * history dictionary: if the word was automatically capitalized, we should insert it in + * all-lower case but if it's a manual pressing of shift, then it should be inserted as is. * Also, batch input needs to know about the current caps mode to display correctly * capitalized suggestions. * @param mode the mode at the time of start + * @param previousWord the previous word as context for suggestions. May be null if none. */ - public void setCapitalizedModeAtStartComposingTime(final int mode) { + public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode, + final CharSequence previousWord) { mCapitalizedMode = mode; + mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString(); } /** @@ -433,15 +406,14 @@ public final class WordComposer { } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. - public LastComposedWord commitWord(final int type, final String committedWord, + // committedWord should contain suggestion spans if applicable. + public LastComposedWord commitWord(final int type, final CharSequence committedWord, final String separatorString, final String prevWord) { // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate // the last composed word to ensure this does not happen. - final int[] primaryKeyCodes = mPrimaryKeyCodes; - mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; - final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, - mInputPointers, mTypedWord.toString(), committedWord, separatorString, + final LastComposedWord lastComposedWord = new LastComposedWord(mEvents, + mInputPointers, mTypedWordCache.toString(), committedWord, separatorString, prevWord, mCapitalizedMode); mInputPointers.reset(); if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD @@ -451,12 +423,13 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; - mTypedWord.setLength(0); + mPreviousWordForSuggestion = committedWord.toString(); + mCombinerChain.reset(); + mEvents.clear(); mCodePointSize = 0; - mTrailingSingleQuotesCount = 0; mIsFirstCharCapitalized = false; mCapitalizedMode = CAPS_MODE_OFF; - refreshSize(); + refreshTypedWordCache(); mAutoCorrection = null; mCursorPositionWithinWord = 0; mIsResumed = false; @@ -464,17 +437,26 @@ public final class WordComposer { return lastComposedWord; } - public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { - mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; + // Call this when the recorded previous word should be discarded. This is typically called + // when the user inputs a separator that's not whitespace (including the case of the + // double-space-to-period feature). + public void discardPreviousWordForSuggestion() { + mPreviousWordForSuggestion = null; + } + + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, + final String previousWord) { + mEvents.clear(); + Collections.copy(mEvents, lastComposedWord.mEvents); mInputPointers.set(lastComposedWord.mInputPointers); - mTypedWord.setLength(0); - mTypedWord.append(lastComposedWord.mTypedWord); - refreshSize(); + mCombinerChain.reset(); + refreshTypedWordCache(); mCapitalizedMode = lastComposedWord.mCapitalizedMode; mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. mCursorPositionWithinWord = mCodePointSize; mRejectedBatchModeSuggestion = null; mIsResumed = true; + mPreviousWordForSuggestion = previousWord; } public boolean isBatchMode() { diff --git a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java index 028f78a87..139e73aa4 100644 --- a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java +++ b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java @@ -26,8 +26,9 @@ import android.os.Environment; import com.android.inputmethod.latin.BinaryDictionaryFileDumper; import com.android.inputmethod.latin.BinaryDictionaryGetter; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; import com.android.inputmethod.latin.utils.LocaleUtils; @@ -51,7 +52,7 @@ public class ExternalDictionaryGetterForDebug { final File[] files = new File(SOURCE_FOLDER).listFiles(); final ArrayList<String> eligibleList = CollectionUtils.newArrayList(); for (File f : files) { - final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(f); + final DictionaryHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(f); if (null == header) continue; eligibleList.add(f.getName()); } @@ -70,7 +71,7 @@ public class ExternalDictionaryGetterForDebug { } private static void showNoFileDialog(final Context context) { - new AlertDialog.Builder(context) + new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context)) .setMessage(R.string.read_external_dictionary_no_files_message) .setPositiveButton(android.R.string.ok, new OnClickListener() { @Override @@ -81,8 +82,8 @@ public class ExternalDictionaryGetterForDebug { } private static void showChooseFileDialog(final Context context, final String[] fileNames) { - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.read_external_dictionary_multiple_files_title) + new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context)) + .setTitle(R.string.read_external_dictionary_multiple_files_title) .setItems(fileNames, new OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { @@ -99,7 +100,7 @@ public class ExternalDictionaryGetterForDebug { public static void askInstallFile(final Context context, final String dirPath, final String fileName, final Runnable completeRunnable) { final File file = new File(dirPath, fileName.toString()); - final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file); + final DictionaryHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file); final StringBuilder message = new StringBuilder(); final String locale = header.getLocaleString(); for (String key : header.mDictionaryOptions.mAttributes.keySet()) { @@ -111,7 +112,7 @@ public class ExternalDictionaryGetterForDebug { final String title = String.format( context.getString(R.string.read_external_dictionary_confirm_install_message), languageName); - new AlertDialog.Builder(context) + new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context)) .setTitle(title) .setMessage(message) .setNegativeButton(android.R.string.cancel, new OnClickListener() { @@ -143,7 +144,7 @@ public class ExternalDictionaryGetterForDebug { } private static void installFile(final Context context, final File file, - final FileHeader header) { + final DictionaryHeader header) { BufferedOutputStream outputStream = null; File tempFile = null; try { @@ -167,7 +168,7 @@ public class ExternalDictionaryGetterForDebug { } } catch (IOException e) { // There was an error: show a dialog - new AlertDialog.Builder(context) + new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context)) .setTitle(R.string.error) .setMessage(e.toString()) .setPositiveButton(android.R.string.ok, new OnClickListener() { diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java index dc937fb25..af899c040 100644 --- a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java +++ b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java @@ -29,4 +29,13 @@ public final class ProductionFlag { public static final boolean USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG = false; public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false; + + // When true, enable {@link InputMethodService#onUpdateCursor} callback with + // {@link InputMethodService#setCursorAnchorMonitorMode}, which is not yet available in + // API level 19. Do not turn this on in production until the new API becomes publicly + // available. + public static final boolean USES_CURSOR_ANCHOR_MONITOR = false; + + // Include all suggestions from all dictionaries in {@link SuggestedWords#mRawSuggestions}. + public static final boolean INCLUDE_RAW_SUGGESTIONS = false; } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java new file mode 100644 index 000000000..d2100d415 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -0,0 +1,2008 @@ +/* + * Copyright (C) 2013 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.inputlogic; + +import android.os.SystemClock; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.SuggestionSpan; +import android.util.Log; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.inputmethod.CorrectionInfo; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.compat.SuggestionSpanUtils; +import com.android.inputmethod.event.Event; +import com.android.inputmethod.event.InputTransaction; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest; +import com.android.inputmethod.latin.InputPointers; +import com.android.inputmethod.latin.LastComposedWord; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.RichInputConnection; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.define.ProductionFlag; +import com.android.inputmethod.latin.settings.SettingsValues; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; +import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; +import com.android.inputmethod.latin.utils.AsyncResultHolder; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.InputTypeUtils; +import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; +import com.android.inputmethod.latin.utils.RecapitalizeStatus; +import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.TextRange; +import com.android.inputmethod.research.ResearchLogger; + +import java.util.ArrayList; +import java.util.TreeSet; +import java.util.concurrent.TimeUnit; + +/** + * This class manages the input logic. + */ +public final class InputLogic { + private static final String TAG = InputLogic.class.getSimpleName(); + + // TODO : Remove this member when we can. + private final LatinIME mLatinIME; + private final SuggestionStripViewAccessor mSuggestionStripViewAccessor; + + // Never null. + private InputLogicHandler mInputLogicHandler = InputLogicHandler.NULL_HANDLER; + + // TODO : make all these fields private as soon as possible. + // Current space state of the input method. This can be any of the above constants. + private int mSpaceState; + // Never null + public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; + public final Suggest mSuggest = new Suggest(); + + public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + public final WordComposer mWordComposer; + public final RichInputConnection mConnection; + private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); + + private int mDeleteCount; + private long mLastKeyTime; + public final TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet(); + + // Keeps track of most recently inserted text (multi-character key) for reverting + private String mEnteredText; + + // TODO: This boolean is persistent state and causes large side effects at unexpected times. + // Find a way to remove it for readability. + private boolean mIsAutoCorrectionIndicatorOn; + private long mDoubleSpacePeriodCountdownStart; + + public InputLogic(final LatinIME latinIME, + final SuggestionStripViewAccessor suggestionStripViewAccessor) { + mLatinIME = latinIME; + mSuggestionStripViewAccessor = suggestionStripViewAccessor; + mWordComposer = new WordComposer(); + mConnection = new RichInputConnection(latinIME); + mInputLogicHandler = InputLogicHandler.NULL_HANDLER; + } + + /** + * Initializes the input logic for input in an editor. + * + * Call this when input starts or restarts in some editor (typically, in onStartInputView). + * If the input is starting in the same field as before, set `restarting' to true. This allows + * the input logic to reset only necessary stuff and save performance. Also, when restarting + * some things must not be done (for example, the keyboard should not be reset to the + * alphabetic layout), so do not send false to this just in case. + * + * @param restarting whether input is starting in the same field as before. Unused for now. + * @param editorInfo the editorInfo associated with the editor. + */ + public void startInput(final boolean restarting, final EditorInfo editorInfo) { + mEnteredText = null; + resetComposingState(true /* alsoResetLastComposedWord */); + mDeleteCount = 0; + mSpaceState = SpaceState.NONE; + mRecapitalizeStatus.deactivate(); + mCurrentlyPressedHardwareKeys.clear(); + mSuggestedWords = SuggestedWords.EMPTY; + // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying + // so we try using some heuristics to find out about these and fix them. + mConnection.tryFixLyingCursorPosition(); + cancelDoubleSpacePeriodCountdown(); + if (InputLogicHandler.NULL_HANDLER == mInputLogicHandler) { + mInputLogicHandler = new InputLogicHandler(mLatinIME, this); + } else { + mInputLogicHandler.reset(); + } + } + + /** + * Clean up the input logic after input is finished. + */ + public void finishInput() { + if (mWordComposer.isComposingWord()) { + mConnection.finishComposingText(); + } + resetComposingState(true /* alsoResetLastComposedWord */); + mInputLogicHandler.reset(); + } + + // Normally this class just gets out of scope after the process ends, but in unit tests, we + // create several instances of LatinIME in the same process, which results in several + // instances of InputLogic. This cleans up the associated handler so that tests don't leak + // handlers. + public void recycle() { + final InputLogicHandler inputLogicHandler = mInputLogicHandler; + mInputLogicHandler = InputLogicHandler.NULL_HANDLER; + inputLogicHandler.destroy(); + mSuggest.mDictionaryFacilitator.closeDictionaries(); + } + + /** + * React to a string input. + * + * This is triggered by keys that input many characters at once, like the ".com" key or + * some additional keys for example. + * + * @param settingsValues the current values of the settings. + * @param event the input event containing the data. + */ + public void onTextInput(final SettingsValues settingsValues, final Event event, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + final String rawText = event.mText.toString(); + mConnection.beginBatchEdit(); + if (mWordComposer.isComposingWord()) { + commitCurrentAutoCorrection(settingsValues, rawText, handler); + } else { + resetComposingState(true /* alsoResetLastComposedWord */); + } + handler.postUpdateSuggestionStrip(); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS + && ResearchLogger.RESEARCH_KEY_OUTPUT_TEXT.equals(rawText)) { + ResearchLogger.getInstance().onResearchKeySelected(mLatinIME); + return; + } + final String text = performSpecificTldProcessingOnTextInput(rawText); + if (SpaceState.PHANTOM == mSpaceState) { + promotePhantomSpace(settingsValues); + } + mConnection.commitText(text, 1); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */); + } + mConnection.endBatchEdit(); + // Space state must be updated before calling updateShiftState + mSpaceState = SpaceState.NONE; + mEnteredText = text; + } + + /** + * A suggestion was picked from the suggestion strip. + * @param settingsValues the current values of the settings. + * @param index the index of the suggestion. + * @param suggestionInfo the suggestion info. + * @param keyboardShiftState the shift state of the keyboard, as returned by + * {@link com.android.inputmethod.keyboard.KeyboardSwitcher#getKeyboardShiftMode()} + * @return the complete transaction object + */ + // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} + // interface + public InputTransaction onPickSuggestionManually(final SettingsValues settingsValues, + final int index, final SuggestedWordInfo suggestionInfo, final int keyboardShiftState, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + final SuggestedWords suggestedWords = mSuggestedWords; + final String suggestion = suggestionInfo.mWord; + // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput + if (suggestion.length() == 1 && suggestedWords.isPunctuationSuggestions()) { + // Word separators are suggested before the user inputs something. + // So, LatinImeLogger logs "" as a user's input. + LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords); + // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. + final Event event = Event.createPunctuationSuggestionPickedEvent(suggestionInfo); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, + false /* isBatchMode */, suggestedWords.mIsPrediction); + } + return onCodeInput(settingsValues, event, keyboardShiftState, handler); + } + + final Event event = Event.createSuggestionPickedEvent(suggestionInfo); + final InputTransaction inputTransaction = new InputTransaction(settingsValues, + event, SystemClock.uptimeMillis(), mSpaceState, keyboardShiftState); + mConnection.beginBatchEdit(); + if (SpaceState.PHANTOM == mSpaceState && suggestion.length() > 0 + // In the batch input mode, a manually picked suggested word should just replace + // the current batch input text and there is no need for a phantom space. + && !mWordComposer.isBatchMode()) { + final int firstChar = Character.codePointAt(suggestion, 0); + if (!settingsValues.isWordSeparator(firstChar) + || settingsValues.isUsuallyPrecededBySpace(firstChar)) { + promotePhantomSpace(settingsValues); + } + } + + // TODO: We should not need the following branch. We should be able to take the same + // code path as for other kinds, use commitChosenWord, and do everything normally. We will + // however need to reset the suggestion strip right away, because we know we can't take + // the risk of calling commitCompletion twice because we don't know how the app will react. + if (SuggestedWordInfo.KIND_APP_DEFINED == suggestionInfo.mKind) { + mSuggestedWords = SuggestedWords.EMPTY; + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + resetComposingState(true /* alsoResetLastComposedWord */); + mConnection.commitCompletion(suggestionInfo.mApplicationSpecifiedCompletionInfo); + mConnection.endBatchEdit(); + return inputTransaction; + } + + // We need to log before we commit, because the word composer will store away the user + // typed word. + final String replacedWord = mWordComposer.getTypedWord(); + LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords); + commitChosenWord(settingsValues, suggestion, + LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, + mWordComposer.isBatchMode(), suggestionInfo.mScore, + suggestionInfo.mKind, suggestionInfo.mSourceDict.mDictType); + } + mConnection.endBatchEdit(); + // Don't allow cancellation of manual pick + mLastComposedWord.deactivate(); + // Space state must be updated before calling updateShiftState + mSpaceState = SpaceState.PHANTOM; + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + + // We should show the "Touch again to save" hint if the user pressed the first entry + // AND it's in none of our current dictionaries (main, user or otherwise). + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + mSuggest.mDictionaryFacilitator; + final boolean showingAddToDictionaryHint = + (SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind + || SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind) + && !dictionaryFacilitator.isValidWord(suggestion, true /* ignoreCase */); + + if (settingsValues.mIsInternal) { + LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } + if (showingAddToDictionaryHint && dictionaryFacilitator.isUserDictionaryEnabled()) { + mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion); + } else { + // If we're not showing the "Touch again to save", then update the suggestion strip. + handler.postUpdateSuggestionStrip(); + } + return inputTransaction; + } + + /** + * Consider an update to the cursor position. Evaluate whether this update has happened as + * part of normal typing or whether it was an explicit cursor move by the user. In any case, + * do the necessary adjustments. + * @param oldSelStart old selection start + * @param oldSelEnd old selection end + * @param newSelStart new selection start + * @param newSelEnd new selection end + * @return whether the cursor has moved as a result of user interaction. + */ + public boolean onUpdateSelection(final int oldSelStart, final int oldSelEnd, + final int newSelStart, final int newSelEnd) { + if (mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart, oldSelEnd, newSelEnd)) { + return false; + } + // TODO: the following is probably better done in resetEntireInputState(). + // it should only happen when the cursor moved, and the very purpose of the + // test below is to narrow down whether this happened or not. Likewise with + // the call to updateShiftState. + // We set this to NONE because after a cursor move, we don't want the space + // state-related special processing to kick in. + mSpaceState = SpaceState.NONE; + + final boolean selectionChangedOrSafeToReset = + oldSelStart != newSelStart || oldSelEnd != newSelEnd // selection changed + || !mWordComposer.isComposingWord(); // safe to reset + final boolean hasOrHadSelection = (oldSelStart != oldSelEnd || newSelStart != newSelEnd); + final int moveAmount = newSelStart - oldSelStart; + if (selectionChangedOrSafeToReset && (hasOrHadSelection + || !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) { + // If we are composing a word and moving the cursor, we would want to set a + // suggestion span for recorrection to work correctly. Unfortunately, that + // would involve the keyboard committing some new text, which would move the + // cursor back to where it was. Latin IME could then fix the position of the cursor + // again, but the asynchronous nature of the calls results in this wreaking havoc + // with selection on double tap and the like. + // Another option would be to send suggestions each time we set the composing + // text, but that is probably too expensive to do, so we decided to leave things + // as is. + // Also, we're posting a resume suggestions message, and this will update the + // suggestions strip in a few milliseconds, so if we cleared the suggestion strip here + // we'd have the suggestion strip noticeably janky. To avoid that, we don't clear + // it here, which means we'll keep outdated suggestions for a split second but the + // visual result is better. + resetEntireInputState(newSelStart, newSelEnd, false /* clearSuggestionStrip */); + } else { + // resetEntireInputState calls resetCachesUponCursorMove, but forcing the + // composition to end. But in all cases where we don't reset the entire input + // state, we still want to tell the rich input connection about the new cursor + // position so that it can update its caches. + mConnection.resetCachesUponCursorMoveAndReturnSuccess( + newSelStart, newSelEnd, false /* shouldFinishComposition */); + } + + // We moved the cursor. If we are touching a word, we need to resume suggestion. + mLatinIME.mHandler.postResumeSuggestions(); + // Reset the last recapitalization. + mRecapitalizeStatus.deactivate(); + return true; + } + + /** + * React to a code input. It may be a code point to insert, or a symbolic value that influences + * the keyboard behavior. + * + * Typically, this is called whenever a key is pressed on the software keyboard. This is not + * the entry point for gesture input; see the onBatchInput* family of functions for this. + * + * @param settingsValues the current settings values. + * @param event the event to handle. + * @param keyboardShiftMode the current shift mode of the keyboard, as returned by + * {@link com.android.inputmethod.keyboard.KeyboardSwitcher#getKeyboardShiftMode()} + * @return the complete transaction object + */ + public InputTransaction onCodeInput(final SettingsValues settingsValues, final Event event, + final int keyboardShiftMode, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + // TODO: rework the following to not squash the keycode and the code point into the same + // var because it's confusing. Instead the switch() should handle this in a readable manner. + final int code = + Event.NOT_A_CODE_POINT == event.mCodePoint ? event.mKeyCode : event.mCodePoint; + final InputTransaction inputTransaction = new InputTransaction(settingsValues, event, + SystemClock.uptimeMillis(), mSpaceState, + getActualCapsMode(settingsValues, keyboardShiftMode)); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_onCodeInput(code, event.mX, event.mY); + } + if (event.mKeyCode != Constants.CODE_DELETE + || inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { + mDeleteCount = 0; + } + mLastKeyTime = inputTransaction.mTimestamp; + mConnection.beginBatchEdit(); + if (!mWordComposer.isComposingWord()) { + mIsAutoCorrectionIndicatorOn = false; + } + + // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. + if (event.mCodePoint != Constants.CODE_SPACE) { + cancelDoubleSpacePeriodCountdown(); + } + + boolean didAutoCorrect = false; + if (Event.NOT_A_KEY_CODE != event.mKeyCode) { + // A special key, like delete, shift, emoji, or the settings key. + switch (event.mKeyCode) { + case Constants.CODE_DELETE: + handleBackspace(inputTransaction); + LatinImeLogger.logOnDelete(event.mX, event.mY); + break; + case Constants.CODE_SHIFT: + performRecapitalization(inputTransaction.mSettingsValues); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + break; + case Constants.CODE_CAPSLOCK: + // Note: Changing keyboard to shift lock state is handled in + // {@link KeyboardSwitcher#onCodeInput(int)}. + break; + case Constants.CODE_SYMBOL_SHIFT: + // Note: Calling back to the keyboard on the symbol Shift key is handled in + // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. + break; + case Constants.CODE_SWITCH_ALPHA_SYMBOL: + // Note: Calling back to the keyboard on symbol key is handled in + // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. + break; + case Constants.CODE_SETTINGS: + onSettingsKeyPressed(); + break; + case Constants.CODE_SHORTCUT: + // We need to switch to the shortcut IME. This is handled by LatinIME since the + // input logic has no business with IME switching. + break; + case Constants.CODE_ACTION_NEXT: + performEditorAction(EditorInfo.IME_ACTION_NEXT); + break; + case Constants.CODE_ACTION_PREVIOUS: + performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); + break; + case Constants.CODE_LANGUAGE_SWITCH: + handleLanguageSwitchKey(); + break; + case Constants.CODE_EMOJI: + // Note: Switching emoji keyboard is being handled in + // {@link KeyboardState#onCodeInput(int,int)}. + break; + case Constants.CODE_ALPHA_FROM_EMOJI: + // Note: Switching back from Emoji keyboard to the main keyboard is being + // handled in {@link KeyboardState#onCodeInput(int,int)}. + break; + case Constants.CODE_SHIFT_ENTER: + // TODO: remove this object + final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, + event.mKeyCode, event.mX, event.mY, event.isKeyRepeat()); + final InputTransaction tmpTransaction = new InputTransaction( + inputTransaction.mSettingsValues, tmpEvent, + inputTransaction.mTimestamp, inputTransaction.mSpaceState, + inputTransaction.mShiftState); + didAutoCorrect = handleNonSpecialCharacter(tmpTransaction, handler); + break; + default: + throw new RuntimeException("Unknown key code : " + event.mKeyCode); + } + } else { + switch (event.mCodePoint) { + case Constants.CODE_ENTER: + final EditorInfo editorInfo = getCurrentInputEditorInfo(); + final int imeOptionsActionId = + InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo); + if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) { + // Either we have an actionLabel and we should performEditorAction with + // actionId regardless of its value. + performEditorAction(editorInfo.actionId); + } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) { + // We didn't have an actionLabel, but we had another action to execute. + // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast, + // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it + // means there should be an action and the app didn't bother to set a specific + // code for it - presumably it only handles one. It does not have to be treated + // in any specific way: anything that is not IME_ACTION_NONE should be sent to + // performEditorAction. + performEditorAction(imeOptionsActionId); + } else { + // No action label, and the action from imeOptions is NONE: this is a regular + // enter key that should input a carriage return. + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); + } + break; + default: + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); + break; + } + } + if (!didAutoCorrect && event.mKeyCode != Constants.CODE_SHIFT + && event.mKeyCode != Constants.CODE_CAPSLOCK + && event.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) + mLastComposedWord.deactivate(); + if (Constants.CODE_DELETE != event.mKeyCode) { + mEnteredText = null; + } + mConnection.endBatchEdit(); + return inputTransaction; + } + + public void onStartBatchInput(final SettingsValues settingsValues, + // TODO: remove these arguments + final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + mInputLogicHandler.onStartBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */); + handler.cancelUpdateSuggestionStrip(); + ++mAutoCommitSequenceNumber; + mConnection.beginBatchEdit(); + if (mWordComposer.isComposingWord()) { + if (settingsValues.mIsInternal) { + if (mWordComposer.isBatchMode()) { + LatinImeLoggerUtils.onAutoCorrection("", mWordComposer.getTypedWord(), " ", + mWordComposer); + } + } + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the batch input at the current cursor position. + resetEntireInputState(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); + } else if (mWordComposer.isSingleLetter()) { + // We auto-correct the previous (typed, not gestured) string iff it's one character + // long. The reason for this is, even in the middle of gesture typing, you'll still + // tap one-letter words and you want them auto-corrected (typically, "i" in English + // should become "I"). However for any longer word, we assume that the reason for + // tapping probably is that the word you intend to type is not in the dictionary, + // so we do not attempt to correct, on the assumption that if that was a dictionary + // word, the user would probably have gestured instead. + commitCurrentAutoCorrection(settingsValues, LastComposedWord.NOT_A_SEPARATOR, + handler); + } else { + commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR); + } + } + final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); + if (Character.isLetterOrDigit(codePointBeforeCursor) + || settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) { + final boolean autoShiftHasBeenOverriden = keyboardSwitcher.getKeyboardShiftMode() != + getCurrentAutoCapsState(settingsValues); + mSpaceState = SpaceState.PHANTOM; + if (!autoShiftHasBeenOverriden) { + // When we change the space state, we need to update the shift state of the + // keyboard unless it has been overridden manually. This is happening for example + // after typing some letters and a period, then gesturing; the keyboard is not in + // caps mode yet, but since a gesture is starting, it should go in caps mode, + // unless the user explictly said it should not. + keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues), + getCurrentRecapitalizeState()); + } + } + mConnection.endBatchEdit(); + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), + // Prev word is 1st word before cursor + getNthPreviousWordForSuggestion( + settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); + } + + /* The sequence number member is only used in onUpdateBatchInput. It is increased each time + * auto-commit happens. The reason we need this is, when auto-commit happens we trim the + * input pointers that are held in a singleton, and to know how much to trim we rely on the + * results of the suggestion process that is held in mSuggestedWords. + * However, the suggestion process is asynchronous, and sometimes we may enter the + * onUpdateBatchInput method twice without having recomputed suggestions yet, or having + * received new suggestions generated from not-yet-trimmed input pointers. In this case, the + * mIndexOfTouchPointOfSecondWords member will be out of date, and we must not use it lest we + * remove an unrelated number of pointers (possibly even more than are left in the input + * pointers, leading to a crash). + * To avoid that, we increase the sequence number each time we auto-commit and trim the + * input pointers, and we do not use any suggested words that have been generated with an + * earlier sequence number. + */ + private int mAutoCommitSequenceNumber = 1; + public void onUpdateBatchInput(final SettingsValues settingsValues, + final InputPointers batchPointers, + // TODO: remove these arguments + final KeyboardSwitcher keyboardSwitcher) { + if (settingsValues.mPhraseGestureEnabled) { + final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate(); + // If these suggested words have been generated with out of date input pointers, then + // we skip auto-commit (see comments above on the mSequenceNumber member). + if (null != candidate + && mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) { + if (candidate.mSourceDict.shouldAutoCommit(candidate)) { + final String[] commitParts = candidate.mWord.split(" ", 2); + batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord); + promotePhantomSpace(settingsValues); + mConnection.commitText(commitParts[0], 0); + mSpaceState = SpaceState.PHANTOM; + keyboardSwitcher.requestUpdatingShiftState( + getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState()); + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + getActualCapsMode(settingsValues, + keyboardSwitcher.getKeyboardShiftMode()), commitParts[0]); + ++mAutoCommitSequenceNumber; + } + } + } + mInputLogicHandler.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber); + } + + public void onEndBatchInput(final InputPointers batchPointers) { + mInputLogicHandler.updateTailBatchInput(batchPointers, mAutoCommitSequenceNumber); + ++mAutoCommitSequenceNumber; + } + + // TODO: remove this argument + public void onCancelBatchInput(final LatinIME.UIHandler handler) { + mInputLogicHandler.onCancelBatchInput(); + handler.showGesturePreviewAndSuggestionStrip( + SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); + } + + // TODO: on the long term, this method should become private, but it will be difficult. + // Especially, how do we deal with InputMethodService.onDisplayCompletions? + public void setSuggestedWords(final SuggestedWords suggestedWords) { + mSuggestedWords = suggestedWords; + final boolean newAutoCorrectionIndicator = suggestedWords.mWillAutoCorrect; + // Put a blue underline to a word in TextView which will be auto-corrected. + if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator + && mWordComposer.isComposingWord()) { + mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; + final CharSequence textWithUnderline = + getTextWithUnderline(mWordComposer.getTypedWord()); + // TODO: when called from an updateSuggestionStrip() call that results from a posted + // message, this is called outside any batch edit. Potentially, this may result in some + // janky flickering of the screen, although the display speed makes it unlikely in + // the practice. + mConnection.setComposingText(textWithUnderline, 1); + } + } + + /** + * Handle inputting a code point to the editor. + * + * Non-special keys are those that generate a single code point. + * This includes all letters, digits, punctuation, separators, emoji. It excludes keys that + * manage keyboard-related stuff like shift, language switch, settings, layout switch, or + * any key that results in multiple code points like the ".com" key. + * + * @param inputTransaction The transaction in progress. + * @return whether this caused an auto-correction to happen. + */ + private boolean handleNonSpecialCharacter(final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + final int codePoint = inputTransaction.mEvent.mCodePoint; + mSpaceState = SpaceState.NONE; + final boolean didAutoCorrect; + if (inputTransaction.mSettingsValues.isWordSeparator(codePoint) + || Character.getType(codePoint) == Character.OTHER_SYMBOL) { + didAutoCorrect = handleSeparator(inputTransaction, + inputTransaction.mEvent.isSuggestionStripPress(), handler); + if (inputTransaction.mSettingsValues.mIsInternal) { + LatinImeLoggerUtils.onSeparator((char)codePoint, + inputTransaction.mEvent.mX, inputTransaction.mEvent.mY); + } + } else { + didAutoCorrect = false; + if (SpaceState.PHANTOM == inputTransaction.mSpaceState) { + if (inputTransaction.mSettingsValues.mIsInternal) { + if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { + LatinImeLoggerUtils.onAutoCorrection("", mWordComposer.getTypedWord(), " ", + mWordComposer); + } + } + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the character at the current cursor position. + resetEntireInputState(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); + } else { + commitTyped(inputTransaction.mSettingsValues, LastComposedWord.NOT_A_SEPARATOR); + } + } + handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction); + } + return didAutoCorrect; + } + + /** + * Handle a non-separator. + * @param settingsValues The current settings values. + * @param inputTransaction The transaction in progress. + */ + private void handleNonSeparator(final SettingsValues settingsValues, + final InputTransaction inputTransaction) { + final int codePoint = inputTransaction.mEvent.mCodePoint; + // TODO: refactor this method to stop flipping isComposingWord around all the time, and + // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter + // which has the same name as other handle* methods but is not the same. + boolean isComposingWord = mWordComposer.isComposingWord(); + + // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. + // See onStartBatchInput() to see how to do it. + if (SpaceState.PHANTOM == inputTransaction.mSpaceState + && !settingsValues.isWordConnector(codePoint)) { + if (isComposingWord) { + // Sanity check + throw new RuntimeException("Should not be composing here"); + } + promotePhantomSpace(settingsValues); + } + + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the character at the current cursor position. + resetEntireInputState(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); + isComposingWord = false; + } + // We want to find out whether to start composing a new word with this character. If so, + // we need to reset the composing state and switch isComposingWord. The order of the + // tests is important for good performance. + // We only start composing if we're not already composing. + if (!isComposingWord + // We only start composing if this is a word code point. Essentially that means it's a + // a letter or a word connector. + && settingsValues.isWordCodePoint(codePoint) + // We never go into composing state if suggestions are not requested. + && settingsValues.isSuggestionsRequested() && + // In languages with spaces, we only start composing a word when we are not already + // touching a word. In languages without spaces, the above conditions are sufficient. + (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations) + || !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces)) { + // Reset entirely the composing state anyway, then start composing a new word unless + // the character is a single quote or a dash. The idea here is, single quote and dash + // are not separators and they should be treated as normal characters, except in the + // first position where they should not start composing a word. + isComposingWord = (Constants.CODE_SINGLE_QUOTE != codePoint + && Constants.CODE_DASH != codePoint); + // 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 */); + } + if (isComposingWord) { + mWordComposer.processEvent(inputTransaction.mEvent); + // If it's the first letter, make note of auto-caps state + if (mWordComposer.isSingleLetter()) { + // We pass 1 to getPreviousWordForSuggestion because we were not composing a word + // yet, so the word we want is the 1st word before the cursor. + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + inputTransaction.mShiftState, getNthPreviousWordForSuggestion( + settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); + } + mConnection.setComposingText(getTextWithUnderline( + mWordComposer.getTypedWord()), 1); + } else { + final boolean swapWeakSpace = maybeStripSpace(inputTransaction, + inputTransaction.mEvent.isSuggestionStripPress()); + + sendKeyCodePoint(settingsValues, codePoint); + + if (swapWeakSpace) { + swapSwapperAndSpace(inputTransaction); + mSpaceState = SpaceState.WEAK; + } + // In case the "add to dictionary" hint was still displayed. + mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); + } + inputTransaction.setRequiresUpdateSuggestions(); + if (settingsValues.mIsInternal) { + LatinImeLoggerUtils.onNonSeparator((char)codePoint, inputTransaction.mEvent.mX, + inputTransaction.mEvent.mY); + } + } + + /** + * Handle input of a separator code point. + * @param inputTransaction The transaction in progress. + * @param isFromSuggestionStrip whether this code point comes from the suggestion strip. + * @return whether this caused an auto-correction to happen. + */ + private boolean handleSeparator(final InputTransaction inputTransaction, + final boolean isFromSuggestionStrip, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + final int codePoint = inputTransaction.mEvent.mCodePoint; + boolean didAutoCorrect = false; + // We avoid sending spaces in languages without spaces if we were composing. + final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint + && !inputTransaction.mSettingsValues.mSpacingAndPunctuations + .mCurrentLanguageHasSpaces + && mWordComposer.isComposingWord(); + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the separator at the current cursor position. + resetEntireInputState(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); + } + // isComposingWord() may have changed since we stored wasComposing + if (mWordComposer.isComposingWord()) { + if (inputTransaction.mSettingsValues.mCorrectionEnabled) { + final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR + : StringUtils.newSingleCodePointString(codePoint); + commitCurrentAutoCorrection(inputTransaction.mSettingsValues, separator, handler); + didAutoCorrect = true; + } else { + commitTyped(inputTransaction.mSettingsValues, + StringUtils.newSingleCodePointString(codePoint)); + } + } + + final boolean swapWeakSpace = maybeStripSpace(inputTransaction, isFromSuggestionStrip); + + final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint + && mConnection.isInsideDoubleQuoteOrAfterDigit(); + + final boolean needsPrecedingSpace; + if (SpaceState.PHANTOM != inputTransaction.mSpaceState) { + needsPrecedingSpace = false; + } else if (Constants.CODE_DOUBLE_QUOTE == codePoint) { + // Double quotes behave like they are usually preceded by space iff we are + // not inside a double quote or after a digit. + needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit; + } else { + needsPrecedingSpace = inputTransaction.mSettingsValues.isUsuallyPrecededBySpace( + codePoint); + } + + if (needsPrecedingSpace) { + promotePhantomSpace(inputTransaction.mSettingsValues); + } + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord()); + } + + if (!shouldAvoidSendingCode) { + sendKeyCodePoint(inputTransaction.mSettingsValues, codePoint); + } + + if (Constants.CODE_SPACE == codePoint) { + if (maybeDoubleSpacePeriod(inputTransaction)) { + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + mSpaceState = SpaceState.DOUBLE; + } else if (!mSuggestedWords.isPunctuationSuggestions()) { + mSpaceState = SpaceState.WEAK; + } + + startDoubleSpacePeriodCountdown(inputTransaction); + inputTransaction.setRequiresUpdateSuggestions(); + } else { + if (swapWeakSpace) { + swapSwapperAndSpace(inputTransaction); + mSpaceState = SpaceState.SWAP_PUNCTUATION; + } else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState + && inputTransaction.mSettingsValues.isUsuallyFollowedBySpace(codePoint)) + || (Constants.CODE_DOUBLE_QUOTE == codePoint + && isInsideDoubleQuoteOrAfterDigit)) { + // 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. A double quote behaves like it's usually followed by space if + // we're inside a double quote. + // The case is a little different if the separator is a space stripper. Such a + // separator does not normally need a space on the right (that's the difference + // between swappers and strippers), so we should not stay in phantom space state if + // the separator is a stripper. Hence the additional test above. + mSpaceState = SpaceState.PHANTOM; + } + + // Set punctuation right away. onUpdateSelection will fire but tests whether it is + // already displayed or not, so it's okay. + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + } + + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + return didAutoCorrect; + } + + /** + * Handle a press on the backspace key. + * @param inputTransaction The transaction in progress. + */ + private void handleBackspace(final InputTransaction inputTransaction) { + mSpaceState = SpaceState.NONE; + mDeleteCount++; + + // In many cases after backspace, we need to update the shift state. Normally we need + // to do this right away to avoid the shift state being out of date in case the user types + // backspace then some other character very fast. However, in the case of backspace key + // repeat, this can lead to flashiness when the cursor flies over positions where the + // shift state should be updated, so if this is a key repeat, we update after a small delay. + // Then again, even in the case of a key repeat, if the cursor is at start of text, it + // can't go any further back, so we can update right away even if it's a key repeat. + final int shiftUpdateKind = + inputTransaction.mEvent.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0 + ? InputTransaction.SHIFT_UPDATE_LATER : InputTransaction.SHIFT_UPDATE_NOW; + inputTransaction.requireShiftUpdate(shiftUpdateKind); + + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can remove the character at the current cursor position. + resetEntireInputState(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); + // When we exit this if-clause, mWordComposer.isComposingWord() will return false. + } + if (mWordComposer.isComposingWord()) { + if (mWordComposer.isBatchMode()) { + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + final String word = mWordComposer.getTypedWord(); + ResearchLogger.latinIME_handleBackspace_batch(word, 1); + } + final String rejectedSuggestion = mWordComposer.getTypedWord(); + mWordComposer.reset(); + mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion); + } else { + mWordComposer.processEvent(inputTransaction.mEvent); + } + mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); + inputTransaction.setRequiresUpdateSuggestions(); + } else { + if (mLastComposedWord.canRevertCommit()) { + if (inputTransaction.mSettingsValues.mIsInternal) { + LatinImeLoggerUtils.onAutoCorrectionCancellation(); + } + revertCommit(inputTransaction); + return; + } + if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(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. + mConnection.deleteSurroundingText(mEnteredText.length(), 0); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleBackspace_cancelTextInput(mEnteredText); + } + mEnteredText = null; + // 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 (SpaceState.DOUBLE == inputTransaction.mSpaceState) { + cancelDoubleSpacePeriodCountdown(); + if (mConnection.revertDoubleSpacePeriod()) { + // No need to reset mSpaceState, it has already be done (that's why we + // receive it as a parameter) + return; + } + } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { + if (mConnection.revertSwapPunctuation()) { + // Likewise + return; + } + } + + // No cancelling of commit/double space/swap: we have a regular backspace. + // We should backspace one char and restart suggestion if at the end of a word. + if (mConnection.hasSelection()) { + // If there is a selection, remove it. + final int numCharsDeleted = mConnection.getExpectedSelectionEnd() + - mConnection.getExpectedSelectionStart(); + mConnection.setSelection(mConnection.getExpectedSelectionEnd(), + mConnection.getExpectedSelectionEnd()); + mConnection.deleteSurroundingText(numCharsDeleted, 0); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleBackspace(numCharsDeleted, + false /* shouldUncommitLogUnit */); + } + } else { + // There is no selection, just delete one character. + if (Constants.NOT_A_CURSOR_POSITION == mConnection.getExpectedSelectionEnd()) { + // This should never happen. + Log.e(TAG, "Backspace when we don't know the selection position"); + } + if (inputTransaction.mSettingsValues.isBeforeJellyBean() || + inputTransaction.mSettingsValues.mInputAttributes.isTypeNull()) { + // There are two possible reasons to send a key event: either the field has + // type TYPE_NULL, in which case the keyboard should send events, or we are + // running in backward compatibility mode. Before Jelly bean, the keyboard + // would simulate a hardware keyboard event on pressing enter or delete. This + // is bad for many reasons (there are race conditions with commits) but some + // applications are relying on this behavior so we continue to support it for + // older apps, so we retain this behavior if the app has target SDK < JellyBean. + sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); + if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) { + sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL); + } + } else { + final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); + if (codePointBeforeCursor == Constants.NOT_A_CODE) { + // HACK for backward compatibility with broken apps that haven't realized + // yet that hardware keyboards are not the only way of inputting text. + // Nothing to delete before the cursor. We should not do anything, but many + // broken apps expect something to happen in this case so that they can + // catch it and have their broken interface react. If you need the keyboard + // to do this, you're doing it wrong -- please fix your app. + mConnection.deleteSurroundingText(1, 0); + return; + } + final int lengthToDelete = + Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1; + mConnection.deleteSurroundingText(lengthToDelete, 0); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleBackspace(lengthToDelete, + true /* shouldUncommitLogUnit */); + } + if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) { + final int codePointBeforeCursorToDeleteAgain = + mConnection.getCodePointBeforeCursor(); + if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) { + final int lengthToDeleteAgain = Character.isSupplementaryCodePoint( + codePointBeforeCursorToDeleteAgain) ? 2 : 1; + mConnection.deleteSurroundingText(lengthToDeleteAgain, 0); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain, + true /* shouldUncommitLogUnit */); + } + } + } + } + } + if (inputTransaction.mSettingsValues.isSuggestionStripVisible() + && inputTransaction.mSettingsValues.mSpacingAndPunctuations + .mCurrentLanguageHasSpaces + && !mConnection.isCursorFollowedByWordCharacter( + inputTransaction.mSettingsValues.mSpacingAndPunctuations)) { + restartSuggestionsOnWordTouchedByCursor(inputTransaction.mSettingsValues, + true /* includeResumedWordInSuggestions */); + } + } + } + + /** + * Handle a press on the language switch key (the "globe key") + */ + private void handleLanguageSwitchKey() { + mLatinIME.switchToNextSubtype(); + } + + /** + * Swap a space with a space-swapping punctuation sign. + * + * This method will check that there are two characters before the cursor and that the first + * one is a space before it does the actual swapping. + * @param inputTransaction The transaction in progress. + */ + private void swapSwapperAndSpace(final InputTransaction inputTransaction) { + final CharSequence lastTwo = mConnection.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) == Constants.CODE_SPACE) { + mConnection.deleteSurroundingText(2, 0); + final String text = lastTwo.charAt(1) + " "; + mConnection.commitText(text, 1); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); + } + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + } + } + + /* + * Strip a trailing space if necessary and returns whether it's a swap weak space situation. + * @param inputTransaction The transaction in progress. + * @param isFromSuggestionStrip Whether this code point is coming from the suggestion strip. + * @return whether we should swap the space instead of removing it. + */ + private boolean maybeStripSpace(final InputTransaction inputTransaction, + final boolean isFromSuggestionStrip) { + final int codePoint = inputTransaction.mEvent.mCodePoint; + if (Constants.CODE_ENTER == codePoint && + SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { + mConnection.removeTrailingSpace(); + return false; + } + if ((SpaceState.WEAK == inputTransaction.mSpaceState + || SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) + && isFromSuggestionStrip) { + if (inputTransaction.mSettingsValues.isUsuallyPrecededBySpace(codePoint)) { + return false; + } + if (inputTransaction.mSettingsValues.isUsuallyFollowedBySpace(codePoint)) { + return true; + } + mConnection.removeTrailingSpace(); + } + return false; + } + + public void startDoubleSpacePeriodCountdown(final InputTransaction inputTransaction) { + mDoubleSpacePeriodCountdownStart = inputTransaction.mTimestamp; + } + + public void cancelDoubleSpacePeriodCountdown() { + mDoubleSpacePeriodCountdownStart = 0; + } + + public boolean isDoubleSpacePeriodCountdownActive(final InputTransaction inputTransaction) { + return inputTransaction.mTimestamp - mDoubleSpacePeriodCountdownStart + < inputTransaction.mSettingsValues.mDoubleSpacePeriodTimeout; + } + + /** + * Apply the double-space-to-period transformation if applicable. + * + * The double-space-to-period transformation means that we replace two spaces with a + * period-space sequence of characters. This typically happens when the user presses space + * twice in a row quickly. + * This method will check that the double-space-to-period is active in settings, that the + * two spaces have been input close enough together, and that the previous character allows + * for the transformation to take place. If all of these conditions are fulfilled, this + * method applies the transformation and returns true. Otherwise, it does nothing and + * returns false. + * + * @param inputTransaction The transaction in progress. + * @return true if we applied the double-space-to-period transformation, false otherwise. + */ + private boolean maybeDoubleSpacePeriod(final InputTransaction inputTransaction) { + if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod) return false; + if (!isDoubleSpacePeriodCountdownActive(inputTransaction)) return false; + // We only do this when we see two spaces and an accepted code point before the cursor. + // The code point may be a surrogate pair but the two spaces may not, so we need 4 chars. + final CharSequence lastThree = mConnection.getTextBeforeCursor(4, 0); + if (null == lastThree) return false; + final int length = lastThree.length(); + if (length < 3) return false; + if (lastThree.charAt(length - 1) != Constants.CODE_SPACE) return false; + if (lastThree.charAt(length - 2) != Constants.CODE_SPACE) return false; + // We know there are spaces in pos -1 and -2, and we have at least three chars. + // If we have only three chars, isSurrogatePairs can't return true as charAt(1) is a space, + // so this is fine. + final int firstCodePoint = + Character.isSurrogatePair(lastThree.charAt(0), lastThree.charAt(1)) ? + Character.codePointAt(lastThree, 0) : lastThree.charAt(length - 3); + if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) { + cancelDoubleSpacePeriodCountdown(); + mConnection.deleteSurroundingText(2, 0); + final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations + .mSentenceSeparatorAndSpace; + mConnection.commitText(textToInsert, 1); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, + false /* isBatchMode */); + } + mWordComposer.discardPreviousWordForSuggestion(); + return true; + } + return false; + } + + /** + * Returns whether this code point can be followed by the double-space-to-period transformation. + * + * See #maybeDoubleSpaceToPeriod for details. + * Generally, most word characters can be followed by the double-space-to-period transformation, + * while most punctuation can't. Some punctuation however does allow for this to take place + * after them, like the closing parenthesis for example. + * + * @param codePoint the code point after which we may want to apply the transformation + * @return whether it's fine to apply the transformation after this code point. + */ + private static boolean canBeFollowedByDoubleSpacePeriod(final int codePoint) { + // TODO: This should probably be a blacklist rather than a whitelist. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Constants.CODE_SINGLE_QUOTE + || codePoint == Constants.CODE_DOUBLE_QUOTE + || codePoint == Constants.CODE_CLOSING_PARENTHESIS + || codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET + || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET + || codePoint == Constants.CODE_PLUS + || codePoint == Constants.CODE_PERCENT + || Character.getType(codePoint) == Character.OTHER_SYMBOL; + } + + /** + * Performs a recapitalization event. + * @param settingsValues The current settings values. + */ + private void performRecapitalization(final SettingsValues settingsValues) { + if (!mConnection.hasSelection()) { + return; // No selection + } + // If we have a recapitalize in progress, use it; otherwise, create a new one. + if (!mRecapitalizeStatus.isActive() + || !mRecapitalizeStatus.isSetAt(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd())) { + final CharSequence selectedText = + mConnection.getSelectedText(0 /* flags, 0 for no styles */); + if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection + mRecapitalizeStatus.initialize(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd(), selectedText.toString(), + settingsValues.mLocale, + settingsValues.mSpacingAndPunctuations.mSortedWordSeparators); + // We trim leading and trailing whitespace. + mRecapitalizeStatus.trim(); + } + mConnection.finishComposingText(); + mRecapitalizeStatus.rotate(); + final int numCharsDeleted = mConnection.getExpectedSelectionEnd() + - mConnection.getExpectedSelectionStart(); + mConnection.setSelection(mConnection.getExpectedSelectionEnd(), + mConnection.getExpectedSelectionEnd()); + mConnection.deleteSurroundingText(numCharsDeleted, 0); + mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); + mConnection.setSelection(mRecapitalizeStatus.getNewCursorStart(), + mRecapitalizeStatus.getNewCursorEnd()); + } + + private void performAdditionToUserHistoryDictionary(final SettingsValues settingsValues, + final String suggestion, final String prevWord) { + // If correction is not enabled, we don't add words to the user history dictionary. + // That's to avoid unintended additions in some sensitive fields, or fields that + // expect to receive non-words. + if (!settingsValues.mCorrectionEnabled) return; + + if (TextUtils.isEmpty(suggestion)) return; + final boolean wasAutoCapitalized = + mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps(); + final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds( + System.currentTimeMillis()); + mSuggest.mDictionaryFacilitator.addToUserHistory(suggestion, wasAutoCapitalized, prevWord, + timeStampInSeconds); + } + + public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) { + // Check if we have a suggestion engine attached. + if (!settingsValues.isSuggestionsRequested()) { + if (mWordComposer.isComposingWord()) { + Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " + + "requested!"); + } + return; + } + + if (!mWordComposer.isComposingWord() && !settingsValues.mBigramPredictionEnabled) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + return; + } + + final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>(); + mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING, + SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords(final SuggestedWords suggestedWords) { + final String typedWord = mWordComposer.getTypedWord(); + // Show new suggestions if we have at least one. Otherwise keep the old + // suggestions with the new typed word. Exception: if the length of the + // typed word is <= 1 (after a deletion typically) we clear old suggestions. + if (suggestedWords.size() > 1 || typedWord.length() <= 1) { + holder.set(suggestedWords); + } else { + holder.set(retrieveOlderSuggestions(typedWord, mSuggestedWords)); + } + } + } + ); + + // This line may cause the current thread to wait. + final SuggestedWords suggestedWords = holder.get(null, + Constants.GET_SUGGESTED_WORDS_TIMEOUT); + if (suggestedWords != null) { + mSuggestionStripViewAccessor.showSuggestionStrip(suggestedWords); + } + } + + /** + * Check if the cursor is touching a word. If so, restart suggestions on this word, else + * do nothing. + * + * @param settingsValues the current values of the settings. + * @param includeResumedWordInSuggestions whether to include the word on which we resume + * suggestions in the suggestion list. + */ + // TODO: make this private. + public void restartSuggestionsOnWordTouchedByCursor(final SettingsValues settingsValues, + final boolean includeResumedWordInSuggestions) { + // HACK: We may want to special-case some apps that exhibit bad behavior in case of + // recorrection. This is a temporary, stopgap measure that will be removed later. + // TODO: remove this. + if (settingsValues.isBrokenByRecorrection() + // Recorrection is not supported in languages without spaces because we don't know + // how to segment them yet. + || !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + // If no suggestions are requested, don't try restarting suggestions. + || !settingsValues.isSuggestionsRequested() + // If we are currently in a batch input, we must not resume suggestions, or the result + // of the batch input will replace the new composition. This may happen in the corner case + // that the app moves the cursor on its own accord during a batch input. + || mInputLogicHandler.isInBatchInput() + // If the cursor is not touching a word, or if there is a selection, return right away. + || mConnection.hasSelection() + // If we don't know the cursor location, return. + || mConnection.getExpectedSelectionStart() < 0) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + return; + } + final int expectedCursorPosition = mConnection.getExpectedSelectionStart(); + if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { + // Show predictions. + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + WordComposer.CAPS_MODE_OFF, + getNthPreviousWordForSuggestion(settingsValues.mSpacingAndPunctuations, 1)); + mLatinIME.mHandler.postUpdateSuggestionStrip(); + return; + } + final TextRange range = mConnection.getWordRangeAtCursor( + settingsValues.mSpacingAndPunctuations.mSortedWordSeparators, + 0 /* additionalPrecedingWordsCount */); + if (null == range) return; // Happens if we don't have an input connection at all + if (range.length() <= 0) return; // Race condition. No text to resume on, so bail out. + // If for some strange reason (editor bug or so) we measure the text before the cursor as + // longer than what the entire text is supposed to be, the safe thing to do is bail out. + if (range.mHasUrlSpans) return; // If there are links, we don't resume suggestions. Making + // edits to a linkified text through batch commands would ruin the URL spans, and unless + // we take very complicated steps to preserve the whole link, we can't do things right so + // we just do not resume because it's safer. + final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor(); + if (numberOfCharsInWordBeforeCursor > expectedCursorPosition) return; + final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); + final String typedWord = range.mWord.toString(); + if (includeResumedWordInSuggestions) { + suggestions.add(new SuggestedWordInfo(typedWord, + SuggestedWords.MAX_SUGGESTIONS + 1, + SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED, + SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, + SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); + } + if (!isResumableWord(settingsValues, typedWord)) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + return; + } + int i = 0; + for (final SuggestionSpan span : range.getSuggestionSpansAtWord()) { + for (final String s : span.getSuggestions()) { + ++i; + if (!TextUtils.equals(s, typedWord)) { + suggestions.add(new SuggestedWordInfo(s, + SuggestedWords.MAX_SUGGESTIONS - i, + SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED, + SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, + SuggestedWordInfo.NOT_A_CONFIDENCE + /* autoCommitFirstWordConfidence */)); + } + } + } + final int[] codePoints = StringUtils.toCodePointArray(typedWord); + mWordComposer.setComposingWord(codePoints, + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), + getNthPreviousWordForSuggestion(settingsValues.mSpacingAndPunctuations, + // We want the previous word for suggestion. If we have chars in the word + // before the cursor, then we want the word before that, hence 2; otherwise, + // we want the word immediately before the cursor, hence 1. + 0 == numberOfCharsInWordBeforeCursor ? 1 : 2)); + mWordComposer.setCursorPositionWithinWord( + typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); + mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, + expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor()); + if (suggestions.isEmpty()) { + // We come here if there weren't any suggestion spans on this word. We will try to + // compute suggestions for it instead. + mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING, + SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords( + final SuggestedWords suggestedWordsIncludingTypedWord) { + final SuggestedWords suggestedWords; + if (suggestedWordsIncludingTypedWord.size() > 1 + && !includeResumedWordInSuggestions) { + // We were able to compute new suggestions for this word. + // Remove the typed word, since we don't want to display it in this + // case. The #getSuggestedWordsExcludingTypedWord() method sets + // willAutoCorrect to false. + suggestedWords = suggestedWordsIncludingTypedWord + .getSuggestedWordsExcludingTypedWord(); + } else { + // No saved suggestions, and we were unable to compute any good one + // either. Rather than displaying an empty suggestion strip, we'll + // display the original word alone in the middle. + // Since there is only one word, willAutoCorrect is false. + suggestedWords = suggestedWordsIncludingTypedWord; + } + mIsAutoCorrectionIndicatorOn = false; + mLatinIME.mHandler.showSuggestionStrip(suggestedWords); + }}); + } else { + // We found suggestion spans in the word. We'll create the SuggestedWords out of + // them, and make willAutoCorrect false. We make typedWordValid false, because the + // color of the word in the suggestion strip changes according to this parameter, + // and false gives the correct color. + final SuggestedWords suggestedWords = new SuggestedWords(suggestions, + null /* rawSuggestions */, typedWord, + false /* typedWordValid */, false /* willAutoCorrect */, + false /* isObsoleteSuggestions */, false /* isPrediction */, + SuggestedWords.NOT_A_SEQUENCE_NUMBER); + mIsAutoCorrectionIndicatorOn = false; + mLatinIME.mHandler.showSuggestionStrip(suggestedWords); + } + } + + /** + * Reverts a previous commit with auto-correction. + * + * This is triggered upon pressing backspace just after a commit with auto-correction. + * + * @param inputTransaction The transaction in progress. + */ + private void revertCommit(final InputTransaction inputTransaction) { + final String previousWord = mLastComposedWord.mPrevWord; + final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord; + final CharSequence committedWord = mLastComposedWord.mCommittedWord; + final String committedWordString = committedWord.toString(); + final int cancelLength = committedWord.length(); + // We want java chars, not codepoints for the following. + final int separatorLength = mLastComposedWord.mSeparatorString.length(); + // TODO: should we check our saved separator against the actual contents of the text view? + final int deleteLength = cancelLength + separatorLength; + if (LatinImeLogger.sDBG) { + if (mWordComposer.isComposingWord()) { + throw new RuntimeException("revertCommit, but we are composing a word"); + } + final CharSequence wordBeforeCursor = + mConnection.getTextBeforeCursor(deleteLength, 0).subSequence(0, cancelLength); + if (!TextUtils.equals(committedWord, wordBeforeCursor)) { + throw new RuntimeException("revertCommit check failed: we thought we were " + + "reverting \"" + committedWord + + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); + } + } + mConnection.deleteSurroundingText(deleteLength, 0); + if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { + mSuggest.mDictionaryFacilitator.cancelAddingUserHistory( + previousWord, committedWordString); + } + final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString; + final SpannableString textToCommit = new SpannableString(stringToCommit); + if (committedWord instanceof SpannableString) { + final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord; + final Object[] spans = committedWordWithSuggestionSpans.getSpans(0, + committedWord.length(), Object.class); + final int lastCharIndex = textToCommit.length() - 1; + // We will collect all suggestions in the following array. + final ArrayList<String> suggestions = CollectionUtils.newArrayList(); + // First, add the committed word to the list of suggestions. + suggestions.add(committedWordString); + for (final Object span : spans) { + // If this is a suggestion span, we check that the locale is the right one, and + // that the word is not the committed word. That should mostly be the case. + // Given this, we add it to the list of suggestions, otherwise we discard it. + if (span instanceof SuggestionSpan) { + final SuggestionSpan suggestionSpan = (SuggestionSpan)span; + if (!suggestionSpan.getLocale().equals( + inputTransaction.mSettingsValues.mLocale.toString())) { + continue; + } + for (final String suggestion : suggestionSpan.getSuggestions()) { + if (!suggestion.equals(committedWordString)) { + suggestions.add(suggestion); + } + } + } else { + // If this is not a suggestion span, we just add it as is. + textToCommit.setSpan(span, 0 /* start */, lastCharIndex /* end */, + committedWordWithSuggestionSpans.getSpanFlags(span)); + } + } + // Add the suggestion list to the list of suggestions. + textToCommit.setSpan(new SuggestionSpan(inputTransaction.mSettingsValues.mLocale, + suggestions.toArray(new String[suggestions.size()]), 0 /* flags */), + 0 /* start */, lastCharIndex /* end */, 0 /* flags */); + } + if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) { + // For languages with spaces, we revert to the typed string, but the cursor is still + // after the separator so we don't resume suggestions. If the user wants to correct + // the word, they have to press backspace again. + mConnection.commitText(textToCommit, 1); + } else { + // For languages without spaces, we revert the typed string but the cursor is flush + // with the typed word, so we need to resume suggestions right away. + final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); + mWordComposer.setComposingWord(codePoints, + mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), previousWord); + mConnection.setComposingText(textToCommit, 1); + } + if (inputTransaction.mSettingsValues.mIsInternal) { + LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_revertCommit(committedWord.toString(), + originallyTypedWord.toString(), + mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString); + } + // Don't restart suggestion yet. We'll restart if the user deletes the + // separator. + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + // We have a separator between the word and the cursor: we should show predictions. + inputTransaction.setRequiresUpdateSuggestions(); + } + + /** + * Factor in auto-caps and manual caps and compute the current caps mode. + * @param settingsValues the current settings values. + * @param keyboardShiftMode the current shift mode of the keyboard. See + * KeyboardSwitcher#getKeyboardShiftMode() for possible values. + * @return the actual caps mode the keyboard is in right now. + */ + private int getActualCapsMode(final SettingsValues settingsValues, + final int keyboardShiftMode) { + if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) { + return keyboardShiftMode; + } + final int auto = getCurrentAutoCapsState(settingsValues); + if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { + return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; + } + if (0 != auto) { + return WordComposer.CAPS_MODE_AUTO_SHIFTED; + } + return WordComposer.CAPS_MODE_OFF; + } + + /** + * Gets the current auto-caps state, factoring in the space state. + * + * This method tries its best to do this in the most efficient possible manner. It avoids + * getting text from the editor if possible at all. + * This is called from the KeyboardSwitcher (through a trampoline in LatinIME) because it + * needs to know auto caps state to display the right layout. + * + * @param settingsValues the relevant settings values + * @return a caps mode from TextUtils.CAP_MODE_* or Constants.TextUtils.CAP_MODE_OFF. + */ + public int getCurrentAutoCapsState(final SettingsValues settingsValues) { + if (!settingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; + + final EditorInfo ei = getCurrentInputEditorInfo(); + if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; + final int inputType = ei.inputType; + // Warning: this depends on mSpaceState, which may not be the most current value. If + // mSpaceState gets updated later, whoever called this may need to be told about it. + return mConnection.getCursorCapsMode(inputType, settingsValues.mSpacingAndPunctuations, + SpaceState.PHANTOM == mSpaceState); + } + + public int getCurrentRecapitalizeState() { + if (!mRecapitalizeStatus.isActive() + || !mRecapitalizeStatus.isSetAt(mConnection.getExpectedSelectionStart(), + mConnection.getExpectedSelectionEnd())) { + // Not recapitalizing at the moment + return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; + } + return mRecapitalizeStatus.getCurrentMode(); + } + + /** + * @return the editor info for the current editor + */ + private EditorInfo getCurrentInputEditorInfo() { + return mLatinIME.getCurrentInputEditorInfo(); + } + + /** + * Get the nth previous word before the cursor as context for the suggestion process. + * @param spacingAndPunctuations the current spacing and punctuations settings. + * @param nthPreviousWord reverse index of the word to get (1-indexed) + * @return the nth previous word before the cursor. + */ + // TODO: Make this private + public CharSequence getNthPreviousWordForSuggestion( + final SpacingAndPunctuations spacingAndPunctuations, final int nthPreviousWord) { + if (spacingAndPunctuations.mCurrentLanguageHasSpaces) { + // If we are typing in a language with spaces we can just look up the previous + // word from textview. + return mConnection.getNthPreviousWord(spacingAndPunctuations, nthPreviousWord); + } else { + return LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null + : mLastComposedWord.mCommittedWord; + } + } + + /** + * Tests the passed word for resumability. + * + * We can resume suggestions on words whose first code point is a word code point (with some + * nuances: check the code for details). + * + * @param settings the current values of the settings. + * @param word the word to evaluate. + * @return whether it's fine to resume suggestions on this word. + */ + private static boolean isResumableWord(final SettingsValues settings, final String word) { + final int firstCodePoint = word.codePointAt(0); + return settings.isWordCodePoint(firstCodePoint) + && Constants.CODE_SINGLE_QUOTE != firstCodePoint + && Constants.CODE_DASH != firstCodePoint; + } + + /** + * @param actionId the action to perform + */ + private void performEditorAction(final int actionId) { + mConnection.performEditorAction(actionId); + } + + /** + * Perform the processing specific to inputting TLDs. + * + * Some keys input a TLD (specifically, the ".com" key) and this warrants some specific + * processing. First, if this is a TLD, we ignore PHANTOM spaces -- this is done by type + * of character in onCodeInput, but since this gets inputted as a whole string we need to + * do it here specifically. Then, if the last character before the cursor is a period, then + * we cut the dot at the start of ".com". This is because humans tend to type "www.google." + * and then press the ".com" key and instinctively don't expect to get "www.google..com". + * + * @param text the raw text supplied to onTextInput + * @return the text to actually send to the editor + */ + private String performSpecificTldProcessingOnTextInput(final String text) { + if (text.length() <= 1 || text.charAt(0) != Constants.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 = SpaceState.NONE; + final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); + // If no code point, #getCodePointBeforeCursor returns NOT_A_CODE_POINT. + if (Constants.CODE_PERIOD == codePointBeforeCursor) { + return text.substring(1); + } else { + return text; + } + } + + /** + * Handle a press on the settings key. + */ + private void onSettingsKeyPressed() { + mLatinIME.displaySettingsDialog(); + } + + /** + * Resets the whole input state to the starting state. + * + * This will clear the composing word, reset the last composed word, clear the suggestion + * strip and tell the input connection about it so that it can refresh its caches. + * + * @param newSelStart the new selection start, in java characters. + * @param newSelEnd the new selection end, in java characters. + * @param clearSuggestionStrip whether this method should clear the suggestion strip. + */ + // TODO: how is this different from startInput ?! + private void resetEntireInputState(final int newSelStart, final int newSelEnd, + final boolean clearSuggestionStrip) { + final boolean shouldFinishComposition = mWordComposer.isComposingWord(); + resetComposingState(true /* alsoResetLastComposedWord */); + if (clearSuggestionStrip) { + mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); + } + mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, newSelEnd, + shouldFinishComposition); + } + + /** + * Resets only the composing state. + * + * Compare #resetEntireInputState, which also clears the suggestion strip and resets the + * input connection caches. This only deals with the composing state. + * + * @param alsoResetLastComposedWord whether to also reset the last composed word. + */ + private void resetComposingState(final boolean alsoResetLastComposedWord) { + mWordComposer.reset(); + if (alsoResetLastComposedWord) { + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + } + } + + /** + * Make a {@link com.android.inputmethod.latin.SuggestedWords} object containing a typed word + * and obsolete suggestions. + * See {@link com.android.inputmethod.latin.SuggestedWords#getTypedWordAndPreviousSuggestions( + * String, com.android.inputmethod.latin.SuggestedWords)}. + * @param typedWord The typed word as a string. + * @param previousSuggestedWords The previously suggested words. + * @return Obsolete suggestions with the newly typed word. + */ + private SuggestedWords retrieveOlderSuggestions(final String typedWord, + final SuggestedWords previousSuggestedWords) { + final SuggestedWords oldSuggestedWords = + previousSuggestedWords.isPunctuationSuggestions() ? SuggestedWords.EMPTY + : previousSuggestedWords; + final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = + SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); + return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, + false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, + true /* isObsoleteSuggestions */, false /* isPrediction */); + } + + /** + * Gets a chunk of text with or the auto-correction indicator underline span as appropriate. + * + * This method looks at the old state of the auto-correction indicator to put or not put + * the underline span as appropriate. It is important to note that this does not correspond + * exactly to whether this word will be auto-corrected to or not: what's important here is + * to keep the same indication as before. + * When we add a new code point to a composing word, we don't know yet if we are going to + * auto-correct it until the suggestions are computed. But in the mean time, we still need + * to display the character and to extend the previous underline. To avoid any flickering, + * the underline should keep the same color it used to have, even if that's not ultimately + * the correct color for this new word. When the suggestions are finished evaluating, we + * will call this method again to fix the color of the underline. + * + * @param text the text on which to maybe apply the span. + * @return the same text, with the auto-correction underline span if that's appropriate. + */ + // TODO: Shouldn't this go in some *Utils class instead? + private CharSequence getTextWithUnderline(final String text) { + return mIsAutoCorrectionIndicatorOn + ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(mLatinIME, text) + : text; + } + + /** + * Sends a DOWN key event followed by an UP key event to the editor. + * + * If possible at all, avoid using this method. It causes all sorts of race conditions with + * the text view because it goes through a different, asynchronous binder. Also, batch edits + * are ignored for key events. Use the normal software input methods instead. + * + * @param keyCode the key code to send inside the key event. + */ + private void sendDownUpKeyEvent(final int keyCode) { + final long eventTime = SystemClock.uptimeMillis(); + mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, + KeyEvent.ACTION_DOWN, keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); + mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, + KeyEvent.ACTION_UP, keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, + KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); + } + + /** + * Sends a code point to the editor, using the most appropriate method. + * + * Normally we send code points with commitText, but there are some cases (where backward + * compatibility is a concern for example) where we want to use deprecated methods. + * + * @param settingsValues the current values of the settings. + * @param codePoint the code point to send. + */ + // TODO: replace these two parameters with an InputTransaction + private void sendKeyCodePoint(final SettingsValues settingsValues, final int codePoint) { + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_sendKeyCodePoint(codePoint); + } + // TODO: Remove this special handling of digit letters. + // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. + if (codePoint >= '0' && codePoint <= '9') { + sendDownUpKeyEvent(codePoint - '0' + KeyEvent.KEYCODE_0); + return; + } + + // TODO: we should do this also when the editor has TYPE_NULL + if (Constants.CODE_ENTER == codePoint && settingsValues.isBeforeJellyBean()) { + // Backward compatibility mode. Before Jelly bean, the keyboard would simulate + // a hardware keyboard event on pressing enter or delete. This is bad for many + // reasons (there are race conditions with commits) but some applications are + // relying on this behavior so we continue to support it for older apps. + sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER); + } else { + mConnection.commitText(StringUtils.newSingleCodePointString(codePoint), 1); + } + } + + /** + * Promote a phantom space to an actual space. + * + * This essentially inserts a space, and that's it. It just checks the options and the text + * before the cursor are appropriate before doing it. + * + * @param settingsValues the current values of the settings. + */ + private void promotePhantomSpace(final SettingsValues settingsValues) { + if (settingsValues.shouldInsertSpacesAutomatically() + && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + && !mConnection.textBeforeCursorLooksLikeURL()) { + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_promotePhantomSpace(); + } + sendKeyCodePoint(settingsValues, Constants.CODE_SPACE); + } + } + + /** + * Do the final processing after a batch input has ended. This commits the word to the editor. + * @param settingsValues the current values of the settings. + * @param suggestedWords suggestedWords to use. + */ + public void onUpdateTailBatchInputCompleted(final SettingsValues settingsValues, + final SuggestedWords suggestedWords, + // TODO: remove this argument + final KeyboardSwitcher keyboardSwitcher) { + final String batchInputText = suggestedWords.isEmpty() ? null : suggestedWords.getWord(0); + if (TextUtils.isEmpty(batchInputText)) { + return; + } + mConnection.beginBatchEdit(); + if (SpaceState.PHANTOM == mSpaceState) { + promotePhantomSpace(settingsValues); + } + final SuggestedWordInfo autoCommitCandidate = mSuggestedWords.getAutoCommitCandidate(); + // Commit except the last word for phrase gesture if the top suggestion is eligible for auto + // commit. + if (settingsValues.mPhraseGestureEnabled && null != autoCommitCandidate) { + // Find the last space + final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1; + if (0 != indexOfLastSpace) { + mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1); + final SuggestedWords suggestedWordsForLastWordOfPhraseGesture = + suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture(); + mLatinIME.showSuggestionStrip(suggestedWordsForLastWordOfPhraseGesture); + } + final String lastWord = batchInputText.substring(indexOfLastSpace); + mWordComposer.setBatchInputWord(lastWord); + mConnection.setComposingText(lastWord, 1); + } else { + mWordComposer.setBatchInputWord(batchInputText); + mConnection.setComposingText(batchInputText, 1); + } + mConnection.endBatchEdit(); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords); + } + // Space state must be updated before calling updateShiftState + mSpaceState = SpaceState.PHANTOM; + keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues), + getCurrentRecapitalizeState()); + } + + /** + * Commit the typed string to the editor. + * + * This is typically called when we should commit the currently composing word without applying + * auto-correction to it. Typically, we come here upon pressing a separator when the keyboard + * is configured to not do auto-correction at all (because of the settings or the properties of + * the editor). In this case, `separatorString' is set to the separator that was pressed. + * We also come here in a variety of cases with external user action. For example, when the + * cursor is moved while there is a composition, or when the keyboard is closed, or when the + * user presses the Send button for an SMS, we don't auto-correct as that would be unexpected. + * In this case, `separatorString' is set to NOT_A_SEPARATOR. + * + * @param settingsValues the current values of the settings. + * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none. + */ + // TODO: Make this private + public void commitTyped(final SettingsValues settingsValues, final String separatorString) { + if (!mWordComposer.isComposingWord()) return; + final String typedWord = mWordComposer.getTypedWord(); + if (typedWord.length() > 0) { + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); + } + commitChosenWord(settingsValues, typedWord, + LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString); + } + } + + /** + * Commit the current auto-correction. + * + * This will commit the best guess of the keyboard regarding what the user meant by typing + * the currently composing word. The IME computes suggestions and assigns a confidence score + * to each of them; when it's confident enough in one suggestion, it replaces the typed string + * by this suggestion at commit time. When it's not confident enough, or when it has no + * suggestions, or when the settings or environment does not allow for auto-correction, then + * this method just commits the typed string. + * Note that if suggestions are currently being computed in the background, this method will + * block until the computation returns. This is necessary for consistency (it would be very + * strange if pressing space would commit a different word depending on how fast you press). + * + * @param settingsValues the current value of the settings. + * @param separator the separator that's causing the commit to happen. + */ + private void commitCurrentAutoCorrection(final SettingsValues settingsValues, + final String separator, + // TODO: Remove this argument. + final LatinIME.UIHandler handler) { + // Complete any pending suggestions query first + if (handler.hasPendingUpdateSuggestions()) { + handler.cancelUpdateSuggestionStrip(); + performUpdateSuggestionStripSync(settingsValues); + } + final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); + final String typedWord = mWordComposer.getTypedWord(); + final String autoCorrection = (typedAutoCorrection != null) + ? typedAutoCorrection : typedWord; + if (autoCorrection != null) { + if (TextUtils.isEmpty(typedWord)) { + throw new RuntimeException("We have an auto-correction but the typed word " + + "is empty? Impossible! I must commit suicide."); + } + if (settingsValues.mIsInternal) { + LatinImeLoggerUtils.onAutoCorrection( + typedWord, autoCorrection, separator, mWordComposer); + } + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + final SuggestedWords suggestedWords = mSuggestedWords; + ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, + separator, mWordComposer.isBatchMode(), suggestedWords); + } + commitChosenWord(settingsValues, autoCorrection, + LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator); + if (!typedWord.equals(autoCorrection)) { + // This will make the correction flash for a short while as a visual clue + // to the user that auto-correction happened. It has no other effect; in particular + // note that this won't affect the text inside the text field AT ALL: it only makes + // the segment of text starting at the supplied index and running for the length + // of the auto-correction flash. At this moment, the "typedWord" argument is + // ignored by TextView. + mConnection.commitCorrection(new CorrectionInfo( + mConnection.getExpectedSelectionEnd() - autoCorrection.length(), + typedWord, autoCorrection)); + } + } + } + + /** + * Commits the chosen word to the text field and saves it for later retrieval. + * + * @param settingsValues the current values of the settings. + * @param chosenWord the word we want to commit. + * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_* + * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none. + */ + private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, + final int commitType, final String separatorString) { + final SuggestedWords suggestedWords = mSuggestedWords; + final CharSequence chosenWordWithSuggestions = + SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord, + suggestedWords); + mConnection.commitText(chosenWordWithSuggestions, 1); + // TODO: we pass 2 here, but would it be better to move this above and pass 1 instead? + final String prevWord = mConnection.getNthPreviousWord( + settingsValues.mSpacingAndPunctuations, 2); + // Add the word to the user history dictionary + performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWord); + // 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#didCommitTypedWord by string equality of the remembered + // strings. + mLastComposedWord = mWordComposer.commitWord(commitType, + chosenWordWithSuggestions, separatorString, prevWord); + final boolean shouldDiscardPreviousWordForSuggestion; + if (0 == StringUtils.codePointCount(separatorString)) { + // Separator is 0-length, we can keep the previous word for suggestion. Either this + // was a manual pick or the language has no spaces in which case we want to keep the + // previous word, or it was the keyboard closing or the cursor moving in which case it + // will be reset anyway. + shouldDiscardPreviousWordForSuggestion = false; + } else { + // Otherwise, we discard if the separator contains any non-whitespace. + shouldDiscardPreviousWordForSuggestion = + !StringUtils.containsOnlyWhitespace(separatorString); + } + if (shouldDiscardPreviousWordForSuggestion) { + mWordComposer.discardPreviousWordForSuggestion(); + } + } + + /** + * Retry resetting caches in the rich input connection. + * + * When the editor can't be accessed we can't reset the caches, so we schedule a retry. + * This method handles the retry, and re-schedules a new retry if we still can't access. + * We only retry up to 5 times before giving up. + * + * @param settingsValues the current values of the settings. + * @param tryResumeSuggestions Whether we should resume suggestions or not. + * @param remainingTries How many times we may try again before giving up. + * @return whether true if the caches were successfully reset, false otherwise. + */ + // TODO: make this private + public boolean retryResetCachesAndReturnSuccess(final SettingsValues settingsValues, + final boolean tryResumeSuggestions, final int remainingTries, + // TODO: remove these arguments + final LatinIME.UIHandler handler) { + if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess( + mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), + false /* shouldFinishComposition */)) { + if (0 < remainingTries) { + handler.postResetCaches(tryResumeSuggestions, remainingTries - 1); + return false; + } + // If remainingTries is 0, we should stop waiting for new tries, however we'll still + // return true as we need to perform other tasks (for example, loading the keyboard). + } + mConnection.tryFixLyingCursorPosition(); + if (tryResumeSuggestions) { + handler.postResumeSuggestions(); + } + return true; + } +} diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java new file mode 100644 index 000000000..9dbe2c38b --- /dev/null +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2013 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.inputlogic; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; + +import com.android.inputmethod.compat.LooperCompatUtils; +import com.android.inputmethod.latin.InputPointers; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; + +/** + * A helper to manage deferred tasks for the input logic. + */ +class InputLogicHandler implements Handler.Callback { + final Handler mNonUIThreadHandler; + // TODO: remove this reference. + final LatinIME mLatinIME; + final InputLogic mInputLogic; + private final Object mLock = new Object(); + private boolean mInBatchInput; // synchronized using {@link #mLock}. + + private static final int MSG_GET_SUGGESTED_WORDS = 1; + + // A handler that never does anything. This is used for cases where events come before anything + // is initialized, though probably only the monkey can actually do this. + public static final InputLogicHandler NULL_HANDLER = new InputLogicHandler() { + @Override + public void reset() {} + @Override + public boolean handleMessage(final Message msg) { return true; } + @Override + public void onStartBatchInput() {} + @Override + public void onUpdateBatchInput(final InputPointers batchPointers, + final int sequenceNumber) {} + @Override + public void onCancelBatchInput() {} + @Override + public void updateTailBatchInput(final InputPointers batchPointers, + final int sequenceNumber) {} + @Override + public void getSuggestedWords(final int sessionId, final int sequenceNumber, + final OnGetSuggestedWordsCallback callback) {} + }; + + private InputLogicHandler() { + mNonUIThreadHandler = null; + mLatinIME = null; + mInputLogic = null; + } + + public InputLogicHandler(final LatinIME latinIME, final InputLogic inputLogic) { + final HandlerThread handlerThread = new HandlerThread( + InputLogicHandler.class.getSimpleName()); + handlerThread.start(); + mNonUIThreadHandler = new Handler(handlerThread.getLooper(), this); + mLatinIME = latinIME; + mInputLogic = inputLogic; + } + + public void reset() { + mNonUIThreadHandler.removeCallbacksAndMessages(null); + } + + // In unit tests, we create several instances of LatinIME, which results in several instances + // of InputLogicHandler. To avoid these handlers lingering, we call this. + public void destroy() { + LooperCompatUtils.quitSafely(mNonUIThreadHandler.getLooper()); + } + + /** + * Handle a message. + * @see android.os.Handler.Callback#handleMessage(android.os.Message) + */ + // Called on the Non-UI handler thread by the Handler code. + @Override + public boolean handleMessage(final Message msg) { + switch (msg.what) { + case MSG_GET_SUGGESTED_WORDS: + mLatinIME.getSuggestedWords(msg.arg1 /* sessionId */, + msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj); + break; + } + return true; + } + + // Called on the UI thread by InputLogic. + public void onStartBatchInput() { + synchronized (mLock) { + mInBatchInput = true; + } + } + + public boolean isInBatchInput() { + return mInBatchInput; + } + + /** + * Fetch suggestions corresponding to an update of a batch input. + * @param batchPointers the updated pointers, including the part that was passed last time. + * @param sequenceNumber the sequence number associated with this batch input. + * @param isTailBatchInput true if this is the end of a batch input, false if it's an update. + */ + // This method can be called from any thread and will see to it that the correct threads + // are used for parts that require it. This method will send a message to the Non-UI handler + // thread to pull suggestions, and get the inlined callback to get called on the Non-UI + // handler thread. If this is the end of a batch input, the callback will then proceed to + // send a message to the UI handler in LatinIME so that showing suggestions can be done on + // the UI thread. + private void updateBatchInput(final InputPointers batchPointers, + final int sequenceNumber, final boolean isTailBatchInput) { + synchronized (mLock) { + if (!mInBatchInput) { + // Batch input has ended or canceled while the message was being delivered. + return; + } + mInputLogic.mWordComposer.setBatchInputPointers(batchPointers); + getSuggestedWords(Suggest.SESSION_GESTURE, sequenceNumber, + new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords(SuggestedWords suggestedWords) { + // We're now inside the callback. This always runs on the Non-UI thread, + // no matter what thread updateBatchInput was originally called on. + if (suggestedWords.isEmpty()) { + // Use old suggestions if we don't have any new ones. + // Previous suggestions are found in InputLogic#mSuggestedWords. + // Since these are the most recent ones and we just recomputed + // new ones to update them, then the previous ones are there. + suggestedWords = mInputLogic.mSuggestedWords; + } + mLatinIME.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWords, + isTailBatchInput /* dismissGestureFloatingPreviewText */); + if (isTailBatchInput) { + mInBatchInput = false; + // The following call schedules onEndBatchInputInternal + // to be called on the UI thread. + mLatinIME.mHandler.showTailBatchInputResult(suggestedWords); + } + } + }); + } + } + + /** + * Update a batch input. + * + * This fetches suggestions and updates the suggestion strip and the floating text preview. + * + * @param batchPointers the updated batch pointers. + * @param sequenceNumber the sequence number associated with this batch input. + */ + // Called on the UI thread by InputLogic. + public void onUpdateBatchInput(final InputPointers batchPointers, + final int sequenceNumber) { + updateBatchInput(batchPointers, sequenceNumber, false /* isTailBatchInput */); + } + + /** + * Cancel a batch input. + * + * Note that as opposed to updateTailBatchInput, we do the UI side of this immediately on the + * same thread, rather than get this to call a method in LatinIME. This is because + * canceling a batch input does not necessitate the long operation of pulling suggestions. + */ + // Called on the UI thread by InputLogic. + public void onCancelBatchInput() { + synchronized (mLock) { + mInBatchInput = false; + } + } + + /** + * Trigger an update for a tail batch input. + * + * A tail batch input is the last update for a gesture, the one that is triggered after the + * user lifts their finger. This method schedules fetching suggestions on the non-UI thread, + * then when the suggestions are computed it comes back on the UI thread to update the + * suggestion strip, commit the first suggestion, and dismiss the floating text preview. + * + * @param batchPointers the updated batch pointers. + * @param sequenceNumber the sequence number associated with this batch input. + */ + // Called on the UI thread by InputLogic. + public void updateTailBatchInput(final InputPointers batchPointers, + final int sequenceNumber) { + updateBatchInput(batchPointers, sequenceNumber, true /* isTailBatchInput */); + } + + public void getSuggestedWords(final int sessionId, final int sequenceNumber, + final OnGetSuggestedWordsCallback callback) { + mNonUIThreadHandler.obtainMessage( + MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback).sendToTarget(); + } +} diff --git a/java/src/com/android/inputmethod/latin/inputlogic/SpaceState.java b/java/src/com/android/inputmethod/latin/inputlogic/SpaceState.java new file mode 100644 index 000000000..ce80c0016 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/inputlogic/SpaceState.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 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.inputlogic; + +/** + * Class for managing space states. + * + * At any given time, the input logic is in one of five possible space states. Depending on the + * current space state, some behavior will change; the prime example of this is the PHANTOM state, + * in which any subsequent letter input will input a space before the letter. Read on the + * description inside this class for each of the space states. + */ +public class SpaceState { + // None: the state where all the keyboard behavior is the most "standard" and no automatic + // input is added or removed. In this state, all self-inserting keys only insert themselves, + // and backspace removes one character. + public static final int NONE = 0; + // Double space: the state where the user pressed space twice quickly, which LatinIME + // resolved as period-space. In this state, pressing backspace will undo the + // double-space-to-period insertion: it will replace ". " with " ". + public static final int DOUBLE = 1; + // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip + // have just been swapped. In this state, pressing backspace will undo the swap: the + // characters will be swapped back back, and the space state will go to WEAK. + public static final int 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). In this state, pressing a punctuation from the suggestion + // strip inserts it before the space (while it inserts it after the space in the NONE state). + public static final int 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. In this state, + // non-separators insert a space before they get inserted. + public static final int PHANTOM = 4; + + private SpaceState() { + // This class is not publicly instantiable. + } +} diff --git a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java deleted file mode 100644 index fda97dafc..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.TreeMap; - -/** - * A base class of the binary dictionary decoder. - */ -public abstract class AbstractDictDecoder implements DictDecoder { - protected FileHeader readHeader(final DictBuffer dictBuffer) - throws IOException, UnsupportedFormatException { - if (dictBuffer == null) { - openDictBuffer(); - } - - final int version = HeaderReader.readVersion(dictBuffer); - if (version < FormatSpec.MINIMUM_SUPPORTED_VERSION - || version > FormatSpec.MAXIMUM_SUPPORTED_VERSION) { - throw new UnsupportedFormatException("Unsupported version : " + version); - } - // TODO: Remove this field. - final int optionsFlags = HeaderReader.readOptionFlags(dictBuffer); - - final int headerSize = HeaderReader.readHeaderSize(dictBuffer); - - if (headerSize < 0) { - throw new UnsupportedFormatException("header size can't be negative."); - } - - final HashMap<String, String> attributes = HeaderReader.readAttributes(dictBuffer, - headerSize); - - final FileHeader header = new FileHeader(headerSize, - new FusionDictionary.DictionaryOptions(attributes, - 0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG), - 0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)), - new FormatOptions(version, - 0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE), - 0 != (optionsFlags & FormatSpec.CONTAINS_TIMESTAMP_FLAG))); - return header; - } - - @Override @UsedForTesting - public int getTerminalPosition(final String word) - throws IOException, UnsupportedFormatException { - if (!isDictBufferOpen()) { - openDictBuffer(); - } - return BinaryDictIOUtils.getTerminalPosition(this, word); - } - - @Override @UsedForTesting - public void readUnigramsAndBigramsBinary(final TreeMap<Integer, String> words, - final TreeMap<Integer, Integer> frequencies, - final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams) - throws IOException, UnsupportedFormatException { - if (!isDictBufferOpen()) { - openDictBuffer(); - } - BinaryDictIOUtils.readUnigramsAndBigramsBinary(this, words, frequencies, bigrams); - } - - /** - * A utility class for reading a file header. - */ - protected static class HeaderReader { - protected static int readVersion(final DictBuffer dictBuffer) - throws IOException, UnsupportedFormatException { - return BinaryDictDecoderUtils.checkFormatVersion(dictBuffer); - } - - protected static int readOptionFlags(final DictBuffer dictBuffer) { - return dictBuffer.readUnsignedShort(); - } - - protected static int readHeaderSize(final DictBuffer dictBuffer) { - return dictBuffer.readInt(); - } - - protected static HashMap<String, String> readAttributes(final DictBuffer dictBuffer, - final int headerSize) { - final HashMap<String, String> attributes = new HashMap<String, String>(); - while (dictBuffer.position() < headerSize) { - // We can avoid an infinite loop here since dictBuffer.position() is always - // increased by calling CharEncoding.readString. - final String key = CharEncoding.readString(dictBuffer); - final String value = CharEncoding.readString(dictBuffer); - attributes.put(key, value); - } - dictBuffer.position(headerSize); - return attributes; - } - } - - /** - * A utility class for reading a PtNode. - */ - protected static class PtNodeReader { - protected static int readPtNodeOptionFlags(final DictBuffer dictBuffer) { - return dictBuffer.readUnsignedByte(); - } - - protected static int readParentAddress(final DictBuffer dictBuffer, - final FormatOptions formatOptions) { - if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) { - return BinaryDictDecoderUtils.readSInt24(dictBuffer); - } else { - return FormatSpec.NO_PARENT_ADDRESS; - } - } - - protected static int readChildrenAddress(final DictBuffer dictBuffer, final int optionFlags, - final FormatOptions formatOptions) { - if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) { - final int address = BinaryDictDecoderUtils.readSInt24(dictBuffer); - if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS; - return address; - } else { - switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: - return dictBuffer.readUnsignedByte(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES: - return dictBuffer.readUnsignedShort(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES: - return dictBuffer.readUnsignedInt24(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS: - default: - return FormatSpec.NO_CHILDREN_ADDRESS; - } - } - } - - // Reads shortcuts and returns the read length. - protected static int readShortcut(final DictBuffer dictBuffer, - final ArrayList<WeightedString> shortcutTargets) { - final int pointerBefore = dictBuffer.position(); - dictBuffer.readUnsignedShort(); // skip the size - while (true) { - final int targetFlags = dictBuffer.readUnsignedByte(); - final String word = CharEncoding.readString(dictBuffer); - shortcutTargets.add(new WeightedString(word, - targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY)); - if (0 == (targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; - } - return dictBuffer.position() - pointerBefore; - } - - protected static int readBigramAddresses(final DictBuffer dictBuffer, - final ArrayList<PendingAttribute> bigrams, final int baseAddress) { - int readLength = 0; - int bigramCount = 0; - while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - final int bigramFlags = dictBuffer.readUnsignedByte(); - ++readLength; - final int sign = 0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE) - ? 1 : -1; - int bigramAddress = baseAddress + readLength; - switch (bigramFlags & FormatSpec.MASK_BIGRAM_ATTR_ADDRESS_TYPE) { - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE: - bigramAddress += sign * dictBuffer.readUnsignedByte(); - readLength += 1; - break; - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES: - bigramAddress += sign * dictBuffer.readUnsignedShort(); - readLength += 2; - break; - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES: - bigramAddress += sign * dictBuffer.readUnsignedInt24(); - readLength += 3; - break; - default: - throw new RuntimeException("Has bigrams with no address"); - } - bigrams.add(new PendingAttribute( - bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY, - bigramAddress)); - if (0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; - } - return readLength; - } - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java deleted file mode 100644 index 216492b4d..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.Map; -import java.util.TreeMap; - -/** - * Decodes binary files for a FusionDictionary. - * - * All the methods in this class are static. - * - * TODO: Remove calls from classes except Ver3DictDecoder - * TODO: Move this file to makedict/internal. - * TODO: Rename this class to DictDecoderUtils. - */ -public final class BinaryDictDecoderUtils { - - private static final boolean DBG = MakedictLog.DBG; - - private BinaryDictDecoderUtils() { - // This utility class is not publicly instantiable. - } - - private static final int MAX_JUMPS = 12; - - @UsedForTesting - public interface DictBuffer { - public int readUnsignedByte(); - public int readUnsignedShort(); - public int readUnsignedInt24(); - public int readInt(); - public int position(); - public void position(int newPosition); - public void put(final byte b); - public int limit(); - @UsedForTesting - public int capacity(); - } - - public static final class ByteBufferDictBuffer implements DictBuffer { - private ByteBuffer mBuffer; - - public ByteBufferDictBuffer(final ByteBuffer buffer) { - mBuffer = buffer; - } - - @Override - public int readUnsignedByte() { - return mBuffer.get() & 0xFF; - } - - @Override - public int readUnsignedShort() { - return mBuffer.getShort() & 0xFFFF; - } - - @Override - public int readUnsignedInt24() { - final int retval = readUnsignedByte(); - return (retval << 16) + readUnsignedShort(); - } - - @Override - public int readInt() { - return mBuffer.getInt(); - } - - @Override - public int position() { - return mBuffer.position(); - } - - @Override - public void position(int newPos) { - mBuffer.position(newPos); - } - - @Override - public void put(final byte b) { - mBuffer.put(b); - } - - @Override - public int limit() { - return mBuffer.limit(); - } - - @Override - public int capacity() { - return mBuffer.capacity(); - } - } - - /** - * A class grouping utility function for our specific character encoding. - */ - static final class CharEncoding { - private static final int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20; - private static final int MAXIMAL_ONE_BYTE_CHARACTER_VALUE = 0xFF; - - /** - * Helper method to find out whether this code fits on one byte - */ - private static boolean fitsOnOneByte(final int character) { - return character >= MINIMAL_ONE_BYTE_CHARACTER_VALUE - && character <= MAXIMAL_ONE_BYTE_CHARACTER_VALUE; - } - - /** - * Compute the size of a character given its character code. - * - * Char format is: - * 1 byte = bbbbbbbb match - * case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte - * else: if 00011111 (= 0x1F) : this is the terminator. This is a relevant choice because - * unicode code points range from 0 to 0x10FFFF, so any 3-byte value starting with - * 00011111 would be outside unicode. - * else: iso-latin-1 code - * This allows for the whole unicode range to be encoded, including chars outside of - * the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control - * characters which should never happen anyway (and still work, but take 3 bytes). - * - * @param character the character code. - * @return the size in binary encoded-form, either 1 or 3 bytes. - */ - static int getCharSize(final int character) { - // See char encoding in FusionDictionary.java - if (fitsOnOneByte(character)) return 1; - if (FormatSpec.INVALID_CHARACTER == character) return 1; - return 3; - } - - /** - * Compute the byte size of a character array. - */ - static int getCharArraySize(final int[] chars) { - int size = 0; - for (int character : chars) size += getCharSize(character); - return size; - } - - /** - * Writes a char array to a byte buffer. - * - * @param codePoints the code point array to write. - * @param buffer the byte buffer to write to. - * @param index the index in buffer to write the character array to. - * @return the index after the last character. - */ - static int writeCharArray(final int[] codePoints, final byte[] buffer, int index) { - for (int codePoint : codePoints) { - if (1 == getCharSize(codePoint)) { - buffer[index++] = (byte)codePoint; - } else { - buffer[index++] = (byte)(0xFF & (codePoint >> 16)); - buffer[index++] = (byte)(0xFF & (codePoint >> 8)); - buffer[index++] = (byte)(0xFF & codePoint); - } - } - return index; - } - - /** - * Writes a string with our character format to a byte buffer. - * - * This will also write the terminator byte. - * - * @param buffer the byte buffer to write to. - * @param origin the offset to write from. - * @param word the string to write. - * @return the size written, in bytes. - */ - static int writeString(final byte[] buffer, final int origin, - final String word) { - final int length = word.length(); - int index = origin; - for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { - final int codePoint = word.codePointAt(i); - if (1 == getCharSize(codePoint)) { - buffer[index++] = (byte)codePoint; - } else { - buffer[index++] = (byte)(0xFF & (codePoint >> 16)); - buffer[index++] = (byte)(0xFF & (codePoint >> 8)); - buffer[index++] = (byte)(0xFF & codePoint); - } - } - buffer[index++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR; - return index - origin; - } - - /** - * Writes a string with our character format to an OutputStream. - * - * This will also write the terminator byte. - * - * @param buffer the OutputStream to write to. - * @param word the string to write. - */ - static void writeString(final OutputStream buffer, final String word) throws IOException { - final int length = word.length(); - for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { - final int codePoint = word.codePointAt(i); - if (1 == getCharSize(codePoint)) { - buffer.write((byte) codePoint); - } else { - buffer.write((byte) (0xFF & (codePoint >> 16))); - buffer.write((byte) (0xFF & (codePoint >> 8))); - buffer.write((byte) (0xFF & codePoint)); - } - } - buffer.write(FormatSpec.PTNODE_CHARACTERS_TERMINATOR); - } - - /** - * Reads a string from a DictBuffer. This is the converse of the above method. - */ - static String readString(final DictBuffer dictBuffer) { - final StringBuilder s = new StringBuilder(); - int character = readChar(dictBuffer); - while (character != FormatSpec.INVALID_CHARACTER) { - s.appendCodePoint(character); - character = readChar(dictBuffer); - } - return s.toString(); - } - - /** - * Reads a character from the buffer. - * - * This follows the character format documented earlier in this source file. - * - * @param dictBuffer the buffer, positioned over an encoded character. - * @return the character code. - */ - static int readChar(final DictBuffer dictBuffer) { - int character = dictBuffer.readUnsignedByte(); - if (!fitsOnOneByte(character)) { - if (FormatSpec.PTNODE_CHARACTERS_TERMINATOR == character) { - return FormatSpec.INVALID_CHARACTER; - } - character <<= 16; - character += dictBuffer.readUnsignedShort(); - } - return character; - } - } - - // Input methods: Read a binary dictionary to memory. - // readDictionaryBinary is the public entry point for them. - - static int readSInt24(final DictBuffer dictBuffer) { - final int retval = dictBuffer.readUnsignedInt24(); - final int sign = ((retval & FormatSpec.MSB24) != 0) ? -1 : 1; - return sign * (retval & FormatSpec.SINT24_MAX); - } - - static int readChildrenAddress(final DictBuffer dictBuffer, - final int optionFlags, final FormatOptions options) { - if (options.mSupportsDynamicUpdate) { - final int address = dictBuffer.readUnsignedInt24(); - if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS; - if ((address & FormatSpec.MSB24) != 0) { - return -(address & FormatSpec.SINT24_MAX); - } else { - return address; - } - } - switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: - return dictBuffer.readUnsignedByte(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES: - return dictBuffer.readUnsignedShort(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES: - return dictBuffer.readUnsignedInt24(); - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS: - default: - return FormatSpec.NO_CHILDREN_ADDRESS; - } - } - - static int readParentAddress(final DictBuffer dictBuffer, - final FormatOptions formatOptions) { - if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) { - final int parentAddress = dictBuffer.readUnsignedInt24(); - final int sign = ((parentAddress & FormatSpec.MSB24) != 0) ? -1 : 1; - return sign * (parentAddress & FormatSpec.SINT24_MAX); - } else { - return FormatSpec.NO_PARENT_ADDRESS; - } - } - - /** - * Reads and returns the PtNode count out of a buffer and forwards the pointer. - */ - /* package */ static int readPtNodeCount(final DictBuffer dictBuffer) { - final int msb = dictBuffer.readUnsignedByte(); - if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= msb) { - return msb; - } else { - return ((FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT & msb) << 8) - + dictBuffer.readUnsignedByte(); - } - } - - /** - * Finds, as a string, the word at the position passed as an argument. - * - * @param dictDecoder the dict decoder. - * @param headerSize the size of the header. - * @param pos the position to seek. - * @param formatOptions file format options. - * @return the word with its frequency, as a weighted string. - */ - /* package for tests */ static WeightedString getWordAtPosition(final DictDecoder dictDecoder, - final int headerSize, final int pos, final FormatOptions formatOptions) { - final WeightedString result; - final int originalPos = dictDecoder.getPosition(); - dictDecoder.setPosition(pos); - - if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) { - result = getWordAtPositionWithParentAddress(dictDecoder, pos, formatOptions); - } else { - result = getWordAtPositionWithoutParentAddress(dictDecoder, headerSize, pos, - formatOptions); - } - - dictDecoder.setPosition(originalPos); - return result; - } - - @SuppressWarnings("unused") - private static WeightedString getWordAtPositionWithParentAddress(final DictDecoder dictDecoder, - final int pos, final FormatOptions options) { - int currentPos = pos; - int frequency = Integer.MIN_VALUE; - final StringBuilder builder = new StringBuilder(); - // the length of the path from the root to the leaf is limited by MAX_WORD_LENGTH - for (int count = 0; count < FormatSpec.MAX_WORD_LENGTH; ++count) { - PtNodeInfo currentInfo; - int loopCounter = 0; - do { - dictDecoder.setPosition(currentPos); - currentInfo = dictDecoder.readPtNode(currentPos, options); - if (BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, options)) { - currentPos = currentInfo.mParentAddress + currentInfo.mOriginalAddress; - } - if (DBG && loopCounter++ > MAX_JUMPS) { - MakedictLog.d("Too many jumps - probably a bug"); - } - } while (BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, options)); - if (Integer.MIN_VALUE == frequency) frequency = currentInfo.mFrequency; - builder.insert(0, - new String(currentInfo.mCharacters, 0, currentInfo.mCharacters.length)); - if (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS) break; - currentPos = currentInfo.mParentAddress + currentInfo.mOriginalAddress; - } - return new WeightedString(builder.toString(), frequency); - } - - private static WeightedString getWordAtPositionWithoutParentAddress( - final DictDecoder dictDecoder, final int headerSize, final int pos, - final FormatOptions options) { - dictDecoder.setPosition(headerSize); - final int count = dictDecoder.readPtNodeCount(); - int groupPos = headerSize + BinaryDictIOUtils.getPtNodeCountSize(count); - final StringBuilder builder = new StringBuilder(); - WeightedString result = null; - - PtNodeInfo last = null; - for (int i = count - 1; i >= 0; --i) { - PtNodeInfo info = dictDecoder.readPtNode(groupPos, options); - groupPos = info.mEndAddress; - if (info.mOriginalAddress == pos) { - builder.append(new String(info.mCharacters, 0, info.mCharacters.length)); - result = new WeightedString(builder.toString(), info.mFrequency); - break; // and return - } - if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) { - if (info.mChildrenAddress > pos) { - if (null == last) continue; - builder.append(new String(last.mCharacters, 0, last.mCharacters.length)); - dictDecoder.setPosition(last.mChildrenAddress); - i = dictDecoder.readPtNodeCount(); - groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i); - last = null; - continue; - } - last = info; - } - if (0 == i && BinaryDictIOUtils.hasChildrenAddress(last.mChildrenAddress)) { - builder.append(new String(last.mCharacters, 0, last.mCharacters.length)); - dictDecoder.setPosition(last.mChildrenAddress); - i = dictDecoder.readPtNodeCount(); - groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i); - last = null; - continue; - } - } - return result; - } - - /** - * Reads a single node array from a buffer. - * - * This methods reads the file at the current position. A node array is fully expected to start - * at the current position. - * This will recursively read other node arrays into the structure, populating the reverse - * maps on the fly and using them to keep track of already read nodes. - * - * @param dictDecoder the dict decoder, correctly positioned at the start of a node array. - * @param headerSize the size, in bytes, of the file header. - * @param reverseNodeArrayMap a mapping from addresses to already read node arrays. - * @param reversePtNodeMap a mapping from addresses to already read PtNodes. - * @param options file format options. - * @return the read node array with all his children already read. - */ - private static PtNodeArray readNodeArray(final DictDecoder dictDecoder, - final int headerSize, final Map<Integer, PtNodeArray> reverseNodeArrayMap, - final Map<Integer, PtNode> reversePtNodeMap, final FormatOptions options) - throws IOException { - final ArrayList<PtNode> nodeArrayContents = new ArrayList<PtNode>(); - final int nodeArrayOriginPos = dictDecoder.getPosition(); - - do { // Scan the linked-list node. - final int nodeArrayHeadPos = dictDecoder.getPosition(); - final int count = dictDecoder.readPtNodeCount(); - int groupOffsetPos = nodeArrayHeadPos + BinaryDictIOUtils.getPtNodeCountSize(count); - for (int i = count; i > 0; --i) { // Scan the array of PtNode. - PtNodeInfo info = dictDecoder.readPtNode(groupOffsetPos, options); - if (BinaryDictIOUtils.isMovedPtNode(info.mFlags, options)) continue; - ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets; - ArrayList<WeightedString> bigrams = null; - if (null != info.mBigrams) { - bigrams = new ArrayList<WeightedString>(); - for (PendingAttribute bigram : info.mBigrams) { - final WeightedString word = getWordAtPosition(dictDecoder, headerSize, - bigram.mAddress, options); - final int reconstructedFrequency = - BinaryDictIOUtils.reconstructBigramFrequency(word.mFrequency, - bigram.mFrequency); - bigrams.add(new WeightedString(word.mWord, reconstructedFrequency)); - } - } - if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) { - PtNodeArray children = reverseNodeArrayMap.get(info.mChildrenAddress); - if (null == children) { - final int currentPosition = dictDecoder.getPosition(); - dictDecoder.setPosition(info.mChildrenAddress); - children = readNodeArray(dictDecoder, headerSize, reverseNodeArrayMap, - reversePtNodeMap, options); - dictDecoder.setPosition(currentPosition); - } - nodeArrayContents.add( - new PtNode(info.mCharacters, shortcutTargets, bigrams, - info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children)); - } else { - nodeArrayContents.add( - new PtNode(info.mCharacters, shortcutTargets, bigrams, - info.mFrequency, - 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD), - 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED))); - } - groupOffsetPos = info.mEndAddress; - } - - // reach the end of the array. - if (options.mSupportsDynamicUpdate) { - final boolean hasValidForwardLink = dictDecoder.readAndFollowForwardLink(); - if (!hasValidForwardLink) break; - } - } while (options.mSupportsDynamicUpdate && dictDecoder.hasNextPtNodeArray()); - - final PtNodeArray nodeArray = new PtNodeArray(nodeArrayContents); - nodeArray.mCachedAddressBeforeUpdate = nodeArrayOriginPos; - nodeArray.mCachedAddressAfterUpdate = nodeArrayOriginPos; - reverseNodeArrayMap.put(nodeArray.mCachedAddressAfterUpdate, nodeArray); - return nodeArray; - } - - /** - * Helper function to get the binary format version from the header. - * @throws IOException - */ - private static int getFormatVersion(final DictBuffer dictBuffer) - throws IOException { - final int magic = dictBuffer.readInt(); - if (FormatSpec.MAGIC_NUMBER == magic) return dictBuffer.readUnsignedShort(); - return FormatSpec.NOT_A_VERSION_NUMBER; - } - - /** - * Helper function to get and validate the binary format version. - * @throws UnsupportedFormatException - * @throws IOException - */ - static int checkFormatVersion(final DictBuffer dictBuffer) - throws IOException, UnsupportedFormatException { - final int version = getFormatVersion(dictBuffer); - if (version < FormatSpec.MINIMUM_SUPPORTED_VERSION - || version > FormatSpec.MAXIMUM_SUPPORTED_VERSION) { - throw new UnsupportedFormatException("This file has version " + version - + ", but this implementation does not support versions above " - + FormatSpec.MAXIMUM_SUPPORTED_VERSION); - } - return version; - } - - /** - * Reads a buffer and returns the memory representation of the dictionary. - * - * This high-level method takes a buffer and reads its contents, populating a - * FusionDictionary structure. The optional dict argument is an existing dictionary to - * which words from the buffer should be added. If it is null, a new dictionary is created. - * - * @param dictDecoder the dict decoder. - * @param dict an optional dictionary to add words to, or null. - * @return the created (or merged) dictionary. - */ - @UsedForTesting - /* package */ static FusionDictionary readDictionaryBinary(final DictDecoder dictDecoder, - final FusionDictionary dict) throws IOException, UnsupportedFormatException { - // Read header - final FileHeader fileHeader = dictDecoder.readHeader(); - - Map<Integer, PtNodeArray> reverseNodeArrayMapping = new TreeMap<Integer, PtNodeArray>(); - Map<Integer, PtNode> reversePtNodeMapping = new TreeMap<Integer, PtNode>(); - final PtNodeArray root = readNodeArray(dictDecoder, fileHeader.mHeaderSize, - reverseNodeArrayMapping, reversePtNodeMapping, fileHeader.mFormatOptions); - - FusionDictionary newDict = new FusionDictionary(root, fileHeader.mDictionaryOptions); - if (null != dict) { - for (final Word w : dict) { - if (w.mIsBlacklistEntry) { - newDict.addBlacklistEntry(w.mWord, w.mShortcutTargets, w.mIsNotAWord); - } else { - newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets, w.mIsNotAWord); - } - } - for (final Word w : dict) { - // By construction a binary dictionary may not have bigrams pointing to - // words that are not also registered as unigrams so we don't have to avoid - // them explicitly here. - for (final WeightedString bigram : w.mBigrams) { - newDict.setBigram(w.mWord, bigram.mWord, bigram.mFrequency); - } - } - } - - return newDict; - } - - /** - * Helper method to pass a file name instead of a File object to isBinaryDictionary. - */ - public static boolean isBinaryDictionary(final String filename) { - final File file = new File(filename); - return isBinaryDictionary(file); - } - - /** - * Basic test to find out whether the file is a binary dictionary or not. - * - * Concretely this only tests the magic number. - * - * @param file The file to test. - * @return true if it's a binary dictionary, false otherwise - */ - public static boolean isBinaryDictionary(final File file) { - FileInputStream inStream = null; - try { - inStream = new FileInputStream(file); - final ByteBuffer buffer = inStream.getChannel().map( - FileChannel.MapMode.READ_ONLY, 0, file.length()); - final int version = getFormatVersion(new ByteBufferDictBuffer(buffer)); - return (version >= FormatSpec.MINIMUM_SUPPORTED_VERSION - && version <= FormatSpec.MAXIMUM_SUPPORTED_VERSION); - } catch (FileNotFoundException e) { - return false; - } catch (IOException e) { - return false; - } finally { - if (inStream != null) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } - } - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java deleted file mode 100644 index d5516ef46..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ /dev/null @@ -1,599 +0,0 @@ -/* - * 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; -import java.util.Stack; - -public final class BinaryDictIOUtils { - private static final boolean DBG = false; - - private BinaryDictIOUtils() { - // This utility class is not publicly instantiable. - } - - private static final class Position { - public static final int NOT_READ_PTNODE_COUNT = -1; - - public int mAddress; - public int mNumOfPtNode; - public int mPosition; - public int mLength; - - public Position(int address, int length) { - mAddress = address; - mLength = length; - mNumOfPtNode = NOT_READ_PTNODE_COUNT; - } - } - - /** - * Retrieves all node arrays without recursive call. - */ - private static void readUnigramsAndBigramsBinaryInner(final DictDecoder dictDecoder, - final int headerSize, final Map<Integer, String> words, - final Map<Integer, Integer> frequencies, - final Map<Integer, ArrayList<PendingAttribute>> bigrams, - final FormatOptions formatOptions) { - int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; - - Stack<Position> stack = new Stack<Position>(); - int index = 0; - - Position initPos = new Position(headerSize, 0); - stack.push(initPos); - - while (!stack.empty()) { - Position p = stack.peek(); - - if (DBG) { - MakedictLog.d("read: address=" + p.mAddress + ", numOfPtNode=" + - p.mNumOfPtNode + ", position=" + p.mPosition + ", length=" + p.mLength); - } - - if (dictDecoder.getPosition() != p.mAddress) dictDecoder.setPosition(p.mAddress); - if (index != p.mLength) index = p.mLength; - - if (p.mNumOfPtNode == Position.NOT_READ_PTNODE_COUNT) { - p.mNumOfPtNode = dictDecoder.readPtNodeCount(); - p.mAddress += getPtNodeCountSize(p.mNumOfPtNode); - p.mPosition = 0; - } - if (p.mNumOfPtNode == 0) { - stack.pop(); - continue; - } - PtNodeInfo info = dictDecoder.readPtNode(p.mAddress, formatOptions); - for (int i = 0; i < info.mCharacters.length; ++i) { - pushedChars[index++] = info.mCharacters[i]; - } - p.mPosition++; - - final boolean isMovedPtNode = isMovedPtNode(info.mFlags, - formatOptions); - final boolean isDeletedPtNode = isDeletedPtNode(info.mFlags, - formatOptions); - if (!isMovedPtNode && !isDeletedPtNode - && info.mFrequency != FusionDictionary.PtNode.NOT_A_TERMINAL) {// found word - words.put(info.mOriginalAddress, new String(pushedChars, 0, index)); - frequencies.put(info.mOriginalAddress, info.mFrequency); - if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams); - } - - if (p.mPosition == p.mNumOfPtNode) { - if (formatOptions.mSupportsDynamicUpdate) { - final boolean hasValidForwardLinkAddress = - dictDecoder.readAndFollowForwardLink(); - if (hasValidForwardLinkAddress && dictDecoder.hasNextPtNodeArray()) { - // The node array has a forward link. - p.mNumOfPtNode = Position.NOT_READ_PTNODE_COUNT; - p.mAddress = dictDecoder.getPosition(); - } else { - stack.pop(); - } - } else { - stack.pop(); - } - } else { - // The Ptnode array has more PtNodes. - p.mAddress = dictDecoder.getPosition(); - } - - if (!isMovedPtNode && hasChildrenAddress(info.mChildrenAddress)) { - final Position childrenPos = new Position(info.mChildrenAddress, index); - stack.push(childrenPos); - } - } - } - - /** - * Reads unigrams and bigrams from the binary file. - * Doesn't store a full memory representation of the dictionary. - * - * @param dictDecoder the dict decoder. - * @param words the map to store the address as a key and the word as a value. - * @param frequencies the map to store the address as a key and the frequency as a value. - * @param bigrams the map to store the address as a key and the list of address as a value. - * @throws IOException if the file can't be read. - * @throws UnsupportedFormatException if the format of the file is not recognized. - */ - /* package */ static void readUnigramsAndBigramsBinary(final DictDecoder dictDecoder, - final Map<Integer, String> words, final Map<Integer, Integer> frequencies, - final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException, - UnsupportedFormatException { - // Read header - final FileHeader header = dictDecoder.readHeader(); - readUnigramsAndBigramsBinaryInner(dictDecoder, header.mHeaderSize, words, - frequencies, bigrams, header.mFormatOptions); - } - - /** - * Gets the address of the last PtNode of the exact matching word in the dictionary. - * If no match is found, returns NOT_VALID_WORD. - * - * @param dictDecoder the dict decoder. - * @param word the word we search for. - * @return the address of the terminal node. - * @throws IOException if the file can't be read. - * @throws UnsupportedFormatException if the format of the file is not recognized. - */ - @UsedForTesting - /* package */ static int getTerminalPosition(final DictDecoder dictDecoder, - final String word) throws IOException, UnsupportedFormatException { - if (word == null) return FormatSpec.NOT_VALID_WORD; - dictDecoder.setPosition(0); - - final FileHeader header = dictDecoder.readHeader(); - int wordPos = 0; - final int wordLen = word.codePointCount(0, word.length()); - for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { - if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD; - - do { - final int ptNodeCount = dictDecoder.readPtNodeCount(); - boolean foundNextPtNode = false; - for (int i = 0; i < ptNodeCount; ++i) { - final int ptNodePos = dictDecoder.getPosition(); - final PtNodeInfo currentInfo = dictDecoder.readPtNode(ptNodePos, - header.mFormatOptions); - final boolean isMovedNode = isMovedPtNode(currentInfo.mFlags, - header.mFormatOptions); - final boolean isDeletedNode = isDeletedPtNode(currentInfo.mFlags, - header.mFormatOptions); - if (isMovedNode) continue; - boolean same = true; - for (int p = 0, j = word.offsetByCodePoints(0, wordPos); - p < currentInfo.mCharacters.length; - ++p, j = word.offsetByCodePoints(j, 1)) { - if (wordPos + p >= wordLen - || word.codePointAt(j) != currentInfo.mCharacters[p]) { - same = false; - break; - } - } - - if (same) { - // found the PtNode matches the word. - if (wordPos + currentInfo.mCharacters.length == wordLen) { - if (currentInfo.mFrequency == PtNode.NOT_A_TERMINAL - || isDeletedNode) { - return FormatSpec.NOT_VALID_WORD; - } else { - return ptNodePos; - } - } - wordPos += currentInfo.mCharacters.length; - if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { - return FormatSpec.NOT_VALID_WORD; - } - foundNextPtNode = true; - dictDecoder.setPosition(currentInfo.mChildrenAddress); - break; - } - } - - // If we found the next PtNode, it is under the file pointer. - // But if not, we are at the end of this node array so we expect to have - // a forward link address that we need to consult and possibly resume - // search on the next node array in the linked list. - if (foundNextPtNode) break; - if (!header.mFormatOptions.mSupportsDynamicUpdate) { - return FormatSpec.NOT_VALID_WORD; - } - - final boolean hasValidForwardLinkAddress = - dictDecoder.readAndFollowForwardLink(); - if (!hasValidForwardLinkAddress || !dictDecoder.hasNextPtNodeArray()) { - return FormatSpec.NOT_VALID_WORD; - } - } while(true); - } - return FormatSpec.NOT_VALID_WORD; - } - - /** - * @return the size written, in bytes. Always 3 bytes. - */ - static int writeSInt24ToBuffer(final DictBuffer dictBuffer, - final int value) { - final int absValue = Math.abs(value); - dictBuffer.put((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF)); - dictBuffer.put((byte)((absValue >> 8) & 0xFF)); - dictBuffer.put((byte)(absValue & 0xFF)); - return 3; - } - - /** - * @return the size written, in bytes. Always 3 bytes. - */ - static int writeSInt24ToStream(final OutputStream destination, final int value) - throws IOException { - final int absValue = Math.abs(value); - destination.write((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF)); - destination.write((byte)((absValue >> 8) & 0xFF)); - destination.write((byte)(absValue & 0xFF)); - return 3; - } - - /** - * @return the size written, in bytes. 1, 2, or 3 bytes. - */ - private static int writeVariableAddress(final OutputStream destination, final int value) - throws IOException { - switch (BinaryDictEncoderUtils.getByteSize(value)) { - case 1: - destination.write((byte)value); - break; - case 2: - destination.write((byte)(0xFF & (value >> 8))); - destination.write((byte)(0xFF & value)); - break; - case 3: - destination.write((byte)(0xFF & (value >> 16))); - destination.write((byte)(0xFF & (value >> 8))); - destination.write((byte)(0xFF & value)); - break; - } - return BinaryDictEncoderUtils.getByteSize(value); - } - - static void skipString(final DictBuffer dictBuffer, - final boolean hasMultipleChars) { - if (hasMultipleChars) { - int character = CharEncoding.readChar(dictBuffer); - while (character != FormatSpec.INVALID_CHARACTER) { - character = CharEncoding.readChar(dictBuffer); - } - } else { - CharEncoding.readChar(dictBuffer); - } - } - - /** - * Write a string to a stream. - * - * @param destination the stream to write. - * @param word the string to be written. - * @return the size written, in bytes. - * @throws IOException - */ - private static int writeString(final OutputStream destination, final String word) - throws IOException { - int size = 0; - final int length = word.length(); - for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { - final int codePoint = word.codePointAt(i); - if (CharEncoding.getCharSize(codePoint) == 1) { - destination.write((byte)codePoint); - size++; - } else { - destination.write((byte)(0xFF & (codePoint >> 16))); - destination.write((byte)(0xFF & (codePoint >> 8))); - destination.write((byte)(0xFF & codePoint)); - size += 3; - } - } - destination.write((byte)FormatSpec.PTNODE_CHARACTERS_TERMINATOR); - size += FormatSpec.PTNODE_TERMINATOR_SIZE; - return size; - } - - /** - * Write a PtNode to an output stream from a PtNodeInfo. - * A PtNode is an in-memory representation of a node in the patricia trie. - * A PtNode info is a container for low-level information about how the - * PtNode is stored in the binary format. - * - * @param destination the stream to write. - * @param info the PtNode info to be written. - * @return the size written, in bytes. - */ - private static int writePtNode(final OutputStream destination, final PtNodeInfo info) - throws IOException { - int size = FormatSpec.PTNODE_FLAGS_SIZE; - destination.write((byte)info.mFlags); - final int parentOffset = info.mParentAddress == FormatSpec.NO_PARENT_ADDRESS ? - FormatSpec.NO_PARENT_ADDRESS : info.mParentAddress - info.mOriginalAddress; - size += writeSInt24ToStream(destination, parentOffset); - - for (int i = 0; i < info.mCharacters.length; ++i) { - if (CharEncoding.getCharSize(info.mCharacters[i]) == 1) { - destination.write((byte)info.mCharacters[i]); - size++; - } else { - size += writeSInt24ToStream(destination, info.mCharacters[i]); - } - } - if (info.mCharacters.length > 1) { - destination.write((byte)FormatSpec.PTNODE_CHARACTERS_TERMINATOR); - size++; - } - - if ((info.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0) { - destination.write((byte)info.mFrequency); - size++; - } - - if (DBG) { - MakedictLog.d("writePtNode origin=" + info.mOriginalAddress + ", size=" + size - + ", child=" + info.mChildrenAddress + ", characters =" - + new String(info.mCharacters, 0, info.mCharacters.length)); - } - final int childrenOffset = info.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS ? - 0 : info.mChildrenAddress - (info.mOriginalAddress + size); - writeSInt24ToStream(destination, childrenOffset); - size += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; - - if (info.mShortcutTargets != null && info.mShortcutTargets.size() > 0) { - final int shortcutListSize = - BinaryDictEncoderUtils.getShortcutListSize(info.mShortcutTargets); - destination.write((byte)(shortcutListSize >> 8)); - destination.write((byte)(shortcutListSize & 0xFF)); - size += 2; - final Iterator<WeightedString> shortcutIterator = info.mShortcutTargets.iterator(); - while (shortcutIterator.hasNext()) { - final WeightedString target = shortcutIterator.next(); - destination.write((byte)BinaryDictEncoderUtils.makeShortcutFlags( - shortcutIterator.hasNext(), target.mFrequency)); - size++; - size += writeString(destination, target.mWord); - } - } - - if (info.mBigrams != null) { - // TODO: Consolidate this code with the code that computes the size of the bigram list - // in BinaryDictEncoderUtils#computeActualNodeArraySize - for (int i = 0; i < info.mBigrams.size(); ++i) { - - final int bigramFrequency = info.mBigrams.get(i).mFrequency; - int bigramFlags = (i < info.mBigrams.size() - 1) - ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0; - size++; - final int bigramOffset = info.mBigrams.get(i).mAddress - (info.mOriginalAddress - + size); - bigramFlags |= (bigramOffset < 0) ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0; - switch (BinaryDictEncoderUtils.getByteSize(bigramOffset)) { - case 1: - bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE; - break; - case 2: - bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES; - break; - case 3: - bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES; - break; - } - bigramFlags |= bigramFrequency & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY; - destination.write((byte)bigramFlags); - size += writeVariableAddress(destination, Math.abs(bigramOffset)); - } - } - return size; - } - - /** - * Compute the size of the PtNode. - */ - static int computePtNodeSize(final PtNodeInfo info, final FormatOptions formatOptions) { - int size = FormatSpec.PTNODE_FLAGS_SIZE + FormatSpec.PARENT_ADDRESS_SIZE - + BinaryDictEncoderUtils.getPtNodeCharactersSize(info.mCharacters) - + getChildrenAddressSize(info.mFlags, formatOptions); - if ((info.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0) { - size += FormatSpec.PTNODE_FREQUENCY_SIZE; - } - if (info.mShortcutTargets != null && !info.mShortcutTargets.isEmpty()) { - size += BinaryDictEncoderUtils.getShortcutListSize(info.mShortcutTargets); - } - if (info.mBigrams != null) { - for (final PendingAttribute attr : info.mBigrams) { - size += FormatSpec.PTNODE_FLAGS_SIZE; - size += BinaryDictEncoderUtils.getByteSize(attr.mAddress); - } - } - return size; - } - - /** - * Write a node array to the stream. - * - * @param destination the stream to write. - * @param infos an array of PtNodeInfo to be written. - * @return the size written, in bytes. - * @throws IOException - */ - static int writeNodes(final OutputStream destination, final PtNodeInfo[] infos) - throws IOException { - int size = getPtNodeCountSize(infos.length); - switch (getPtNodeCountSize(infos.length)) { - case 1: - destination.write((byte)infos.length); - break; - case 2: - final int encodedPtNodeCount = - infos.length | FormatSpec.LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG; - destination.write((byte)(encodedPtNodeCount >> 8)); - destination.write((byte)(encodedPtNodeCount & 0xFF)); - break; - default: - throw new RuntimeException("Invalid node count size."); - } - for (final PtNodeInfo info : infos) size += writePtNode(destination, info); - writeSInt24ToStream(destination, FormatSpec.NO_FORWARD_LINK_ADDRESS); - return size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE; - } - - private static final int HEADER_READING_BUFFER_SIZE = 16384; - /** - * Convenience method to read the header of a binary file. - * - * This is quite resource intensive - don't call when performance is critical. - * - * @param file The file to read. - * @param offset The offset in the file where to start reading the data. - * @param length The length of the data file. - */ - private static FileHeader getDictionaryFileHeader( - final File file, final long offset, final long length) - throws FileNotFoundException, IOException, UnsupportedFormatException { - final byte[] buffer = new byte[HEADER_READING_BUFFER_SIZE]; - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, - new DictDecoder.DictionaryBufferFactory() { - @Override - public DictBuffer getDictionaryBuffer(File file) - throws FileNotFoundException, IOException { - final FileInputStream inStream = new FileInputStream(file); - try { - inStream.skip(offset); - inStream.read(buffer); - return new ByteArrayDictBuffer(buffer); - } finally { - inStream.close(); - } - } - } - ); - return dictDecoder.readHeader(); - } - - public static FileHeader getDictionaryFileHeaderOrNull(final File file, final long offset, - final long length) { - try { - final FileHeader header = getDictionaryFileHeader(file, offset, length); - return header; - } catch (UnsupportedFormatException e) { - return null; - } catch (IOException e) { - return null; - } - } - - /** - * Helper method to hide the actual value of the no children address. - */ - public static boolean hasChildrenAddress(final int address) { - return FormatSpec.NO_CHILDREN_ADDRESS != address; - } - - /** - * Helper method to check whether the node is moved. - */ - public static boolean isMovedPtNode(final int flags, final FormatOptions options) { - return options.mSupportsDynamicUpdate - && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_MOVED); - } - - /** - * Helper method to check whether the dictionary can be updated dynamically. - */ - public static boolean supportsDynamicUpdate(final FormatOptions options) { - return options.mVersion >= FormatSpec.FIRST_VERSION_WITH_DYNAMIC_UPDATE - && options.mSupportsDynamicUpdate; - } - - /** - * Helper method to check whether the node is deleted. - */ - public static boolean isDeletedPtNode(final int flags, final FormatOptions formatOptions) { - return formatOptions.mSupportsDynamicUpdate - && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_DELETED); - } - - /** - * Compute the binary size of the node count - * @param count the node count - * @return the size of the node count, either 1 or 2 bytes. - */ - public static int getPtNodeCountSize(final int count) { - if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= count) { - return 1; - } else if (FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY >= count) { - return 2; - } else { - throw new RuntimeException("Can't have more than " - + FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY + " PtNode in a PtNodeArray (found " - + count + ")"); - } - } - - static int getChildrenAddressSize(final int optionFlags, - final FormatOptions formatOptions) { - if (formatOptions.mSupportsDynamicUpdate) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; - switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: - return 1; - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES: - return 2; - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES: - return 3; - case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS: - default: - return 0; - } - } - - /** - * Calculate bigram frequency from compressed value - * - * @param unigramFrequency - * @param bigramFrequency compressed frequency - * @return approximate bigram frequency - */ - public static int reconstructBigramFrequency(final int unigramFrequency, - final int bigramFrequency) { - final float stepSize = (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency) - / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY); - final float resultFreqFloat = unigramFrequency + stepSize * (bigramFrequency + 1.0f); - return (int)resultFreqFloat; - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/DictUpdater.java b/java/src/com/android/inputmethod/latin/makedict/DictUpdater.java deleted file mode 100644 index c4f7ec91f..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/DictUpdater.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * An interface of a binary dictionary updater. - */ -@UsedForTesting -public interface DictUpdater extends DictDecoder { - - /** - * Deletes the word from the binary dictionary. - * - * @param word the word to be deleted. - */ - @UsedForTesting - public void deleteWord(final String word) throws IOException, UnsupportedFormatException; - - /** - * Inserts a word into a binary dictionary. - * - * @param word the word to be inserted. - * @param frequency the frequency of the new word. - * @param bigramStrings bigram list, or null if none. - * @param shortcuts shortcut list, or null if none. - * @param isBlackListEntry whether this should be a blacklist entry. - */ - // TODO: Support batch insertion. - @UsedForTesting - public void insertWord(final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, - final ArrayList<WeightedString> shortcuts, final boolean isNotAWord, - final boolean isBlackListEntry) throws IOException, UnsupportedFormatException; -} diff --git a/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java new file mode 100644 index 000000000..df447fd75 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 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.makedict; + +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +/** + * Class representing dictionary header. + */ +public final class DictionaryHeader { + public final int mBodyOffset; + public final DictionaryOptions mDictionaryOptions; + public final FormatOptions mFormatOptions; + + // Note that these are corresponding definitions in native code in latinime::HeaderPolicy + // and latinime::HeaderReadWriteUtils. + // TODO: Standardize the key names and bump up the format version, taking care not to + // break format version 2 dictionaries. + public static final String DICTIONARY_VERSION_KEY = "version"; + public static final String DICTIONARY_LOCALE_KEY = "locale"; + public static final String DICTIONARY_ID_KEY = "dictionary"; + public static final String DICTIONARY_DESCRIPTION_KEY = "description"; + public static final String DICTIONARY_DATE_KEY = "date"; + public static final String HAS_HISTORICAL_INFO_KEY = "HAS_HISTORICAL_INFO"; + public static final String USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE"; + public static final String FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY = + "FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP"; + public static final String FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY = + "FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID"; + public static final String FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY = + "FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS"; + public static final String MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_COUNT"; + public static final String MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_COUNT"; + public static final String ATTRIBUTE_VALUE_TRUE = "1"; + + public DictionaryHeader(final int headerSize, final DictionaryOptions dictionaryOptions, + final FormatOptions formatOptions) throws UnsupportedFormatException { + mDictionaryOptions = dictionaryOptions; + mFormatOptions = formatOptions; + mBodyOffset = formatOptions.mVersion < FormatSpec.VERSION4 ? headerSize : 0; + if (null == getLocaleString()) { + throw new UnsupportedFormatException("Cannot create a FileHeader without a locale"); + } + if (null == getVersion()) { + throw new UnsupportedFormatException( + "Cannot create a FileHeader without a version"); + } + if (null == getId()) { + throw new UnsupportedFormatException("Cannot create a FileHeader without an ID"); + } + } + + // Helper method to get the locale as a String + public String getLocaleString() { + return mDictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_KEY); + } + + // Helper method to get the version String + public String getVersion() { + return mDictionaryOptions.mAttributes.get(DICTIONARY_VERSION_KEY); + } + + // Helper method to get the dictionary ID as a String + public String getId() { + return mDictionaryOptions.mAttributes.get(DICTIONARY_ID_KEY); + } + + // Helper method to get the description + public String getDescription() { + // TODO: Right now each dictionary file comes with a description in its own language. + // It will display as is no matter the device's locale. It should be internationalized. + return mDictionaryOptions.mAttributes.get(DICTIONARY_DESCRIPTION_KEY); + } +}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java deleted file mode 100644 index 28da9ffdd..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * The utility class to help dynamic updates on the binary dictionary. - * - * All the methods in this class are static. - */ -@UsedForTesting -public final class DynamicBinaryDictIOUtils { - private static final boolean DBG = false; - private static final int MAX_JUMPS = 10000; - - private DynamicBinaryDictIOUtils() { - // This utility class is not publicly instantiable. - } - - /* package */ static int markAsDeleted(final int flags) { - return (flags & (~FormatSpec.MASK_CHILDREN_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED; - } - - /** - * Update a parent address in a PtNode that is referred to by ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to write. - * @param ptNodeOriginAddress the address of the PtNode. - * @param newParentAddress the absolute address of the parent. - * @param formatOptions file format options. - */ - private static void updateParentAddress(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newParentAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - final int originalPosition = dictBuffer.position(); - dictBuffer.position(ptNodeOriginAddress); - if (!formatOptions.mSupportsDynamicUpdate) { - throw new RuntimeException("this file format does not support parent addresses"); - } - final int flags = dictBuffer.readUnsignedByte(); - if (BinaryDictIOUtils.isMovedPtNode(flags, formatOptions)) { - // If the node is moved, the parent address is stored in the destination node. - // We are guaranteed to process the destination node later, so there is no need to - // update anything here. - dictBuffer.position(originalPosition); - return; - } - if (DBG) { - MakedictLog.d("update parent address flags=" + flags + ", " + ptNodeOriginAddress); - } - final int parentOffset = newParentAddress - ptNodeOriginAddress; - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, parentOffset); - dictBuffer.position(originalPosition); - } - - /** - * Update parent addresses in a node array stored at ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to be modified. - * @param ptNodeOriginAddress the address of the node array to update. - * @param newParentAddress the address to be written. - * @param formatOptions file format options. - */ - private static void updateParentAddresses(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newParentAddress, - final FormatOptions formatOptions) { - final int originalPosition = dictUpdater.getPosition(); - dictUpdater.setPosition(ptNodeOriginAddress); - do { - final int count = dictUpdater.readPtNodeCount(); - for (int i = 0; i < count; ++i) { - updateParentAddress(dictUpdater, dictUpdater.getPosition(), newParentAddress, - formatOptions); - dictUpdater.skipPtNode(formatOptions); - } - if (!dictUpdater.readAndFollowForwardLink()) break; - if (dictUpdater.getPosition() == FormatSpec.NO_FORWARD_LINK_ADDRESS) break; - } while (formatOptions.mSupportsDynamicUpdate); - dictUpdater.setPosition(originalPosition); - } - - /** - * Update a children address in a PtNode that is addressed by ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to write. - * @param ptNodeOriginAddress the address of the PtNode. - * @param newChildrenAddress the absolute address of the child. - * @param formatOptions file format options. - */ - private static void updateChildrenAddress(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newChildrenAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - final int originalPosition = dictBuffer.position(); - dictBuffer.position(ptNodeOriginAddress); - final int flags = dictBuffer.readUnsignedByte(); - BinaryDictDecoderUtils.readParentAddress(dictBuffer, formatOptions); - BinaryDictIOUtils.skipString(dictBuffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0); - if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) dictBuffer.readUnsignedByte(); - final int childrenOffset = newChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS - ? FormatSpec.NO_CHILDREN_ADDRESS : newChildrenAddress - dictBuffer.position(); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, childrenOffset); - dictBuffer.position(originalPosition); - } - - /** - * Helper method to move a PtNode to the tail of the file. - */ - private static int movePtNode(final OutputStream destination, - final Ver3DictUpdater dictUpdater, final PtNodeInfo info, - final int nodeArrayOriginAddress, final int oldNodeAddress, - final FormatOptions formatOptions) throws IOException { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - updateParentAddress(dictUpdater, oldNodeAddress, dictBuffer.limit() + 1, formatOptions); - dictBuffer.position(oldNodeAddress); - final int currentFlags = dictBuffer.readUnsignedByte(); - dictBuffer.position(oldNodeAddress); - dictBuffer.put((byte)(FormatSpec.FLAG_IS_MOVED | (currentFlags - & (~FormatSpec.MASK_MOVE_AND_DELETE_FLAG)))); - int size = FormatSpec.PTNODE_FLAGS_SIZE; - updateForwardLink(dictUpdater, nodeArrayOriginAddress, dictBuffer.limit(), formatOptions); - size += BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { info }); - return size; - } - - @SuppressWarnings("unused") - private static void updateForwardLink(final Ver3DictUpdater dictUpdater, - final int nodeArrayOriginAddress, final int newNodeArrayAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - dictUpdater.setPosition(nodeArrayOriginAddress); - int jumpCount = 0; - while (jumpCount++ < MAX_JUMPS) { - final int count = dictUpdater.readPtNodeCount(); - for (int i = 0; i < count; ++i) { - dictUpdater.readPtNode(dictUpdater.getPosition(), formatOptions); - } - final int forwardLinkAddress = dictBuffer.readUnsignedInt24(); - if (forwardLinkAddress == FormatSpec.NO_FORWARD_LINK_ADDRESS) { - dictBuffer.position(dictBuffer.position() - FormatSpec.FORWARD_LINK_ADDRESS_SIZE); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeArrayAddress); - return; - } - dictBuffer.position(forwardLinkAddress); - } - if (DBG && jumpCount >= MAX_JUMPS) { - throw new RuntimeException("too many jumps, probably a bug."); - } - } - - /** - * Move a PtNode that is referred to by oldPtNodeOrigin to the tail of the file, and set the - * children address to the byte after the PtNode. - * - * @param fileEndAddress the address of the tail of the file. - * @param codePoints the characters to put inside the PtNode. - * @param length how many code points to read from codePoints. - * @param flags the flags for this PtNode. - * @param frequency the frequency of this terminal. - * @param parentAddress the address of the parent PtNode of this PtNode. - * @param shortcutTargets the shortcut targets for this PtNode. - * @param bigrams the bigrams for this PtNode. - * @param destination the stream representing the tail of the file. - * @param dictUpdater the DictUpdater. - * @param oldPtNodeArrayOrigin the origin of the old PtNode array this PtNode was a part of. - * @param oldPtNodeOrigin the old origin where this PtNode used to be stored. - * @param formatOptions format options for this dictionary. - * @return the size written, in bytes. - * @throws IOException if the file can't be accessed - */ - private static int movePtNode(final int fileEndAddress, final int[] codePoints, - final int length, final int flags, final int frequency, final int parentAddress, - final ArrayList<WeightedString> shortcutTargets, - final ArrayList<PendingAttribute> bigrams, final OutputStream destination, - final Ver3DictUpdater dictUpdater, final int oldPtNodeArrayOrigin, - final int oldPtNodeOrigin, final FormatOptions formatOptions) throws IOException { - int size = 0; - final int newPtNodeOrigin = fileEndAddress + 1; - final int[] writtenCharacters = Arrays.copyOfRange(codePoints, 0, length); - final PtNodeInfo tmpInfo = new PtNodeInfo(newPtNodeOrigin, -1 /* endAddress */, - flags, writtenCharacters, frequency, parentAddress, FormatSpec.NO_CHILDREN_ADDRESS, - shortcutTargets, bigrams); - size = BinaryDictIOUtils.computePtNodeSize(tmpInfo, formatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newPtNodeOrigin, newPtNodeOrigin + size, - flags, writtenCharacters, frequency, parentAddress, - fileEndAddress + 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE, shortcutTargets, - bigrams); - movePtNode(destination, dictUpdater, newInfo, oldPtNodeArrayOrigin, oldPtNodeOrigin, - formatOptions); - return 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE; - } - - /** - * Converts a list of WeightedString to a list of PendingAttribute. - */ - public static ArrayList<PendingAttribute> resolveBigramPositions(final DictUpdater dictUpdater, - final ArrayList<WeightedString> bigramStrings) - throws IOException, UnsupportedFormatException { - if (bigramStrings == null) return CollectionUtils.newArrayList(); - final ArrayList<PendingAttribute> bigrams = CollectionUtils.newArrayList(); - for (final WeightedString bigram : bigramStrings) { - final int pos = dictUpdater.getTerminalPosition(bigram.mWord); - if (pos == FormatSpec.NOT_VALID_WORD) { - // TODO: figure out what is the correct thing to do here. - } else { - bigrams.add(new PendingAttribute(bigram.mFrequency, pos)); - } - } - return bigrams; - } - - /** - * Insert a word into a binary dictionary. - * - * @param dictUpdater the dict updater. - * @param destination a stream to the underlying file, with the pointer at the end of the file. - * @param word the word to insert. - * @param frequency the frequency of the new word. - * @param bigramStrings bigram list, or null if none. - * @param shortcuts shortcut list, or null if none. - * @param isBlackListEntry whether this should be a blacklist entry. - * @throws IOException if the file can't be accessed. - * @throws UnsupportedFormatException if the existing dictionary is in an unexpected format. - */ - // TODO: Support batch insertion. - // TODO: Remove @UsedForTesting once UserHistoryDictionary is implemented by BinaryDictionary. - @UsedForTesting - public static void insertWord(final Ver3DictUpdater dictUpdater, - final OutputStream destination, final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, - final ArrayList<WeightedString> shortcuts, final boolean isNotAWord, - final boolean isBlackListEntry) - throws IOException, UnsupportedFormatException { - final ArrayList<PendingAttribute> bigrams = resolveBigramPositions(dictUpdater, - bigramStrings); - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - - final boolean isTerminal = true; - final boolean hasBigrams = !bigrams.isEmpty(); - final boolean hasShortcuts = shortcuts != null && !shortcuts.isEmpty(); - - // find the insert position of the word. - if (dictBuffer.position() != 0) dictBuffer.position(0); - final FileHeader fileHeader = dictUpdater.readHeader(); - - int wordPos = 0, address = dictBuffer.position(), nodeOriginAddress = dictBuffer.position(); - final int[] codePoints = FusionDictionary.getCodePoints(word); - final int wordLen = codePoints.length; - - for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { - if (wordPos >= wordLen) break; - nodeOriginAddress = dictBuffer.position(); - int nodeParentAddress = -1; - final int ptNodeCount = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer); - boolean foundNextNode = false; - - for (int i = 0; i < ptNodeCount; ++i) { - address = dictBuffer.position(); - final PtNodeInfo currentInfo = dictUpdater.readPtNode(address, - fileHeader.mFormatOptions); - final boolean isMovedNode = BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, - fileHeader.mFormatOptions); - if (isMovedNode) continue; - nodeParentAddress = (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS) - ? FormatSpec.NO_PARENT_ADDRESS : currentInfo.mParentAddress + address; - boolean matched = true; - for (int p = 0; p < currentInfo.mCharacters.length; ++p) { - if (wordPos + p >= wordLen) { - /* - * splitting - * before - * abcd - ef - * - * insert "abc" - * - * after - * abc - d - ef - */ - final int newNodeAddress = dictBuffer.limit(); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1, - isTerminal, 0, hasShortcuts, hasBigrams, false /* isNotAWord */, - false /* isBlackListEntry */, fileHeader.mFormatOptions); - int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p, flags, - frequency, nodeParentAddress, shortcuts, bigrams, destination, - dictUpdater, nodeOriginAddress, address, fileHeader.mFormatOptions); - - final int[] characters2 = Arrays.copyOfRange(currentInfo.mCharacters, p, - currentInfo.mCharacters.length); - if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - updateParentAddresses(dictUpdater, currentInfo.mChildrenAddress, - newNodeAddress + written + 1, fileHeader.mFormatOptions); - } - final PtNodeInfo newInfo2 = new PtNodeInfo( - newNodeAddress + written + 1, -1 /* endAddress */, - currentInfo.mFlags, characters2, currentInfo.mFrequency, - newNodeAddress + 1, currentInfo.mChildrenAddress, - currentInfo.mShortcutTargets, currentInfo.mBigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo2 }); - return; - } else if (codePoints[wordPos + p] != currentInfo.mCharacters[p]) { - if (p > 0) { - /* - * splitting - * before - * ab - cd - * - * insert "ac" - * - * after - * a - b - cd - * | - * - c - */ - - final int newNodeAddress = dictBuffer.limit(); - final int childrenAddress = currentInfo.mChildrenAddress; - - // move prefix - final int prefixFlags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1, - false /* isTerminal */, 0 /* childrenAddressSize*/, - false /* hasShortcut */, false /* hasBigrams */, - false /* isNotAWord */, false /* isBlackListEntry */, - fileHeader.mFormatOptions); - int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p, - prefixFlags, -1 /* frequency */, nodeParentAddress, null, null, - destination, dictUpdater, nodeOriginAddress, address, - fileHeader.mFormatOptions); - - final int[] suffixCharacters = Arrays.copyOfRange( - currentInfo.mCharacters, p, currentInfo.mCharacters.length); - if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - updateParentAddresses(dictUpdater, currentInfo.mChildrenAddress, - newNodeAddress + written + 1, fileHeader.mFormatOptions); - } - final int suffixFlags = BinaryDictEncoderUtils.makePtNodeFlags( - suffixCharacters.length > 1, - (currentInfo.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0, - 0 /* childrenAddressSize */, - (currentInfo.mFlags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS) - != 0, - (currentInfo.mFlags & FormatSpec.FLAG_HAS_BIGRAMS) != 0, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo suffixInfo = new PtNodeInfo( - newNodeAddress + written + 1, -1 /* endAddress */, suffixFlags, - suffixCharacters, currentInfo.mFrequency, newNodeAddress + 1, - currentInfo.mChildrenAddress, currentInfo.mShortcutTargets, - currentInfo.mBigrams); - written += BinaryDictIOUtils.computePtNodeSize(suffixInfo, - fileHeader.mFormatOptions) + 1; - - final int[] newCharacters = Arrays.copyOfRange(codePoints, wordPos + p, - codePoints.length); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags( - newCharacters.length > 1, isTerminal, - 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo( - newNodeAddress + written, -1 /* endAddress */, flags, - newCharacters, frequency, newNodeAddress + 1, - FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, - new PtNodeInfo[] { suffixInfo, newInfo }); - return; - } - matched = false; - break; - } - } - - if (matched) { - if (wordPos + currentInfo.mCharacters.length == wordLen) { - // the word exists in the dictionary. - // only update the PtNode. - final int newNodeAddress = dictBuffer.limit(); - final boolean hasMultipleChars = currentInfo.mCharacters.length > 1; - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1, - -1 /* endAddress */, flags, currentInfo.mCharacters, frequency, - nodeParentAddress, currentInfo.mChildrenAddress, shortcuts, - bigrams); - movePtNode(destination, dictUpdater, newInfo, nodeOriginAddress, address, - fileHeader.mFormatOptions); - return; - } - wordPos += currentInfo.mCharacters.length; - if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { - /* - * found the prefix of the word. - * make new PtNode and link to the PtNode from this PtNode. - * - * before - * ab - cd - * - * insert "abcde" - * - * after - * ab - cd - e - */ - final int newNodeArrayAddress = dictBuffer.limit(); - updateChildrenAddress(dictUpdater, address, newNodeArrayAddress, - fileHeader.mFormatOptions); - final int newNodeAddress = newNodeArrayAddress + 1; - final boolean hasMultipleChars = (wordLen - wordPos) > 1; - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress, -1, flags, - characters, frequency, address, FormatSpec.NO_CHILDREN_ADDRESS, - shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo }); - return; - } - dictBuffer.position(currentInfo.mChildrenAddress); - foundNextNode = true; - break; - } - } - - if (foundNextNode) continue; - - // reached the end of the array. - final int linkAddressPosition = dictBuffer.position(); - int nextLink = dictBuffer.readUnsignedInt24(); - if ((nextLink & FormatSpec.MSB24) != 0) { - nextLink = -(nextLink & FormatSpec.SINT24_MAX); - } - if (nextLink == FormatSpec.NO_FORWARD_LINK_ADDRESS) { - /* - * expand this node. - * - * before - * ab - cd - * - * insert "abef" - * - * after - * ab - cd - * | - * - ef - */ - - // change the forward link address. - final int newNodeAddress = dictBuffer.limit(); - dictBuffer.position(linkAddressPosition); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeAddress); - - final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(characters.length > 1, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1, - -1 /* endAddress */, flags, characters, frequency, nodeParentAddress, - FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[]{ newInfo }); - return; - } else { - depth--; - dictBuffer.position(nextLink); - } - } - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index b56234f6d..f25503488 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -18,10 +18,9 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; -import java.io.File; +import java.util.Date; +import java.util.HashMap; /** * Dictionary File Format Specification. @@ -40,12 +39,8 @@ public final class FormatSpec { * p | not used 3 bits * t | each unigram and bigram entry has a time stamp? * i | 1 bit, 1 = yes, 0 = no : CONTAINS_TIMESTAMP_FLAG - * o | has bigrams ? 1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG - * n | FRENCH_LIGATURE_PROCESSING_FLAG - * f | supports dynamic updates ? 1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE - * l | GERMAN_UMLAUT_PROCESSING_FLAG - * a | - * gs + * o | + * nflags * * h | * e | size of the file header, 4bytes @@ -82,45 +77,36 @@ public final class FormatSpec { * s * * f | - * o | IF SUPPORTS_DYNAMIC_UPDATE (defined in the file header) - * r | forward link address, 3byte - * w | 1 byte = bbbbbbbb match - * a | case 1xxxxxxx => -((xxxxxxx << 16) + (next byte << 8) + next byte) - * r | otherwise => (xxxxxxx << 16) + (next byte << 8) + next byte - * d | - * linkaddress + * o | forward link address, 3byte + * r | 1 byte = bbbbbbbb match + * w | case 1xxxxxxx => -((xxxxxxx << 16) + (next byte << 8) + next byte) + * a | otherwise => (xxxxxxx << 16) + (next byte << 8) + next byte + * r | + * dlinkaddress */ /* Node (FusionDictionary.PtNode) layout is as follows: - * | IF !SUPPORTS_DYNAMIC_UPDATE - * | addressType xx : mask with MASK_CHILDREN_ADDRESS_TYPE - * | 2 bits, 00 = no children : FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS - * f | 01 = 1 byte : FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE - * l | 10 = 2 bytes : FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES - * a | 11 = 3 bytes : FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES - * g | ELSE - * s | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED - * | This must be the same as FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES - * | 01 = yes : FLAG_IS_MOVED - * | the new address is stored in the same place as the parent address - * | is deleted? 10 = yes : FLAG_IS_DELETED - * | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS - * | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL - * | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS + * | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED + * | This must be the same as FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES + * | 01 = yes : FLAG_IS_MOVED + * f | the new address is stored in the same place as the parent address + * l | is deleted? 10 = yes : FLAG_IS_DELETED + * a | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS + * g | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL + * s | 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 not a word ? 1 bit, 1 = yes, 0 = no : FLAG_IS_NOT_A_WORD * | is blacklisted ? 1 bit, 1 = yes, 0 = no : FLAG_IS_BLACKLISTED * * p | - * a | IF SUPPORTS_DYNAMIC_UPDATE (defined in the file header) - * r | parent address, 3byte - * e | 1 byte = bbbbbbbb match - * n | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) - * t | otherwise => (bbbbbbbb << 16) + (next byte << 8) + next byte - * a | This address is relative to the head of the PtNode. - * d | If the node doesn't have a parent, this field is set to 0. + * a | parent address, 3byte + * r | 1 byte = bbbbbbbb match + * e | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) + * n | otherwise => (bbbbbbbb << 16) + (next byte << 8) + next byte + * t | This address is relative to the head of the PtNode. + * a | If the node doesn't have a parent, this field is set to 0. * d | - * ress + * dress * * c | IF FLAG_HAS_MULTIPLE_CHARS * h | char, char, char, char n * (1 or 3 bytes) : use PtNodeInfo for i/o helpers @@ -134,23 +120,16 @@ public final class FormatSpec { * e | frequency 1 byte * q | * - * c | IF SUPPORTS_DYNAMIC_UPDATE - * h | children address, 3 bytes - * i | 1 byte = bbbbbbbb match - * l | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) - * d | otherwise => (bbbbbbbb<<16) + (next byte << 8) + next byte - * r | if this node doesn't have children, this field is set to 0. - * e | (see BinaryDictEncoderUtils#writeVariableSignedAddress) - * n | ELSIF 00 = FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS == addressType - * a | // nothing - * d | ELSIF 01 = FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE == addressType - * d | children address, 1 byte - * r | ELSIF 10 = FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES == addressType - * e | children address, 2 bytes - * s | ELSE // 11 = FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES = addressType - * s | children address, 3 bytes - * | END - * | This address is relative to the position of this field. + * c | + * h | children address, 3 bytes + * i | 1 byte = bbbbbbbb match + * l | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) + * d | otherwise => (bbbbbbbb<<16) + (next byte << 8) + next byte + * r | if this node doesn't have children, this field is set to 0. + * e | (see BinaryDictEncoderUtils#writeVariableSignedAddress) + * n | This address is relative to the position of this field. + * a | + * ddress * * | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS * | shortcut string list @@ -199,21 +178,18 @@ public final class FormatSpec { */ public static final int MAGIC_NUMBER = 0x9BC13AFE; - static final int MINIMUM_SUPPORTED_VERSION = 2; - static final int MAXIMUM_SUPPORTED_VERSION = 4; static final int NOT_A_VERSION_NUMBER = -1; static final int FIRST_VERSION_WITH_DYNAMIC_UPDATE = 3; static final int FIRST_VERSION_WITH_TERMINAL_ID = 4; - static final int VERSION3 = 3; - static final int VERSION4 = 4; - // These options need to be the same numeric values as the one in the native reading code. - static final int GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; - // TODO: Make the native reading code read this variable. - static final int SUPPORTS_DYNAMIC_UPDATE = 0x2; - static final int FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; - static final int CONTAINS_BIGRAMS_FLAG = 0x8; - static final int CONTAINS_TIMESTAMP_FLAG = 0x10; + // These MUST have the same values as the relevant constants in format_utils.h. + // From version 4 on, we use version * 100 + revision as a version number. That allows + // us to change the format during development while having testing devices remove + // older files with each upgrade, while still having a readable versioning scheme. + public static final int VERSION2 = 2; + public static final int VERSION4 = 401; + static final int MINIMUM_SUPPORTED_VERSION = VERSION2; + static final int MAXIMUM_SUPPORTED_VERSION = VERSION4; // TODO: Make this value adaptative to content data, store it in the header, and // use it in the reading code. @@ -263,29 +239,31 @@ public final class FormatSpec { static final int PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE = 3; static final int PTNODE_SHORTCUT_LIST_SIZE_SIZE = 2; - // These values are used only by version 4 or later. + // These values are used only by version 4 or later. They MUST match the definitions in + // ver4_dict_constants.cpp. static final String TRIE_FILE_EXTENSION = ".trie"; + public static final String HEADER_FILE_EXTENSION = ".header"; static final String FREQ_FILE_EXTENSION = ".freq"; - static final String UNIGRAM_TIMESTAMP_FILE_EXTENSION = ".timestamp"; // tat = Terminal Address Table static final String TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat"; static final String BIGRAM_FILE_EXTENSION = ".bigram"; static final String SHORTCUT_FILE_EXTENSION = ".shortcut"; static final String LOOKUP_TABLE_FILE_SUFFIX = "_lookup"; static final String CONTENT_TABLE_FILE_SUFFIX = "_index"; + static final int FLAGS_IN_FREQ_FILE_SIZE = 1; static final int FREQUENCY_AND_FLAGS_SIZE = 2; static final int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3; static final int UNIGRAM_TIMESTAMP_SIZE = 4; + static final int UNIGRAM_COUNTER_SIZE = 1; + static final int UNIGRAM_LEVEL_SIZE = 1; // With the English main dictionary as of October 2013, the size of bigram address table is - // is 584KB with the block size being 4. - // This is 91% of that of full address table. - static final int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 4; - static final int BIGRAM_CONTENT_COUNT = 2; + // is 345KB with the block size being 16. + // This is 54% of that of full address table. + static final int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 16; + static final int BIGRAM_CONTENT_COUNT = 1; static final int BIGRAM_FREQ_CONTENT_INDEX = 0; - static final int BIGRAM_TIMESTAMP_CONTENT_INDEX = 1; static final String BIGRAM_FREQ_CONTENT_ID = "_freq"; - static final String BIGRAM_TIMESTAMP_CONTENT_ID = "_timestamp"; static final int BIGRAM_TIMESTAMP_SIZE = 4; static final int BIGRAM_COUNTER_SIZE = 1; static final int BIGRAM_LEVEL_SIZE = 1; @@ -293,7 +271,7 @@ public final class FormatSpec { static final int SHORTCUT_CONTENT_COUNT = 1; static final int SHORTCUT_CONTENT_INDEX = 0; // With the English main dictionary as of October 2013, the size of shortcut address table is - // 29KB with the block size being 64. + // 26KB with the block size being 64. // This is only 4.4% of that of full address table. static final int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64; static final String SHORTCUT_CONTENT_ID = "_shortcut"; @@ -331,107 +309,56 @@ public final class FormatSpec { */ public static final class FormatOptions { public final int mVersion; - public final boolean mSupportsDynamicUpdate; - public final boolean mHasTerminalId; public final boolean mHasTimestamp; - @UsedForTesting - public FormatOptions(final int version) { - this(version, false); - } @UsedForTesting - public FormatOptions(final int version, final boolean supportsDynamicUpdate) { - this(version, supportsDynamicUpdate, false /* hasTimestamp */); + public FormatOptions(final int version) { + this(version, false /* hasTimestamp */); } - public FormatOptions(final int version, final boolean supportsDynamicUpdate, - final boolean hasTimestamp) { + public FormatOptions(final int version, final boolean hasTimestamp) { mVersion = version; - if (version < FIRST_VERSION_WITH_DYNAMIC_UPDATE && supportsDynamicUpdate) { - throw new RuntimeException("Dynamic updates are only supported with versions " - + FIRST_VERSION_WITH_DYNAMIC_UPDATE + " and ulterior."); - } - mSupportsDynamicUpdate = supportsDynamicUpdate; - mHasTerminalId = (version >= FIRST_VERSION_WITH_TERMINAL_ID); mHasTimestamp = hasTimestamp; } } /** - * Class representing file header. + * Options global to the dictionary. */ - public static final class FileHeader { - public final int mHeaderSize; - public final DictionaryOptions mDictionaryOptions; - public final FormatOptions mFormatOptions; - // Note that these are corresponding definitions in native code in latinime::HeaderPolicy - // and latinime::HeaderReadWriteUtils. - public static final String SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE = "SUPPORTS_DYNAMIC_UPDATE"; - public static final String USES_FORGETTING_CURVE_ATTRIBUTE = "USES_FORGETTING_CURVE"; - public static final String ATTRIBUTE_VALUE_TRUE = "1"; - - public static final String DICTIONARY_VERSION_ATTRIBUTE = "version"; - public static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale"; - public static final String DICTIONARY_ID_ATTRIBUTE = "dictionary"; - private static final String DICTIONARY_DESCRIPTION_ATTRIBUTE = "description"; - public FileHeader(final int headerSize, final DictionaryOptions dictionaryOptions, - final FormatOptions formatOptions) { - mHeaderSize = headerSize; - mDictionaryOptions = dictionaryOptions; - mFormatOptions = formatOptions; - } - - // Helper method to get the locale as a String - public String getLocaleString() { - return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_LOCALE_ATTRIBUTE); - } - - // Helper method to get the version String - public String getVersion() { - return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_VERSION_ATTRIBUTE); + public static final class DictionaryOptions { + public final HashMap<String, String> mAttributes; + public DictionaryOptions(final HashMap<String, String> attributes) { + mAttributes = attributes; } - - // Helper method to get the dictionary ID as a String - public String getId() { - return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_ID_ATTRIBUTE); - } - - // Helper method to get the description - public String getDescription() { - // TODO: Right now each dictionary file comes with a description in its own language. - // It will display as is no matter the device's locale. It should be internationalized. - return mDictionaryOptions.mAttributes.get(FileHeader.DICTIONARY_DESCRIPTION_ATTRIBUTE); + @Override + public String toString() { // Convenience method + return toString(0, false); } - } - - /** - * Returns new dictionary decoder. - * - * @param dictFile the dictionary file. - * @param bufferType The type of buffer, as one of USE_* in DictDecoder. - * @return new dictionary decoder if the dictionary file exists, otherwise null. - */ - public static DictDecoder getDictDecoder(final File dictFile, final int bufferType) { - if (dictFile.isDirectory()) { - return new Ver4DictDecoder(dictFile, bufferType); - } else if (dictFile.isFile()) { - return new Ver3DictDecoder(dictFile, bufferType); - } - return null; - } - - public static DictDecoder getDictDecoder(final File dictFile, - final DictionaryBufferFactory factory) { - if (dictFile.isDirectory()) { - return new Ver4DictDecoder(dictFile, factory); - } else if (dictFile.isFile()) { - return new Ver3DictDecoder(dictFile, factory); + public String toString(final int indentCount, final boolean plumbing) { + final StringBuilder indent = new StringBuilder(); + if (plumbing) { + indent.append("H:"); + } else { + for (int i = 0; i < indentCount; ++i) { + indent.append(" "); + } + } + final StringBuilder s = new StringBuilder(); + for (final String optionKey : mAttributes.keySet()) { + s.append(indent); + s.append(optionKey); + s.append(" = "); + if ("date".equals(optionKey) && !plumbing) { + // Date needs a number of milliseconds, but the dictionary contains seconds + s.append(new Date( + 1000 * Long.parseLong(mAttributes.get(optionKey))).toString()); + } else { + s.append(mAttributes.get(optionKey)); + } + s.append("\n"); + } + return s.toString(); } - return null; - } - - public static DictDecoder getDictDecoder(final File dictFile) { - return getDictDecoder(dictFile, DictDecoder.USE_READONLY_BYTEBUFFER); } private FormatSpec() { diff --git a/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java b/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java deleted file mode 100644 index cf07209d9..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/MakedictLog.java +++ /dev/null @@ -1,47 +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.latin.makedict; - -import android.util.Log; - -/** - * Wrapper to redirect log events to the right output medium. - */ -public final class MakedictLog { - public static final boolean DBG = false; - private static final String TAG = MakedictLog.class.getSimpleName(); - - public static void d(String message) { - if (DBG) { - Log.d(TAG, message); - } - } - - public static void i(String message) { - if (DBG) { - Log.i(TAG, message); - } - } - - public static void w(String message) { - Log.w(TAG, message); - } - - public static void e(String message) { - Log.e(TAG, message); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/ProbabilityInfo.java b/java/src/com/android/inputmethod/latin/makedict/ProbabilityInfo.java new file mode 100644 index 000000000..5fcbb6357 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/ProbabilityInfo.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.utils.CombinedFormatUtils; + +import java.util.Arrays; + +public final class ProbabilityInfo { + public final int mProbability; + // mTimestamp, mLevel and mCount are historical info. These values are depend on the + // implementation in native code; thus, we must not use them and have any assumptions about + // them except for tests. + public final int mTimestamp; + public final int mLevel; + public final int mCount; + + @UsedForTesting + public static ProbabilityInfo max(final ProbabilityInfo probabilityInfo1, + final ProbabilityInfo probabilityInfo2) { + if (probabilityInfo1 == null) { + return probabilityInfo2; + } + if (probabilityInfo2 == null) { + return probabilityInfo1; + } + if (probabilityInfo1.mProbability > probabilityInfo2.mProbability) { + return probabilityInfo1; + } else { + return probabilityInfo2; + } + } + + public ProbabilityInfo(final int probability) { + this(probability, BinaryDictionary.NOT_A_VALID_TIMESTAMP, 0, 0); + } + + public ProbabilityInfo(final int probability, final int timestamp, final int level, + final int count) { + mProbability = probability; + mTimestamp = timestamp; + mLevel = level; + mCount = count; + } + + public boolean hasHistoricalInfo() { + return mTimestamp != BinaryDictionary.NOT_A_VALID_TIMESTAMP; + } + + @Override + public int hashCode() { + if (hasHistoricalInfo()) { + return Arrays.hashCode(new Object[] { mProbability, mTimestamp, mLevel, mCount }); + } else { + return Arrays.hashCode(new Object[] { mProbability }); + } + } + + @Override + public String toString() { + return CombinedFormatUtils.formatProbabilityInfo(this); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof ProbabilityInfo)) return false; + final ProbabilityInfo p = (ProbabilityInfo)o; + if (!hasHistoricalInfo() && !p.hasHistoricalInfo()) { + return mProbability == p.mProbability; + } + return mProbability == p.mProbability && mTimestamp == p.mTimestamp && mLevel == p.mLevel + && mCount == p.mCount; + } +}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/makedict/SparseTable.java b/java/src/com/android/inputmethod/latin/makedict/SparseTable.java deleted file mode 100644 index 7592a0c13..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/SparseTable.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; - -/** - * SparseTable is an extensible map from integer to integer. - * This holds one value for every mBlockSize keys, so it uses 1/mBlockSize'th of the full index - * memory. - */ -@UsedForTesting -public class SparseTable { - - /** - * mLookupTable is indexed by terminal ID, containing exactly one entry for every mBlockSize - * terminals. - * It contains at index i = j / mBlockSize the index in each ArrayList in mContentsTables where - * the values for terminals with IDs j to j + mBlockSize - 1 are stored as an mBlockSize-sized - * integer array. - */ - private final ArrayList<Integer> mLookupTable; - private final ArrayList<ArrayList<Integer>> mContentTables; - - private final int mBlockSize; - private final int mContentTableCount; - public static final int NOT_EXIST = -1; - public static final int SIZE_OF_INT_IN_BYTES = 4; - - @UsedForTesting - public SparseTable(final int initialCapacity, final int blockSize, - final int contentTableCount) { - mBlockSize = blockSize; - final int lookupTableSize = initialCapacity / mBlockSize - + (initialCapacity % mBlockSize > 0 ? 1 : 0); - mLookupTable = new ArrayList<Integer>(Collections.nCopies(lookupTableSize, NOT_EXIST)); - mContentTableCount = contentTableCount; - mContentTables = CollectionUtils.newArrayList(); - for (int i = 0; i < mContentTableCount; ++i) { - mContentTables.add(new ArrayList<Integer>()); - } - } - - @UsedForTesting - public SparseTable(final ArrayList<Integer> lookupTable, - final ArrayList<ArrayList<Integer>> contentTables, final int blockSize) { - mBlockSize = blockSize; - mContentTableCount = contentTables.size(); - mLookupTable = lookupTable; - mContentTables = contentTables; - } - - /** - * Converts an byte array to an int array considering each set of 4 bytes is an int stored in - * big-endian. - * The length of byteArray must be a multiple of four. - * Otherwise, IndexOutOfBoundsException will be raised. - */ - @UsedForTesting - private static ArrayList<Integer> convertByteArrayToIntegerArray(final byte[] byteArray) { - final ArrayList<Integer> integerArray = new ArrayList<Integer>(byteArray.length / 4); - for (int i = 0; i < byteArray.length; i += 4) { - int value = 0; - for (int j = i; j < i + 4; ++j) { - value <<= 8; - value |= byteArray[j] & 0xFF; - } - integerArray.add(value); - } - return integerArray; - } - - @UsedForTesting - public int get(final int contentTableIndex, final int index) { - if (!contains(index)) { - return NOT_EXIST; - } - return mContentTables.get(contentTableIndex).get( - mLookupTable.get(index / mBlockSize) + (index % mBlockSize)); - } - - @UsedForTesting - public ArrayList<Integer> getAll(final int index) { - final ArrayList<Integer> ret = CollectionUtils.newArrayList(); - for (int i = 0; i < mContentTableCount; ++i) { - ret.add(get(i, index)); - } - return ret; - } - - @UsedForTesting - public void set(final int contentTableIndex, final int index, final int value) { - if (mLookupTable.get(index / mBlockSize) == NOT_EXIST) { - mLookupTable.set(index / mBlockSize, mContentTables.get(contentTableIndex).size()); - for (int i = 0; i < mContentTableCount; ++i) { - for (int j = 0; j < mBlockSize; ++j) { - mContentTables.get(i).add(NOT_EXIST); - } - } - } - mContentTables.get(contentTableIndex).set( - mLookupTable.get(index / mBlockSize) + (index % mBlockSize), value); - } - - public void remove(final int indexOfContent, final int index) { - set(indexOfContent, index, NOT_EXIST); - } - - @UsedForTesting - public int size() { - return mLookupTable.size() * mBlockSize; - } - - @UsedForTesting - /* package */ int getContentTableSize() { - // This class always has at least one content table. - return mContentTables.get(0).size(); - } - - @UsedForTesting - /* package */ int getLookupTableSize() { - return mLookupTable.size(); - } - - public boolean contains(final int index) { - if (index < 0 || index / mBlockSize >= mLookupTable.size() - || mLookupTable.get(index / mBlockSize) == NOT_EXIST) { - return false; - } - return true; - } - - @UsedForTesting - public void write(final OutputStream lookupOutStream, final OutputStream[] contentOutStreams) - throws IOException { - if (contentOutStreams.length != mContentTableCount) { - throw new RuntimeException(contentOutStreams.length + " streams are given, but the" - + " table has " + mContentTableCount + " content tables."); - } - for (final int index : mLookupTable) { - BinaryDictEncoderUtils.writeUIntToStream(lookupOutStream, index, SIZE_OF_INT_IN_BYTES); - } - - for (int i = 0; i < contentOutStreams.length; ++i) { - for (final int data : mContentTables.get(i)) { - BinaryDictEncoderUtils.writeUIntToStream(contentOutStreams[i], data, - SIZE_OF_INT_IN_BYTES); - } - } - } - - @UsedForTesting - public void writeToFiles(final File lookupTableFile, final File[] contentFiles) - throws IOException { - FileOutputStream lookupTableOutStream = null; - final FileOutputStream[] contentTableOutStreams = new FileOutputStream[mContentTableCount]; - try { - lookupTableOutStream = new FileOutputStream(lookupTableFile); - for (int i = 0; i < contentFiles.length; ++i) { - contentTableOutStreams[i] = new FileOutputStream(contentFiles[i]); - } - write(lookupTableOutStream, contentTableOutStreams); - } finally { - if (lookupTableOutStream != null) { - lookupTableOutStream.close(); - } - for (int i = 0; i < contentTableOutStreams.length; ++i) { - if (contentTableOutStreams[i] != null) { - contentTableOutStreams[i].close(); - } - } - } - } - - private static byte[] readFileToByteArray(final File file) throws IOException { - final byte[] contents = new byte[(int) file.length()]; - FileInputStream inStream = null; - try { - inStream = new FileInputStream(file); - inStream.read(contents); - } finally { - if (inStream != null) { - inStream.close(); - } - } - return contents; - } - - @UsedForTesting - public static SparseTable readFromFiles(final File lookupTableFile, final File[] contentFiles, - final int blockSize) throws IOException { - final ArrayList<ArrayList<Integer>> contentTables = - new ArrayList<ArrayList<Integer>>(contentFiles.length); - for (int i = 0; i < contentFiles.length; ++i) { - contentTables.add(convertByteArrayToIntegerArray(readFileToByteArray(contentFiles[i]))); - } - return new SparseTable(convertByteArrayToIntegerArray(readFileToByteArray(lookupTableFile)), - contentTables, blockSize); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java deleted file mode 100644 index acab4f8a5..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.JniUtils; - -import android.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * An implementation of DictDecoder for version 3 binary dictionary. - */ -@UsedForTesting -public class Ver3DictDecoder extends AbstractDictDecoder { - private static final String TAG = Ver3DictDecoder.class.getSimpleName(); - - static { - JniUtils.loadNativeLibrary(); - } - - // TODO: implement something sensical instead of just a phony method - private static native int doNothing(); - - protected static class PtNodeReader extends AbstractDictDecoder.PtNodeReader { - private static int readFrequency(final DictBuffer dictBuffer) { - return dictBuffer.readUnsignedByte(); - } - } - - protected final File mDictionaryBinaryFile; - private final DictionaryBufferFactory mBufferFactory; - protected DictBuffer mDictBuffer; - - /* package */ Ver3DictDecoder(final File file, final int factoryFlag) { - mDictionaryBinaryFile = file; - mDictBuffer = null; - - if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) { - mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); - } else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) { - mBufferFactory = new DictionaryBufferFromByteArrayFactory(); - } else if ((factoryFlag & MASK_DICTBUFFER) == USE_WRITABLE_BYTEBUFFER) { - mBufferFactory = new DictionaryBufferFromWritableByteBufferFactory(); - } else { - mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); - } - } - - /* package */ Ver3DictDecoder(final File file, final DictionaryBufferFactory factory) { - mDictionaryBinaryFile = file; - mBufferFactory = factory; - } - - @Override - public void openDictBuffer() throws FileNotFoundException, IOException { - mDictBuffer = mBufferFactory.getDictionaryBuffer(mDictionaryBinaryFile); - } - - @Override - public boolean isDictBufferOpen() { - return mDictBuffer != null; - } - - /* package */ DictBuffer getDictBuffer() { - return mDictBuffer; - } - - @UsedForTesting - /* package */ DictBuffer openAndGetDictBuffer() throws FileNotFoundException, IOException { - openDictBuffer(); - return getDictBuffer(); - } - - @Override - public FileHeader readHeader() throws IOException, UnsupportedFormatException { - if (mDictBuffer == null) { - openDictBuffer(); - } - final FileHeader header = super.readHeader(mDictBuffer); - final int version = header.mFormatOptions.mVersion; - if (!(version >= 2 && version <= 3)) { - throw new UnsupportedFormatException("File header has a wrong version : " + version); - } - return header; - } - - // TODO: Make this buffer multi thread safe. - private final int[] mCharacterBuffer = new int[FormatSpec.MAX_WORD_LENGTH]; - @Override - public PtNodeInfo readPtNode(final int ptNodePos, final FormatOptions options) { - int addressPointer = ptNodePos; - final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); - addressPointer += FormatSpec.PTNODE_FLAGS_SIZE; - - final int parentAddress = PtNodeReader.readParentAddress(mDictBuffer, options); - if (BinaryDictIOUtils.supportsDynamicUpdate(options)) { - addressPointer += FormatSpec.PARENT_ADDRESS_SIZE; - } - - final int characters[]; - if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) { - int index = 0; - int character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - while (FormatSpec.INVALID_CHARACTER != character) { - // FusionDictionary is making sure that the length of the word is smaller than - // MAX_WORD_LENGTH. - // So we'll never write past the end of mCharacterBuffer. - mCharacterBuffer[index++] = character; - character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - } - characters = Arrays.copyOfRange(mCharacterBuffer, 0, index); - } else { - final int character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - characters = new int[] { character }; - } - final int frequency; - if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) { - frequency = PtNodeReader.readFrequency(mDictBuffer); - addressPointer += FormatSpec.PTNODE_FREQUENCY_SIZE; - } else { - frequency = PtNode.NOT_A_TERMINAL; - } - int childrenAddress = PtNodeReader.readChildrenAddress(mDictBuffer, flags, options); - if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - childrenAddress += addressPointer; - } - addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options); - final ArrayList<WeightedString> shortcutTargets; - if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) { - // readShortcut will add shortcuts to shortcutTargets. - shortcutTargets = new ArrayList<WeightedString>(); - addressPointer += PtNodeReader.readShortcut(mDictBuffer, shortcutTargets); - } else { - shortcutTargets = null; - } - - final ArrayList<PendingAttribute> bigrams; - if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) { - bigrams = new ArrayList<PendingAttribute>(); - addressPointer += PtNodeReader.readBigramAddresses(mDictBuffer, bigrams, - addressPointer); - if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - throw new RuntimeException("Too many bigrams in a PtNode (" + bigrams.size() - + " but max is " + FormatSpec.MAX_BIGRAMS_IN_A_PTNODE + ")"); - } - } else { - bigrams = null; - } - return new PtNodeInfo(ptNodePos, addressPointer, flags, characters, frequency, - parentAddress, childrenAddress, shortcutTargets, bigrams); - } - - @Override - public FusionDictionary readDictionaryBinary(final FusionDictionary dict, - final boolean deleteDictIfBroken) - throws FileNotFoundException, IOException, UnsupportedFormatException { - if (mDictBuffer == null) { - openDictBuffer(); - } - try { - return BinaryDictDecoderUtils.readDictionaryBinary(this, dict); - } catch (IOException e) { - Log.e(TAG, "The dictionary " + mDictionaryBinaryFile.getName() + " is broken.", e); - if (deleteDictIfBroken && !mDictionaryBinaryFile.delete()) { - Log.e(TAG, "Failed to delete the broken dictionary."); - } - throw e; - } catch (UnsupportedFormatException e) { - Log.e(TAG, "The dictionary " + mDictionaryBinaryFile.getName() + " is broken.", e); - if (deleteDictIfBroken && !mDictionaryBinaryFile.delete()) { - Log.e(TAG, "Failed to delete the broken dictionary."); - } - throw e; - } - } - - @Override - public void setPosition(int newPos) { - mDictBuffer.position(newPos); - } - - @Override - public int getPosition() { - return mDictBuffer.position(); - } - - @Override - public int readPtNodeCount() { - return BinaryDictDecoderUtils.readPtNodeCount(mDictBuffer); - } - - @Override - public boolean readAndFollowForwardLink() { - final int nextAddress = mDictBuffer.readUnsignedInt24(); - if (nextAddress >= 0 && nextAddress < mDictBuffer.limit()) { - mDictBuffer.position(nextAddress); - return true; - } - return false; - } - - @Override - public boolean hasNextPtNodeArray() { - return mDictBuffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS; - } - - @Override - public void skipPtNode(final FormatOptions formatOptions) { - final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); - PtNodeReader.readParentAddress(mDictBuffer, formatOptions); - BinaryDictIOUtils.skipString(mDictBuffer, - (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0); - PtNodeReader.readChildrenAddress(mDictBuffer, flags, formatOptions); - if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) PtNodeReader.readFrequency(mDictBuffer); - if ((flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS) != 0) { - final int shortcutsSize = mDictBuffer.readUnsignedShort(); - mDictBuffer.position(mDictBuffer.position() + shortcutsSize - - FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE); - } - if ((flags & FormatSpec.FLAG_HAS_BIGRAMS) != 0) { - int bigramCount = 0; - while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - final int bigramFlags = mDictBuffer.readUnsignedByte(); - switch (bigramFlags & FormatSpec.MASK_BIGRAM_ATTR_ADDRESS_TYPE) { - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE: - mDictBuffer.readUnsignedByte(); - break; - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES: - mDictBuffer.readUnsignedShort(); - break; - case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES: - mDictBuffer.readUnsignedInt24(); - break; - } - if ((bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT) == 0) break; - } - if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - throw new RuntimeException("Too many bigrams in a PtNode."); - } - } - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java deleted file mode 100644 index 07adda625..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; - -/** - * An implementation of DictUpdater for version 3 binary dictionary. - */ -@UsedForTesting -public class Ver3DictUpdater extends Ver3DictDecoder implements DictUpdater { - private OutputStream mOutStream; - - @UsedForTesting - public Ver3DictUpdater(final File dictFile, final int factoryType) { - // DictUpdater must have an updatable DictBuffer. - super(dictFile, ((factoryType & MASK_DICTBUFFER) == USE_BYTEARRAY) - ? USE_BYTEARRAY : USE_WRITABLE_BYTEBUFFER); - mOutStream = null; - } - - private void openStreamAndBuffer() throws FileNotFoundException, IOException { - super.openDictBuffer(); - mOutStream = new FileOutputStream(mDictionaryBinaryFile, true /* append */); - } - - private void close() throws IOException { - if (mOutStream != null) { - mOutStream.close(); - mOutStream = null; - } - } - - @Override @UsedForTesting - public void deleteWord(final String word) throws IOException, UnsupportedFormatException { - if (mOutStream == null) openStreamAndBuffer(); - mDictBuffer.position(0); - readHeader(); - final int wordPos = getTerminalPosition(word); - if (wordPos != FormatSpec.NOT_VALID_WORD) { - mDictBuffer.position(wordPos); - final int flags = mDictBuffer.readUnsignedByte(); - mDictBuffer.position(wordPos); - mDictBuffer.put((byte) DynamicBinaryDictIOUtils.markAsDeleted(flags)); - } - close(); - } - - @Override @UsedForTesting - public void insertWord(final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, - final ArrayList<WeightedString> shortcuts, - final boolean isNotAWord, final boolean isBlackListEntry) - throws IOException, UnsupportedFormatException { - if (mOutStream == null) openStreamAndBuffer(); - DynamicBinaryDictIOUtils.insertWord(this, mOutStream, word, frequency, bigramStrings, - shortcuts, isNotAWord, isBlackListEntry); - close(); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java deleted file mode 100644 index 734223ec2..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import android.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * An implementation of binary dictionary decoder for version 4 binary dictionary. - */ -@UsedForTesting -public class Ver4DictDecoder extends AbstractDictDecoder { - private static final String TAG = Ver4DictDecoder.class.getSimpleName(); - - private static final int FILETYPE_TRIE = 1; - private static final int FILETYPE_FREQUENCY = 2; - private static final int FILETYPE_TERMINAL_ADDRESS_TABLE = 3; - private static final int FILETYPE_BIGRAM_FREQ = 4; - private static final int FILETYPE_SHORTCUT = 5; - - private final File mDictDirectory; - private final DictionaryBufferFactory mBufferFactory; - protected DictBuffer mDictBuffer; - private DictBuffer mFrequencyBuffer; - private DictBuffer mTerminalAddressTableBuffer; - private DictBuffer mBigramBuffer; - private DictBuffer mShortcutBuffer; - private SparseTable mBigramAddressTable; - private SparseTable mShortcutAddressTable; - - @UsedForTesting - /* package */ Ver4DictDecoder(final File dictDirectory, final int factoryFlag) { - mDictDirectory = dictDirectory; - mDictBuffer = mFrequencyBuffer = null; - - if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) { - mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); - } else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) { - mBufferFactory = new DictionaryBufferFromByteArrayFactory(); - } else if ((factoryFlag & MASK_DICTBUFFER) == USE_WRITABLE_BYTEBUFFER) { - mBufferFactory = new DictionaryBufferFromWritableByteBufferFactory(); - } else { - mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); - } - } - - @UsedForTesting - /* package */ Ver4DictDecoder(final File dictDirectory, final DictionaryBufferFactory factory) { - mDictDirectory = dictDirectory; - mBufferFactory = factory; - mDictBuffer = mFrequencyBuffer = null; - } - - private File getFile(final int fileType) { - if (fileType == FILETYPE_TRIE) { - return new File(mDictDirectory, - mDictDirectory.getName() + FormatSpec.TRIE_FILE_EXTENSION); - } else if (fileType == FILETYPE_FREQUENCY) { - return new File(mDictDirectory, - mDictDirectory.getName() + FormatSpec.FREQ_FILE_EXTENSION); - } else if (fileType == FILETYPE_TERMINAL_ADDRESS_TABLE) { - return new File(mDictDirectory, - mDictDirectory.getName() + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); - } else if (fileType == FILETYPE_BIGRAM_FREQ) { - return new File(mDictDirectory, - mDictDirectory.getName() + FormatSpec.BIGRAM_FILE_EXTENSION - + FormatSpec.BIGRAM_FREQ_CONTENT_ID); - } else if (fileType == FILETYPE_SHORTCUT) { - return new File(mDictDirectory, - mDictDirectory.getName() + FormatSpec.SHORTCUT_FILE_EXTENSION - + FormatSpec.SHORTCUT_CONTENT_ID); - } else { - throw new RuntimeException("Unsupported kind of file : " + fileType); - } - } - - @Override - public void openDictBuffer() throws FileNotFoundException, IOException { - mDictBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_TRIE)); - mFrequencyBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_FREQUENCY)); - mTerminalAddressTableBuffer = mBufferFactory.getDictionaryBuffer( - getFile(FILETYPE_TERMINAL_ADDRESS_TABLE)); - mBigramBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_BIGRAM_FREQ)); - loadBigramAddressSparseTable(); - mShortcutBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_SHORTCUT)); - loadShortcutAddressSparseTable(); - } - - @Override - public boolean isDictBufferOpen() { - return mDictBuffer != null; - } - - /* package */ DictBuffer getDictBuffer() { - return mDictBuffer; - } - - @Override - public FileHeader readHeader() throws IOException, UnsupportedFormatException { - if (mDictBuffer == null) { - openDictBuffer(); - } - final FileHeader header = super.readHeader(mDictBuffer); - final int version = header.mFormatOptions.mVersion; - if (version != 4) { - throw new UnsupportedFormatException("File header has a wrong version : " + version); - } - return header; - } - - private void loadBigramAddressSparseTable() throws IOException { - final File lookupIndexFile = new File(mDictDirectory, mDictDirectory.getName() - + FormatSpec.BIGRAM_FILE_EXTENSION + FormatSpec.LOOKUP_TABLE_FILE_SUFFIX); - final File freqsFile = new File(mDictDirectory, mDictDirectory.getName() - + FormatSpec.BIGRAM_FILE_EXTENSION + FormatSpec.CONTENT_TABLE_FILE_SUFFIX - + FormatSpec.BIGRAM_FREQ_CONTENT_ID); - mBigramAddressTable = SparseTable.readFromFiles(lookupIndexFile, new File[] { freqsFile }, - FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE); - } - - // TODO: Let's have something like SparseTableContentsReader in this class. - private void loadShortcutAddressSparseTable() throws IOException { - final File lookupIndexFile = new File(mDictDirectory, mDictDirectory.getName() - + FormatSpec.SHORTCUT_FILE_EXTENSION + FormatSpec.LOOKUP_TABLE_FILE_SUFFIX); - final File contentFile = new File(mDictDirectory, mDictDirectory.getName() - + FormatSpec.SHORTCUT_FILE_EXTENSION + FormatSpec.CONTENT_TABLE_FILE_SUFFIX - + FormatSpec.SHORTCUT_CONTENT_ID); - final File timestampsFile = new File(mDictDirectory, mDictDirectory.getName() - + FormatSpec.SHORTCUT_FILE_EXTENSION + FormatSpec.CONTENT_TABLE_FILE_SUFFIX - + FormatSpec.SHORTCUT_CONTENT_ID); - mShortcutAddressTable = SparseTable.readFromFiles(lookupIndexFile, - new File[] { contentFile, timestampsFile }, - FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE); - } - - protected static class PtNodeReader extends AbstractDictDecoder.PtNodeReader { - protected static int readFrequency(final DictBuffer frequencyBuffer, final int terminalId) { - frequencyBuffer.position(terminalId * FormatSpec.FREQUENCY_AND_FLAGS_SIZE + 1); - return frequencyBuffer.readUnsignedByte(); - } - - protected static int readTerminalId(final DictBuffer dictBuffer) { - return dictBuffer.readInt(); - } - } - - private ArrayList<WeightedString> readShortcuts(final int terminalId) { - if (mShortcutAddressTable.get(0, terminalId) == SparseTable.NOT_EXIST) return null; - - final ArrayList<WeightedString> ret = CollectionUtils.newArrayList(); - final int posOfShortcuts = mShortcutAddressTable.get(FormatSpec.SHORTCUT_CONTENT_INDEX, - terminalId); - mShortcutBuffer.position(posOfShortcuts); - while (true) { - final int flags = mShortcutBuffer.readUnsignedByte(); - final String word = CharEncoding.readString(mShortcutBuffer); - ret.add(new WeightedString(word, - flags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY)); - if (0 == (flags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; - } - return ret; - } - - // TODO: Make this buffer thread safe. - // TODO: Support words longer than FormatSpec.MAX_WORD_LENGTH. - private final int[] mCharacterBuffer = new int[FormatSpec.MAX_WORD_LENGTH]; - @Override - public PtNodeInfo readPtNode(int ptNodePos, FormatOptions options) { - int addressPointer = ptNodePos; - final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); - addressPointer += FormatSpec.PTNODE_FLAGS_SIZE; - - final int parentAddress = PtNodeReader.readParentAddress(mDictBuffer, options); - if (BinaryDictIOUtils.supportsDynamicUpdate(options)) { - addressPointer += FormatSpec.PARENT_ADDRESS_SIZE; - } - - final int characters[]; - if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) { - int index = 0; - int character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - while (FormatSpec.INVALID_CHARACTER != character - && index < FormatSpec.MAX_WORD_LENGTH) { - mCharacterBuffer[index++] = character; - character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - } - characters = Arrays.copyOfRange(mCharacterBuffer, 0, index); - } else { - final int character = CharEncoding.readChar(mDictBuffer); - addressPointer += CharEncoding.getCharSize(character); - characters = new int[] { character }; - } - final int terminalId; - if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) { - terminalId = PtNodeReader.readTerminalId(mDictBuffer); - addressPointer += FormatSpec.PTNODE_TERMINAL_ID_SIZE; - } else { - terminalId = PtNode.NOT_A_TERMINAL; - } - - final int frequency; - if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) { - frequency = PtNodeReader.readFrequency(mFrequencyBuffer, terminalId); - } else { - frequency = PtNode.NOT_A_TERMINAL; - } - int childrenAddress = PtNodeReader.readChildrenAddress(mDictBuffer, flags, options); - if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - childrenAddress += addressPointer; - } - addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options); - final ArrayList<WeightedString> shortcutTargets = readShortcuts(terminalId); - - final ArrayList<PendingAttribute> bigrams; - if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) { - bigrams = new ArrayList<PendingAttribute>(); - final int posOfBigrams = mBigramAddressTable.get(0 /* contentTableIndex */, terminalId); - mBigramBuffer.position(posOfBigrams); - while (bigrams.size() < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - // If bigrams.size() reaches FormatSpec.MAX_BIGRAMS_IN_A_PTNODE, - // remaining bigram entries are ignored. - final int bigramFlags = mBigramBuffer.readUnsignedByte(); - final int targetTerminalId = mBigramBuffer.readUnsignedInt24(); - mTerminalAddressTableBuffer.position( - targetTerminalId * FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE); - final int targetAddress = mTerminalAddressTableBuffer.readUnsignedInt24(); - bigrams.add(new PendingAttribute( - bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY, - targetAddress)); - if (0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; - } - if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { - throw new RuntimeException("Too many bigrams in a PtNode (" + bigrams.size() - + " but max is " + FormatSpec.MAX_BIGRAMS_IN_A_PTNODE + ")"); - } - } else { - bigrams = null; - } - return new PtNodeInfo(ptNodePos, addressPointer, flags, characters, frequency, - parentAddress, childrenAddress, shortcutTargets, bigrams); - } - - private void deleteDictFiles() { - final File[] files = mDictDirectory.listFiles(); - for (int i = 0; i < files.length; ++i) { - files[i].delete(); - } - } - - @Override - public FusionDictionary readDictionaryBinary(final FusionDictionary dict, - final boolean deleteDictIfBroken) - throws FileNotFoundException, IOException, UnsupportedFormatException { - if (mDictBuffer == null) { - openDictBuffer(); - } - try { - return BinaryDictDecoderUtils.readDictionaryBinary(this, dict); - } catch (IOException e) { - Log.e(TAG, "The dictionary " + mDictDirectory.getName() + " is broken.", e); - if (deleteDictIfBroken) { - deleteDictFiles(); - } - throw e; - } catch (UnsupportedFormatException e) { - Log.e(TAG, "The dictionary " + mDictDirectory.getName() + " is broken.", e); - if (deleteDictIfBroken) { - deleteDictFiles(); - } - throw e; - } - } - - @Override - public void setPosition(int newPos) { - mDictBuffer.position(newPos); - } - - @Override - public int getPosition() { - return mDictBuffer.position(); - } - - @Override - public int readPtNodeCount() { - return BinaryDictDecoderUtils.readPtNodeCount(mDictBuffer); - } - - @Override - public boolean readAndFollowForwardLink() { - final int nextAddress = mDictBuffer.readUnsignedInt24(); - if (nextAddress >= 0 && nextAddress < mDictBuffer.limit()) { - mDictBuffer.position(nextAddress); - return true; - } - return false; - } - - @Override - public boolean hasNextPtNodeArray() { - return mDictBuffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS; - } - - @Override - public void skipPtNode(final FormatOptions formatOptions) { - final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); - PtNodeReader.readParentAddress(mDictBuffer, formatOptions); - BinaryDictIOUtils.skipString(mDictBuffer, - (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0); - if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) PtNodeReader.readTerminalId(mDictBuffer); - PtNodeReader.readChildrenAddress(mDictBuffer, flags, formatOptions); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java deleted file mode 100644 index 8d5b48a9b..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java +++ /dev/null @@ -1,475 +0,0 @@ -/* -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * An implementation of DictEncoder for version 4 binary dictionary. - */ -@UsedForTesting -public class Ver4DictEncoder implements DictEncoder { - private final File mDictPlacedDir; - private byte[] mTrieBuf; - private int mTriePos; - private int mHeaderSize; - private OutputStream mTrieOutStream; - private OutputStream mFreqOutStream; - private OutputStream mUnigramTimestampOutStream; - private OutputStream mTerminalAddressTableOutStream; - private File mDictDir; - private String mBaseFilename; - private BigramContentWriter mBigramWriter; - private ShortcutContentWriter mShortcutWriter; - - @UsedForTesting - public Ver4DictEncoder(final File dictPlacedDir) { - mDictPlacedDir = dictPlacedDir; - } - - private interface SparseTableContentWriterInterface { - public void write(final OutputStream outStream) throws IOException; - } - - private static class SparseTableContentWriter { - private final int mContentCount; - private final SparseTable mSparseTable; - private final File mLookupTableFile; - protected final File mBaseDir; - private final File[] mAddressTableFiles; - private final File[] mContentFiles; - protected final OutputStream[] mContentOutStreams; - - public SparseTableContentWriter(final String name, final int initialCapacity, - final int blockSize, final File baseDir, final String[] contentFilenames, - final String[] contentIds) { - if (contentFilenames.length != contentIds.length) { - throw new RuntimeException("The length of contentFilenames and the length of" - + " contentIds are different " + contentFilenames.length + ", " - + contentIds.length); - } - mContentCount = contentFilenames.length; - mSparseTable = new SparseTable(initialCapacity, blockSize, mContentCount); - mLookupTableFile = new File(baseDir, name + FormatSpec.LOOKUP_TABLE_FILE_SUFFIX); - mAddressTableFiles = new File[mContentCount]; - mContentFiles = new File[mContentCount]; - mBaseDir = baseDir; - for (int i = 0; i < mContentCount; ++i) { - mAddressTableFiles[i] = new File(mBaseDir, - name + FormatSpec.CONTENT_TABLE_FILE_SUFFIX + contentIds[i]); - mContentFiles[i] = new File(mBaseDir, contentFilenames[i] + contentIds[i]); - } - mContentOutStreams = new OutputStream[mContentCount]; - } - - public void openStreams() throws FileNotFoundException { - for (int i = 0; i < mContentCount; ++i) { - mContentOutStreams[i] = new FileOutputStream(mContentFiles[i]); - } - } - - protected void write(final int contentIndex, final int index, - final SparseTableContentWriterInterface writer) throws IOException { - mSparseTable.set(contentIndex, index, (int) mContentFiles[contentIndex].length()); - writer.write(mContentOutStreams[contentIndex]); - mContentOutStreams[contentIndex].flush(); - } - - public void closeStreams() throws IOException { - mSparseTable.writeToFiles(mLookupTableFile, mAddressTableFiles); - for (int i = 0; i < mContentCount; ++i) { - mContentOutStreams[i].close(); - } - } - } - - private static class BigramContentWriter extends SparseTableContentWriter { - private final boolean mWriteTimestamp; - - public BigramContentWriter(final String name, final int initialCapacity, - final File baseDir, final boolean writeTimestamp) { - super(name + FormatSpec.BIGRAM_FILE_EXTENSION, initialCapacity, - FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, baseDir, - getContentFilenames(name, writeTimestamp), getContentIds(writeTimestamp)); - mWriteTimestamp = writeTimestamp; - } - - private static String[] getContentFilenames(final String name, - final boolean writeTimestamp) { - final String[] contentFilenames; - if (writeTimestamp) { - contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION, - name + FormatSpec.BIGRAM_FILE_EXTENSION }; - } else { - contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION }; - } - return contentFilenames; - } - - private static String[] getContentIds(final boolean writeTimestamp) { - final String[] contentIds; - if (writeTimestamp) { - contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID, - FormatSpec.BIGRAM_TIMESTAMP_CONTENT_ID }; - } else { - contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID }; - } - return contentIds; - } - - public void writeBigramsForOneWord(final int terminalId, final int bigramCount, - final Iterator<WeightedString> bigramIterator, final FusionDictionary dict) - throws IOException { - write(FormatSpec.BIGRAM_FREQ_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - writeBigramsForOneWordInternal(outStream, bigramIterator, dict); - }}); - if (mWriteTimestamp) { - write(FormatSpec.BIGRAM_TIMESTAMP_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - initBigramTimestampsCountersAndLevelsForOneWordInternal(outStream, - bigramCount); - }}); - } - } - - private void writeBigramsForOneWordInternal(final OutputStream outStream, - final Iterator<WeightedString> bigramIterator, final FusionDictionary dict) - throws IOException { - while (bigramIterator.hasNext()) { - final WeightedString bigram = bigramIterator.next(); - final PtNode target = - FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord); - final int unigramFrequencyForThisWord = target.mFrequency; - final int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags( - bigramIterator.hasNext(), 0, bigram.mFrequency, - unigramFrequencyForThisWord, bigram.mWord); - BinaryDictEncoderUtils.writeUIntToStream(outStream, bigramFlags, - FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, target.mTerminalId, - FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE); - } - } - - private void initBigramTimestampsCountersAndLevelsForOneWordInternal( - final OutputStream outStream, final int bigramCount) throws IOException { - for (int i = 0; i < bigramCount; ++i) { - // TODO: Figure out what initial values should be. - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_TIMESTAMP_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_COUNTER_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_LEVEL_SIZE); - } - } - } - - private static class ShortcutContentWriter extends SparseTableContentWriter { - public ShortcutContentWriter(final String name, final int initialCapacity, - final File baseDir) { - super(name + FormatSpec.SHORTCUT_FILE_EXTENSION, initialCapacity, - FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, baseDir, - new String[] { name + FormatSpec.SHORTCUT_FILE_EXTENSION }, - new String[] { FormatSpec.SHORTCUT_CONTENT_ID }); - } - - public void writeShortcutForOneWord(final int terminalId, - final Iterator<WeightedString> shortcutIterator) throws IOException { - write(FormatSpec.SHORTCUT_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - writeShortcutForOneWordInternal(outStream, shortcutIterator); - } - }); - } - - private void writeShortcutForOneWordInternal(final OutputStream outStream, - final Iterator<WeightedString> shortcutIterator) throws IOException { - while (shortcutIterator.hasNext()) { - final WeightedString target = shortcutIterator.next(); - final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags( - shortcutIterator.hasNext(), target.mFrequency); - BinaryDictEncoderUtils.writeUIntToStream(outStream, shortcutFlags, - FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); - CharEncoding.writeString(outStream, target.mWord); - } - } - } - - private void openStreams(final FormatOptions formatOptions, final DictionaryOptions dictOptions) - throws FileNotFoundException, IOException { - final FileHeader header = new FileHeader(0, dictOptions, formatOptions); - mBaseFilename = header.getId() + "." + header.getVersion(); - mDictDir = new File(mDictPlacedDir, mBaseFilename); - final File trieFile = new File(mDictDir, mBaseFilename + FormatSpec.TRIE_FILE_EXTENSION); - final File freqFile = new File(mDictDir, mBaseFilename + FormatSpec.FREQ_FILE_EXTENSION); - final File timestampFile = new File(mDictDir, - mBaseFilename + FormatSpec.UNIGRAM_TIMESTAMP_FILE_EXTENSION); - final File terminalAddressTableFile = new File(mDictDir, - mBaseFilename + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); - if (!mDictDir.isDirectory()) { - if (mDictDir.exists()) mDictDir.delete(); - mDictDir.mkdirs(); - } - mTrieOutStream = new FileOutputStream(trieFile); - mFreqOutStream = new FileOutputStream(freqFile); - mTerminalAddressTableOutStream = new FileOutputStream(terminalAddressTableFile); - if (formatOptions.mHasTimestamp) { - mUnigramTimestampOutStream = new FileOutputStream(timestampFile); - } - } - - private void close() throws IOException { - try { - if (mTrieOutStream != null) { - mTrieOutStream.close(); - } - if (mFreqOutStream != null) { - mFreqOutStream.close(); - } - if (mTerminalAddressTableOutStream != null) { - mTerminalAddressTableOutStream.close(); - } - if (mUnigramTimestampOutStream != null) { - mUnigramTimestampOutStream.close(); - } - } finally { - mTrieOutStream = null; - mFreqOutStream = null; - mTerminalAddressTableOutStream = null; - } - } - - @Override - public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) - throws IOException, UnsupportedFormatException { - if (formatOptions.mVersion != FormatSpec.VERSION4) { - throw new UnsupportedFormatException("File header has a wrong version number : " - + formatOptions.mVersion); - } - if (!mDictPlacedDir.isDirectory()) { - throw new UnsupportedFormatException("Given path is not a directory."); - } - - if (mTrieOutStream == null) { - openStreams(formatOptions, dict.mOptions); - } - - mHeaderSize = BinaryDictEncoderUtils.writeDictionaryHeader(mTrieOutStream, dict, - formatOptions); - - MakedictLog.i("Flattening the tree..."); - ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray); - int terminalCount = 0; - for (final PtNodeArray array : flatNodes) { - for (final PtNode node : array.mData) { - if (node.isTerminal()) node.mTerminalId = terminalCount++; - } - } - - MakedictLog.i("Computing addresses..."); - BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions); - if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes); - - writeTerminalData(flatNodes, terminalCount); - if (formatOptions.mHasTimestamp) { - initUnigramTimestamps(terminalCount); - } - mBigramWriter = new BigramContentWriter(mBaseFilename, terminalCount, mDictDir, - formatOptions.mHasTimestamp); - writeBigrams(flatNodes, dict); - mShortcutWriter = new ShortcutContentWriter(mBaseFilename, terminalCount, mDictDir); - writeShortcuts(flatNodes); - - final PtNodeArray lastNodeArray = flatNodes.get(flatNodes.size() - 1); - final int bufferSize = lastNodeArray.mCachedAddressAfterUpdate + lastNodeArray.mCachedSize; - mTrieBuf = new byte[bufferSize]; - - MakedictLog.i("Writing file..."); - for (PtNodeArray nodeArray : flatNodes) { - BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions); - } - if (MakedictLog.DBG) { - BinaryDictEncoderUtils.showStatistics(flatNodes); - MakedictLog.i("has " + terminalCount + " terminals."); - } - mTrieOutStream.write(mTrieBuf); - - MakedictLog.i("Done"); - close(); - } - - @Override - public void setPosition(int position) { - if (mTrieBuf == null || position < 0 || position >- mTrieBuf.length) return; - mTriePos = position; - } - - @Override - public int getPosition() { - return mTriePos; - } - - @Override - public void writePtNodeCount(int ptNodeCount) { - final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount); - // ptNodeCount must fit on one byte or two bytes. - // Please see comments in FormatSpec - if (countSize != 1 && countSize != 2) { - throw new RuntimeException("Strange size from getPtNodeCountSize : " + countSize); - } - final int encodedPtNodeCount = (countSize == 2) ? - (ptNodeCount | FormatSpec.LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG) : ptNodeCount; - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, encodedPtNodeCount, - countSize); - } - - private void writePtNodeFlags(final PtNode ptNode, final FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, - BinaryDictEncoderUtils.makePtNodeFlags(ptNode, childrenPos, formatOptions), - FormatSpec.PTNODE_FLAGS_SIZE); - } - - private void writeParentPosition(int parentPos, final PtNode ptNode, - final FormatOptions formatOptions) { - if (parentPos != FormatSpec.NO_PARENT_ADDRESS) { - parentPos -= ptNode.mCachedAddressAfterUpdate; - } - mTriePos = BinaryDictEncoderUtils.writeParentAddress(mTrieBuf, mTriePos, parentPos, - formatOptions); - } - - private void writeCharacters(final int[] characters, final boolean hasSeveralChars) { - mTriePos = CharEncoding.writeCharArray(characters, mTrieBuf, mTriePos); - if (hasSeveralChars) { - mTrieBuf[mTriePos++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR; - } - } - - private void writeTerminalId(final int terminalId) { - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, terminalId, - FormatSpec.PTNODE_TERMINAL_ID_SIZE); - } - - private void writeChildrenPosition(PtNode ptNode, FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - if (formatOptions.mSupportsDynamicUpdate) { - mTriePos += BinaryDictEncoderUtils.writeSignedChildrenPosition(mTrieBuf, - mTriePos, childrenPos); - } else { - mTriePos += BinaryDictEncoderUtils.writeChildrenPosition(mTrieBuf, - mTriePos, childrenPos); - } - } - - private void writeBigrams(final ArrayList<PtNodeArray> flatNodes, final FusionDictionary dict) - throws IOException { - mBigramWriter.openStreams(); - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.mBigrams != null) { - mBigramWriter.writeBigramsForOneWord(ptNode.mTerminalId, ptNode.mBigrams.size(), - ptNode.mBigrams.iterator(), dict); - } - } - } - mBigramWriter.closeStreams(); - } - - private void writeShortcuts(final ArrayList<PtNodeArray> flatNodes) throws IOException { - mShortcutWriter.openStreams(); - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.mShortcutTargets != null && !ptNode.mShortcutTargets.isEmpty()) { - mShortcutWriter.writeShortcutForOneWord(ptNode.mTerminalId, - ptNode.mShortcutTargets.iterator()); - } - } - } - mShortcutWriter.closeStreams(); - } - - @Override - public void writeForwardLinkAddress(int forwardLinkAddress) { - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, - forwardLinkAddress, FormatSpec.FORWARD_LINK_ADDRESS_SIZE); - } - - @Override - public void writePtNode(final PtNode ptNode, final int parentPosition, - final FormatOptions formatOptions, final FusionDictionary dict) { - writePtNodeFlags(ptNode, formatOptions); - writeParentPosition(parentPosition, ptNode, formatOptions); - writeCharacters(ptNode.mChars, ptNode.hasSeveralChars()); - if (ptNode.isTerminal()) { - writeTerminalId(ptNode.mTerminalId); - } - writeChildrenPosition(ptNode, formatOptions); - } - - private void writeTerminalData(final ArrayList<PtNodeArray> flatNodes, - final int terminalCount) throws IOException { - final byte[] freqBuf = new byte[terminalCount * FormatSpec.FREQUENCY_AND_FLAGS_SIZE]; - final byte[] terminalAddressTableBuf = - new byte[terminalCount * FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE]; - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.isTerminal()) { - BinaryDictEncoderUtils.writeUIntToBuffer(freqBuf, - ptNode.mTerminalId * FormatSpec.FREQUENCY_AND_FLAGS_SIZE, - ptNode.mFrequency, FormatSpec.FREQUENCY_AND_FLAGS_SIZE); - BinaryDictEncoderUtils.writeUIntToBuffer(terminalAddressTableBuf, - ptNode.mTerminalId * FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, - ptNode.mCachedAddressAfterUpdate + mHeaderSize, - FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE); - } - } - } - mFreqOutStream.write(freqBuf); - mTerminalAddressTableOutStream.write(terminalAddressTableBuf); - } - - private void initUnigramTimestamps(final int terminalCount) throws IOException { - // Initial value of time stamps for each word is 0. - final byte[] unigramTimestampBuf = - new byte[terminalCount * FormatSpec.UNIGRAM_TIMESTAMP_SIZE]; - mUnigramTimestampOutStream.write(unigramTimestampBuf); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java deleted file mode 100644 index 3d8f186ba..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -/** - * An implementation of DictUpdater for version 4 binary dictionary. - */ -@UsedForTesting -public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { - - @UsedForTesting - public Ver4DictUpdater(final File dictDirectory, final int factoryType) { - // DictUpdater must have an updatable DictBuffer. - super(dictDirectory, ((factoryType & MASK_DICTBUFFER) == USE_BYTEARRAY) - ? USE_BYTEARRAY : USE_WRITABLE_BYTEBUFFER); - } - - @Override - public void deleteWord(final String word) throws IOException, UnsupportedFormatException { - if (mDictBuffer == null) openDictBuffer(); - readHeader(); - final int wordPos = getTerminalPosition(word); - if (wordPos != FormatSpec.NOT_VALID_WORD) { - mDictBuffer.position(wordPos); - final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); - mDictBuffer.position(wordPos); - mDictBuffer.put((byte) DynamicBinaryDictIOUtils.markAsDeleted(flags)); - } - } - - @Override - public void insertWord(final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, final ArrayList<WeightedString> shortcuts, - final boolean isNotAWord, final boolean isBlackListEntry) - throws IOException, UnsupportedFormatException { - // TODO: Implement this method. - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/WeightedString.java b/java/src/com/android/inputmethod/latin/makedict/WeightedString.java new file mode 100644 index 000000000..f6782df9e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/WeightedString.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.util.Arrays; + +/** + * A string with a probability. + * + * This represents an "attribute", that is either a bigram or a shortcut. + */ +public final class WeightedString { + public final String mWord; + public ProbabilityInfo mProbabilityInfo; + + public WeightedString(final String word, final int probability) { + this(word, new ProbabilityInfo(probability)); + } + + public WeightedString(final String word, final ProbabilityInfo probabilityInfo) { + mWord = word; + mProbabilityInfo = probabilityInfo; + } + + @UsedForTesting + public int getProbability() { + return mProbabilityInfo.mProbability; + } + + public void setProbability(final int probability) { + mProbabilityInfo = new ProbabilityInfo(probability); + } + + @Override + public int hashCode() { + return Arrays.hashCode(new Object[] { mWord, mProbabilityInfo}); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof WeightedString)) return false; + final WeightedString w = (WeightedString)o; + return mWord.equals(w.mWord) && mProbabilityInfo.equals(w.mProbabilityInfo); + } +}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/makedict/Word.java b/java/src/com/android/inputmethod/latin/makedict/Word.java deleted file mode 100644 index 0eabb7bf3..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Word.java +++ /dev/null @@ -1,100 +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.latin.makedict; - -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Utility class for a word with a frequency. - * - * This is chiefly used to iterate a dictionary. - */ -public final class Word implements Comparable<Word> { - public final String mWord; - public final int mFrequency; - public final ArrayList<WeightedString> mShortcutTargets; - public final ArrayList<WeightedString> mBigrams; - public final boolean mIsNotAWord; - public final boolean mIsBlacklistEntry; - - private int mHashCode = 0; - - public Word(final String word, final int frequency, - final ArrayList<WeightedString> shortcutTargets, - final ArrayList<WeightedString> bigrams, - final boolean isNotAWord, final boolean isBlacklistEntry) { - mWord = word; - mFrequency = frequency; - mShortcutTargets = shortcutTargets; - mBigrams = bigrams; - mIsNotAWord = isNotAWord; - mIsBlacklistEntry = isBlacklistEntry; - } - - private static int computeHashCode(Word word) { - return Arrays.hashCode(new Object[] { - word.mWord, - word.mFrequency, - word.mShortcutTargets.hashCode(), - word.mBigrams.hashCode(), - word.mIsNotAWord, - word.mIsBlacklistEntry - }); - } - - /** - * Three-way comparison. - * - * A Word x is greater than a word y if x has a higher frequency. If they have the same - * frequency, they are sorted in lexicographic order. - */ - @Override - public int compareTo(Word w) { - if (mFrequency < w.mFrequency) return 1; - if (mFrequency > w.mFrequency) return -1; - return mWord.compareTo(w.mWord); - } - - /** - * Equality test. - * - * Words are equal if they have the same frequency, the same spellings, and the same - * attributes. - */ - @Override - public boolean equals(Object o) { - if (o == this) return true; - 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) - && mIsNotAWord == w.mIsNotAWord - && mIsBlacklistEntry == w.mIsBlacklistEntry; - } - - @Override - public int hashCode() { - if (mHashCode == 0) { - mHashCode = computeHashCode(this); - } - return mHashCode; - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java new file mode 100644 index 000000000..853392200 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java @@ -0,0 +1,164 @@ +/* + * 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.CombinedFormatUtils; +import com.android.inputmethod.latin.utils.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Utility class for a word with a probability. + * + * This is chiefly used to iterate a dictionary. + */ +public final class WordProperty implements Comparable<WordProperty> { + public final String mWord; + public final ProbabilityInfo mProbabilityInfo; + public final ArrayList<WeightedString> mShortcutTargets; + public final ArrayList<WeightedString> mBigrams; + public final boolean mIsNotAWord; + public final boolean mIsBlacklistEntry; + public final boolean mHasShortcuts; + public final boolean mHasBigrams; + + private int mHashCode = 0; + + @UsedForTesting + public WordProperty(final String word, final ProbabilityInfo probabilityInfo, + final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams, + final boolean isNotAWord, final boolean isBlacklistEntry) { + mWord = word; + mProbabilityInfo = probabilityInfo; + mShortcutTargets = shortcutTargets; + mBigrams = bigrams; + mIsNotAWord = isNotAWord; + mIsBlacklistEntry = isBlacklistEntry; + mHasBigrams = bigrams != null && !bigrams.isEmpty(); + mHasShortcuts = shortcutTargets != null && !shortcutTargets.isEmpty(); + } + + private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) { + return new ProbabilityInfo( + probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_PROBABILITY_INDEX], + probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX], + probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_LEVEL_INDEX], + probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_COUNT_INDEX]); + } + + // Construct word property using information from native code. + // This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY. + public WordProperty(final int[] codePoints, final boolean isNotAWord, + final boolean isBlacklisted, final boolean hasBigram, + final boolean hasShortcuts, final int[] probabilityInfo, + final ArrayList<int[]> bigramTargets, final ArrayList<int[]> bigramProbabilityInfo, + final ArrayList<int[]> shortcutTargets, + final ArrayList<Integer> shortcutProbabilities) { + mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints); + mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo); + mShortcutTargets = CollectionUtils.newArrayList(); + mBigrams = CollectionUtils.newArrayList(); + mIsNotAWord = isNotAWord; + mIsBlacklistEntry = isBlacklisted; + mHasShortcuts = hasShortcuts; + mHasBigrams = hasBigram; + + final int bigramTargetCount = bigramTargets.size(); + for (int i = 0; i < bigramTargetCount; i++) { + final String bigramTargetString = + StringUtils.getStringFromNullTerminatedCodePointArray(bigramTargets.get(i)); + mBigrams.add(new WeightedString(bigramTargetString, + createProbabilityInfoFromArray(bigramProbabilityInfo.get(i)))); + } + + final int shortcutTargetCount = shortcutTargets.size(); + for (int i = 0; i < shortcutTargetCount; i++) { + final String shortcutTargetString = + StringUtils.getStringFromNullTerminatedCodePointArray(shortcutTargets.get(i)); + mShortcutTargets.add( + new WeightedString(shortcutTargetString, shortcutProbabilities.get(i))); + } + } + + public int getProbability() { + return mProbabilityInfo.mProbability; + } + + private static int computeHashCode(WordProperty word) { + return Arrays.hashCode(new Object[] { + word.mWord, + word.mProbabilityInfo, + word.mShortcutTargets.hashCode(), + word.mBigrams.hashCode(), + word.mIsNotAWord, + word.mIsBlacklistEntry + }); + } + + /** + * Three-way comparison. + * + * A Word x is greater than a word y if x has a higher frequency. If they have the same + * frequency, they are sorted in lexicographic order. + */ + @Override + public int compareTo(final WordProperty w) { + if (getProbability() < w.getProbability()) return 1; + if (getProbability() > w.getProbability()) return -1; + return mWord.compareTo(w.mWord); + } + + /** + * Equality test. + * + * Words are equal if they have the same frequency, the same spellings, and the same + * attributes. + */ + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof WordProperty)) return false; + WordProperty w = (WordProperty)o; + return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord) + && mShortcutTargets.equals(w.mShortcutTargets) && mBigrams.equals(w.mBigrams) + && mIsNotAWord == w.mIsNotAWord && mIsBlacklistEntry == w.mIsBlacklistEntry + && mHasBigrams == w.mHasBigrams && mHasShortcuts && w.mHasBigrams; + } + + @Override + public int hashCode() { + if (mHashCode == 0) { + mHashCode = computeHashCode(this); + } + return mHashCode; + } + + @UsedForTesting + public boolean isValid() { + return getProbability() != BinaryDictionary.NOT_A_PROBABILITY; + } + + @Override + public String toString() { + return CombinedFormatUtils.formatWordProperty(this); + } +} diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 1de15a333..352288f8b 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -17,25 +17,17 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.makedict.DictDecoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.settings.Settings; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.utils.LanguageModelParam; import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -44,9 +36,7 @@ import java.util.Map; */ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableBinaryDictionary { private static final String TAG = DecayingExpandableBinaryDictionaryBase.class.getSimpleName(); - public static final boolean DBG_SAVE_RESTORE = false; - private static final boolean DBG_STRESS_TEST = false; - private static final boolean PROFILE_SAVE_RESTORE = LatinImeLogger.sDBG; + private static final boolean DBG_DUMP_ON_CLOSE = false; /** Any pair being typed or picked */ public static final int FREQUENCY_FOR_TYPED = 2; @@ -54,182 +44,62 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB public static final int FREQUENCY_FOR_WORDS_IN_DICTS = FREQUENCY_FOR_TYPED; public static final int FREQUENCY_FOR_WORDS_NOT_IN_DICTS = Dictionary.NOT_A_PROBABILITY; - /** Locale for which this user history dictionary is storing words */ - private final String mLocale; + /** The locale for this dictionary. */ + public final Locale mLocale; - private final String mFileName; + private Map<String, String> mAdditionalAttributeMap = null; - private final SharedPreferences mPrefs; - - private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions = - CollectionUtils.newArrayList(); - - // Should always be false except when we use this class for test - @UsedForTesting boolean mIsTest = false; - - /* package */ DecayingExpandableBinaryDictionaryBase(final Context context, - final String locale, final SharedPreferences sp, final String dictionaryType, - final String fileName) { - super(context, fileName, dictionaryType, true); + protected DecayingExpandableBinaryDictionaryBase(final Context context, + final String dictName, final Locale locale, final String dictionaryType, + final File dictFile) { + super(context, dictName, locale, dictionaryType, dictFile); mLocale = locale; - mFileName = fileName; - mPrefs = sp; - if (mLocale != null && mLocale.length() > 1) { - asyncLoadDictionaryToMemory(); + if (mLocale != null && mLocale.toString().length() > 1) { reloadDictionaryIfRequired(); } } @Override public void close() { - if (!ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) { - closeBinaryDictionary(); + if (DBG_DUMP_ON_CLOSE) { + dumpAllWordsForDebug(); } // Flush pending writes. - // TODO: Remove after this class become to use a dynamic binary dictionary. - asyncFlashAllBinaryDictionary(); - Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale); + asyncFlushBinaryDictionary(); + super.close(); } @Override protected Map<String, String> getHeaderAttributeMap() { - HashMap<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - attributeMap.put(FormatSpec.FileHeader.USES_FORGETTING_CURVE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - attributeMap.put(FormatSpec.FileHeader.DICTIONARY_ID_ATTRIBUTE, mFileName); - attributeMap.put(FormatSpec.FileHeader.DICTIONARY_LOCALE_ATTRIBUTE, mLocale); + final Map<String, String> attributeMap = super.getHeaderAttributeMap(); + if (mAdditionalAttributeMap != null) { + attributeMap.putAll(mAdditionalAttributeMap); + } + attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); return attributeMap; } @Override - protected boolean hasContentChanged() { + protected boolean haveContentsChanged() { return false; } @Override - protected boolean needsToReloadBeforeWriting() { - return false; - } - - /** - * Pair will be added to the decaying dictionary. - * - * The first word may be null. That means we don't know the context, in other words, - * it's only a unigram. The first word may also be an empty string : this means start - * context, as in beginning of a sentence for example. - * The second word may not be null (a NullPointerException would be thrown). - */ - public void addToDictionary(final String word0, final String word1, final boolean isValid) { - if (word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH || - (word0 != null && word0.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) { - return; - } - final int frequency = ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ? - (isValid ? FREQUENCY_FOR_WORDS_IN_DICTS : FREQUENCY_FOR_WORDS_NOT_IN_DICTS) : - FREQUENCY_FOR_TYPED; - addWordDynamically(word1, null /* shortcutTarget */, frequency, 0 /* shortcutFreq */, - false /* isNotAWord */); - // Do not insert a word as a bigram of itself - if (word1.equals(word0)) { - return; - } - if (null != word0) { - addBigramDynamically(word0, word1, frequency, isValid); - } - } - - public void cancelAddingUserHistory(final String word0, final String word1) { - removeBigramDynamically(word0, word1); - } - - @Override - protected void loadDictionaryAsync() { - final int[] profTotalCount = { 0 }; - final String locale = getLocale(); - if (DBG_STRESS_TEST) { - try { - Log.w(TAG, "Start stress in loading: " + locale); - Thread.sleep(15000); - Log.w(TAG, "End stress in loading"); - } catch (InterruptedException e) { - } - } - final long last = Settings.readLastUserHistoryWriteTime(mPrefs, locale); - final long now = System.currentTimeMillis(); - final ExpandableBinaryDictionary dictionary = this; - final OnAddWordListener listener = new OnAddWordListener() { - @Override - public void setUnigram(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq) { - if (DBG_SAVE_RESTORE) { - Log.d(TAG, "load unigram: " + word + "," + frequency); - } - addWord(word, shortcutTarget, frequency, shortcutFreq, false /* isNotAWord */); - ++profTotalCount[0]; - } - - @Override - public void setBigram(final String word0, final String word1, final int frequency) { - if (word0.length() < Constants.DICTIONARY_MAX_WORD_LENGTH - && word1.length() < Constants.DICTIONARY_MAX_WORD_LENGTH) { - if (DBG_SAVE_RESTORE) { - Log.d(TAG, "load bigram: " + word0 + "," + word1 + "," + frequency); - } - ++profTotalCount[0]; - addBigram(word0, word1, frequency, last); - } - } - }; - - // Load the dictionary from binary file - final File dictFile = new File(mContext.getFilesDir(), mFileName); - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(dictFile, - DictDecoder.USE_BYTEARRAY); - if (dictDecoder == null) { - // This is an expected condition: we don't have a user history dictionary for this - // language yet. It will be created sometime later. - return; - } - - try { - dictDecoder.openDictBuffer(); - UserHistoryDictIOUtils.readDictionaryBinary(dictDecoder, listener); - } catch (IOException e) { - Log.d(TAG, "IOException on opening a bytebuffer", e); - } finally { - if (PROFILE_SAVE_RESTORE) { - final long diff = System.currentTimeMillis() - now; - Log.d(TAG, "PROF: Load UserHistoryDictionary: " - + locale + ", " + diff + "ms. load " + profTotalCount[0] + "entries."); - } - } - } - - protected String getLocale() { - return mLocale; - } - - public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { - session.setPredictionDictionary(this); - mSessions.add(session); - session.onDictionaryReady(); - } - - public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) { - mSessions.remove(session); + protected void loadInitialContentsLocked() { + // No initial contents. } @UsedForTesting - public void clearAndFlushDictionary() { - // Clear the node structure on memory + public void clearAndFlushDictionaryWithAdditionalAttributes( + final Map<String, String> attributeMap) { + mAdditionalAttributeMap = attributeMap; clear(); - // Then flush the cleared state of the dictionary on disk. - asyncFlashAllBinaryDictionary(); } - /* package */ void decayIfNeeded() { + /* package */ void runGCIfRequired() { runGCIfRequired(false /* mindsBlockByGC */); } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java index e9ca662e7..de2744f29 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java +++ b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java @@ -43,7 +43,7 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver { /** * Interval to update for decaying dictionaries. */ - private static final long DICTIONARY_DECAY_INTERVAL = TimeUnit.MINUTES.toMillis(60); + /* package */ static final long DICTIONARY_DECAY_INTERVAL = TimeUnit.MINUTES.toMillis(60); public static void setUpIntervalAlarmForDictionaryDecaying(Context context) { AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); @@ -60,7 +60,7 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver { public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) { - PersonalizationHelper.tryDecayingAllOpeningUserHistoryDictionary(); + PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries(); } } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java deleted file mode 100644 index 6f152bb91..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2013 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.personalization; - -import android.content.Context; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.compat.ActivityManagerCompatUtils; -import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.AbstractDictionaryWriter; -import com.android.inputmethod.latin.ExpandableDictionary; -import com.android.inputmethod.latin.WordComposer; -import com.android.inputmethod.latin.ExpandableDictionary.NextWord; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; -import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils; -import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Map; - -// Currently this class is used to implement dynamic prodiction dictionary. -// TODO: Move to native code. -public class DynamicPersonalizationDictionaryWriter extends AbstractDictionaryWriter { - private static final String TAG = DynamicPersonalizationDictionaryWriter.class.getSimpleName(); - /** Maximum number of pairs. Pruning will start when databases goes above this number. */ - public static final int DEFAULT_MAX_HISTORY_BIGRAMS = 10000; - public static final int LOW_MEMORY_MAX_HISTORY_BIGRAMS = 2000; - - /** Any pair being typed or picked */ - private static final int FREQUENCY_FOR_TYPED = 2; - - private static final int BINARY_DICT_VERSION = 3; - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = - new FormatSpec.FormatOptions(BINARY_DICT_VERSION, true /* supportsDynamicUpdate */); - - private final UserHistoryDictionaryBigramList mBigramList = - new UserHistoryDictionaryBigramList(); - private final ExpandableDictionary mExpandableDictionary; - private final int mMaxHistoryBigrams; - - public DynamicPersonalizationDictionaryWriter(final Context context, final String dictType) { - super(context, dictType); - mExpandableDictionary = new ExpandableDictionary(dictType); - final boolean isLowRamDevice = ActivityManagerCompatUtils.isLowRamDevice(context); - mMaxHistoryBigrams = isLowRamDevice ? - LOW_MEMORY_MAX_HISTORY_BIGRAMS : DEFAULT_MAX_HISTORY_BIGRAMS; - } - - @Override - public void clear() { - mBigramList.evictAll(); - mExpandableDictionary.clearDictionary(); - } - - /** - * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes - * are done to update the binary dictionary. - * @param word The word to add. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this unigram. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored - * if shortcutTarget is null. - * @param isNotAWord true if this is not a word, i.e. shortcut only. - */ - @Override - public void addUnigramWord(final String word, final String shortcutTarget, final int frequency, - final int shortcutFreq, final boolean isNotAWord) { - if (mBigramList.size() > mMaxHistoryBigrams * 2) { - // Too many entries: just stop adding new vocabulary and wait next refresh. - return; - } - mExpandableDictionary.addWord(word, shortcutTarget, frequency, shortcutFreq); - mBigramList.addBigram(null, word, (byte)frequency); - } - - @Override - public void addBigramWords(final String word0, final String word1, final int frequency, - final boolean isValid, final long lastModifiedTime) { - if (mBigramList.size() > mMaxHistoryBigrams * 2) { - // Too many entries: just stop adding new vocabulary and wait next refresh. - return; - } - if (lastModifiedTime > 0) { - mExpandableDictionary.setBigramAndGetFrequency(word0, word1, - new ForgettingCurveParams(frequency, System.currentTimeMillis(), - lastModifiedTime)); - mBigramList.addBigram(word0, word1, (byte)frequency); - } else { - mExpandableDictionary.setBigramAndGetFrequency(word0, word1, - new ForgettingCurveParams(isValid)); - mBigramList.addBigram(word0, word1, (byte)frequency); - } - } - - @Override - public void removeBigramWords(final String word0, final String word1) { - if (mBigramList.removeBigram(word0, word1)) { - mExpandableDictionary.removeBigram(word0, word1); - } - } - - @Override - protected void writeDictionary(final DictEncoder dictEncoder, - final Map<String, String> attributeMap) throws IOException, UnsupportedFormatException { - UserHistoryDictIOUtils.writeDictionary(dictEncoder, - new FrequencyProvider(mBigramList, mExpandableDictionary, mMaxHistoryBigrams), - mBigramList, FORMAT_OPTIONS); - } - - private static class FrequencyProvider implements BigramDictionaryInterface { - private final UserHistoryDictionaryBigramList mBigramList; - private final ExpandableDictionary mExpandableDictionary; - private final int mMaxHistoryBigrams; - - public FrequencyProvider(final UserHistoryDictionaryBigramList bigramList, - final ExpandableDictionary expandableDictionary, final int maxHistoryBigrams) { - mBigramList = bigramList; - mExpandableDictionary = expandableDictionary; - mMaxHistoryBigrams = maxHistoryBigrams; - } - - @Override - public int getFrequency(final String word0, final String word1) { - final int freq; - if (word0 == null) { // unigram - freq = FREQUENCY_FOR_TYPED; - } else { // bigram - final NextWord nw = mExpandableDictionary.getBigramWord(word0, word1); - if (nw != null) { - final ForgettingCurveParams forgettingCurveParams = nw.getFcParams(); - final byte prevFc = mBigramList.getBigrams(word0).get(word1); - final byte fc = forgettingCurveParams.getFc(); - final boolean isValid = forgettingCurveParams.isValid(); - if (prevFc > 0 && prevFc == fc) { - freq = fc & 0xFF; - } else if (UserHistoryForgettingCurveUtils. - needsToSave(fc, isValid, mBigramList.size() <= mMaxHistoryBigrams)) { - freq = fc & 0xFF; - } else { - // Delete this entry - freq = -1; - } - } else { - // Delete this entry - freq = -1; - } - } - return freq; - } - } - - @Override - public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, - final String prevWord, final ProximityInfo proximityInfo, - boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { - return mExpandableDictionary.getSuggestions(composer, prevWord, proximityInfo, - blockOffensiveWords, additionalFeaturesOptions); - } - - @Override - public boolean isValidWord(final String word) { - return mExpandableDictionary.isValidWord(word); - } - - @UsedForTesting - public boolean isInBigramListForTests(final String word) { - // TODO: Use native method to determine whether the word is in dictionary or not - return mBigramList.containsKey(word) || mBigramList.getBigrams(null).containsKey(word); - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java index f257165cb..4afd5b4c9 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java @@ -16,58 +16,29 @@ package com.android.inputmethod.latin.personalization; -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; -import com.android.inputmethod.latin.utils.CollectionUtils; - import android.content.Context; -import android.content.SharedPreferences; -import java.util.ArrayList; +import com.android.inputmethod.latin.Dictionary; -/** - * This class is a dictionary for the personalized language model that uses binary dictionary. - */ -public class PersonalizationDictionary extends ExpandableBinaryDictionary { - private static final String NAME = "personalization"; - private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions = - CollectionUtils.newArrayList(); +import java.io.File; +import java.util.Locale; - /** Locale for which this user history dictionary is storing words */ - private final String mLocale; +public class PersonalizationDictionary extends DecayingExpandableBinaryDictionaryBase { + /* package */ static final String NAME = PersonalizationDictionary.class.getSimpleName(); - public PersonalizationDictionary(final Context context, final String locale, - final SharedPreferences prefs) { - // TODO: Make isUpdatable true. - super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_PERSONALIZATION, - false /* isUpdatable */); - mLocale = locale; - // TODO: Restore last updated time - loadDictionary(); + /* package */ PersonalizationDictionary(final Context context, final Locale locale) { + this(context, locale, null /* dictFile */); } - @Override - protected void loadDictionaryAsync() { - // TODO: Implement + public PersonalizationDictionary(final Context context, final Locale locale, + final File dictFile) { + super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_PERSONALIZATION, + dictFile); } @Override - protected boolean hasContentChanged() { + public boolean isValidWord(final String word) { + // Strings out of this dictionary should not be considered existing words. return false; } - - @Override - protected boolean needsToReloadBeforeWriting() { - return false; - } - - public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) { - session.setDictionary(this); - mSessions.add(session); - session.onDictionaryReady(); - } - - public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) { - mSessions.remove(session); - } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java index c1833ff14..9bef7a198 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java @@ -19,19 +19,29 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; import android.content.res.Configuration; -public class PersonalizationDictionarySessionRegister { - public static void init(Context context) { +import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest; +import com.android.inputmethod.latin.utils.DistracterFilter; + +public class PersonalizationDictionarySessionRegistrar { + public static void init(final Context context, + final DictionaryFacilitatorForSuggest dictionaryFacilitator, + final DistracterFilter distracterFilter) { + } + + public static void onConfigurationChanged(final Context context, final Configuration conf, + final DictionaryFacilitatorForSuggest dictionaryFacilitator, + final DistracterFilter distracterFilter) { } - public static void onConfigurationChanged(final Context context, final Configuration conf) { + public static void onUpdateData(final Context context, final String type) { } - public static void onUpdateData(Context context, String type) { + public static void onRemoveData(final Context context, final String type) { } - public static void onRemoveData(Context context, String type) { + public static void resetAll(final Context context) { } - public static void onDestroy(Context context) { + public static void close(final Context context) { } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java deleted file mode 100644 index a86f6e584..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2013 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.personalization; - -import android.content.Context; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; - -/** - * This class is a session where a data provider can communicate with a personalization - * dictionary. - */ -public abstract class PersonalizationDictionaryUpdateSession { - /** - * This class is a parameter for a new unigram or bigram word which will be added - * to the personalization dictionary. - */ - public static class PersonalizationLanguageModelParam { - public final String mWord0; - public final String mWord1; - public final boolean mIsValid; - public final int mFrequency; - public PersonalizationLanguageModelParam(String word0, String word1, boolean isValid, - int frequency) { - mWord0 = word0; - mWord1 = word1; - mIsValid = isValid; - mFrequency = frequency; - } - } - - // TODO: Use a dynamic binary dictionary instead - public WeakReference<PersonalizationDictionary> mDictionary; - public WeakReference<DecayingExpandableBinaryDictionaryBase> mPredictionDictionary; - public final String mSystemLocale; - public PersonalizationDictionaryUpdateSession(String locale) { - mSystemLocale = locale; - } - - public abstract void onDictionaryReady(); - - public abstract void onDictionaryClosed(Context context); - - public void setDictionary(PersonalizationDictionary dictionary) { - mDictionary = new WeakReference<PersonalizationDictionary>(dictionary); - } - - public void setPredictionDictionary(DecayingExpandableBinaryDictionaryBase dictionary) { - mPredictionDictionary = - new WeakReference<DecayingExpandableBinaryDictionaryBase>(dictionary); - } - - protected PersonalizationDictionary getDictionary() { - return mDictionary == null ? null : mDictionary.get(); - } - - protected DecayingExpandableBinaryDictionaryBase getPredictionDictionary() { - return mPredictionDictionary == null ? null : mPredictionDictionary.get(); - } - - private void unsetDictionary() { - final PersonalizationDictionary dictionary = getDictionary(); - if (dictionary == null) { - return; - } - dictionary.unRegisterUpdateSession(this); - } - - private void unsetPredictionDictionary() { - final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary(); - if (dictionary == null) { - return; - } - dictionary.unRegisterUpdateSession(this); - } - - public void clearAndFlushPredictionDictionary(Context context) { - final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary(); - if (dictionary == null) { - return; - } - dictionary.clearAndFlushDictionary(); - } - - public void closeSession(Context context) { - unsetDictionary(); - unsetPredictionDictionary(); - onDictionaryClosed(context); - } - - // TODO: Support multi locale to add bigram - public void addBigramToPersonalizationDictionary(String word0, String word1, boolean isValid, - int frequency) { - final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary(); - if (dictionary == null) { - return; - } - dictionary.addToDictionary(word0, word1, isValid); - } - - // Bulk import - // TODO: Support multi locale to add bigram - public void addBigramsToPersonalizationDictionary( - final ArrayList<PersonalizationLanguageModelParam> lmParams) { - final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary(); - if (dictionary == null) { - return; - } - for (final PersonalizationLanguageModelParam lmParam : lmParams) { - dictionary.addToDictionary(lmParam.mWord0, lmParam.mWord1, lmParam.mIsValid); - } - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index 221ddeeba..7c43182bc 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -16,36 +16,35 @@ package com.android.inputmethod.latin.personalization; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.util.Log; +import java.io.File; +import java.io.FilenameFilter; import java.lang.ref.SoftReference; +import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class PersonalizationHelper { private static final String TAG = PersonalizationHelper.class.getSimpleName(); private static final boolean DEBUG = false; private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>> sLangUserHistoryDictCache = CollectionUtils.newConcurrentHashMap(); - private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>> sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap(); - private static final ConcurrentHashMap<String, - SoftReference<PersonalizationPredictionDictionary>> - sLangPersonalizationPredictionDictCache = - CollectionUtils.newConcurrentHashMap(); - public static UserHistoryDictionary getUserHistoryDictionary( - final Context context, final String locale, final SharedPreferences sp) { + final Context context, final Locale locale) { + final String localeStr = locale.toString(); synchronized (sLangUserHistoryDictCache) { - if (sLangUserHistoryDictCache.containsKey(locale)) { + if (sLangUserHistoryDictCache.containsKey(localeStr)) { final SoftReference<UserHistoryDictionary> ref = - sLangUserHistoryDictCache.get(locale); + sLangUserHistoryDictCache.get(localeStr); final UserHistoryDictionary dict = ref == null ? null : ref.get(); if (dict != null) { if (DEBUG) { @@ -55,77 +54,111 @@ public class PersonalizationHelper { return dict; } } - final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale, sp); - sLangUserHistoryDictCache.put(locale, new SoftReference<UserHistoryDictionary>(dict)); + final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale); + sLangUserHistoryDictCache.put(localeStr, + new SoftReference<UserHistoryDictionary>(dict)); return dict; } } - public static void tryDecayingAllOpeningUserHistoryDictionary() { - for (final ConcurrentHashMap.Entry<String, SoftReference<UserHistoryDictionary>> entry - : sLangUserHistoryDictCache.entrySet()) { - if (entry.getValue() != null) { - final UserHistoryDictionary dict = entry.getValue().get(); - if (dict != null) { - dict.decayIfNeeded(); - } - } + private static int sCurrentTimestampForTesting = 0; + public static void currentTimeChangedForTesting(final int currentTimestamp) { + if (TimeUnit.MILLISECONDS.toSeconds( + DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL) + < currentTimestamp - sCurrentTimestampForTesting) { + // TODO: Run GC for both PersonalizationDictionary and UserHistoryDictionary. + runGCOnAllOpenedUserHistoryDictionaries(); } } - public static void registerPersonalizationDictionaryUpdateSession(final Context context, - final PersonalizationDictionaryUpdateSession session, String locale) { - final PersonalizationPredictionDictionary predictionDictionary = - getPersonalizationPredictionDictionary(context, locale, - PreferenceManager.getDefaultSharedPreferences(context)); - predictionDictionary.registerUpdateSession(session); - final PersonalizationDictionary dictionary = - getPersonalizationDictionary(context, locale, - PreferenceManager.getDefaultSharedPreferences(context)); - dictionary.registerUpdateSession(session); + public static void runGCOnAllOpenedUserHistoryDictionaries() { + runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache); + } + + @UsedForTesting + public static void runGCOnAllOpenedPersonalizationDictionaries() { + runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache); + } + + private static <T extends DecayingExpandableBinaryDictionaryBase> + void runGCOnAllDictionariesIfRequired( + final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) { + for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry + : dictionaryMap.entrySet()) { + final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get(); + if (dict != null) { + dict.runGCIfRequired(); + } else { + dictionaryMap.remove(entry.getKey()); + } + } } public static PersonalizationDictionary getPersonalizationDictionary( - final Context context, final String locale, final SharedPreferences sp) { + final Context context, final Locale locale) { + final String localeStr = locale.toString(); synchronized (sLangPersonalizationDictCache) { - if (sLangPersonalizationDictCache.containsKey(locale)) { + if (sLangPersonalizationDictCache.containsKey(localeStr)) { final SoftReference<PersonalizationDictionary> ref = - sLangPersonalizationDictCache.get(locale); + sLangPersonalizationDictCache.get(localeStr); final PersonalizationDictionary dict = ref == null ? null : ref.get(); if (dict != null) { if (DEBUG) { - Log.w(TAG, "Use cached PersonalizationDictCache for " + locale); + Log.w(TAG, "Use cached PersonalizationDictionary for " + locale); } return dict; } } - final PersonalizationDictionary dict = - new PersonalizationDictionary(context, locale, sp); + final PersonalizationDictionary dict = new PersonalizationDictionary(context, locale); sLangPersonalizationDictCache.put( - locale, new SoftReference<PersonalizationDictionary>(dict)); + localeStr, new SoftReference<PersonalizationDictionary>(dict)); return dict; } } - public static PersonalizationPredictionDictionary getPersonalizationPredictionDictionary( - final Context context, final String locale, final SharedPreferences sp) { - synchronized (sLangPersonalizationPredictionDictCache) { - if (sLangPersonalizationPredictionDictCache.containsKey(locale)) { - final SoftReference<PersonalizationPredictionDictionary> ref = - sLangPersonalizationPredictionDictCache.get(locale); - final PersonalizationPredictionDictionary dict = ref == null ? null : ref.get(); - if (dict != null) { - if (DEBUG) { - Log.w(TAG, "Use cached PersonalizationPredictionDictionary for " + locale); + public static void removeAllPersonalizationDictionaries(final Context context) { + removeAllDictionaries(context, sLangPersonalizationDictCache, + PersonalizationDictionary.NAME); + } + + public static void removeAllUserHistoryDictionaries(final Context context) { + removeAllDictionaries(context, sLangUserHistoryDictCache, + UserHistoryDictionary.NAME); + } + + private static <T extends DecayingExpandableBinaryDictionaryBase> void removeAllDictionaries( + final Context context, final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap, + final String dictNamePrefix) { + synchronized (dictionaryMap) { + for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry + : dictionaryMap.entrySet()) { + if (entry.getValue() != null) { + final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get(); + if (dict != null) { + dict.clear(); } - return dict; } } - final PersonalizationPredictionDictionary dict = - new PersonalizationPredictionDictionary(context, locale, sp); - sLangPersonalizationPredictionDictCache.put( - locale, new SoftReference<PersonalizationPredictionDictionary>(dict)); - return dict; + dictionaryMap.clear(); + if (!FileUtils.deleteFilteredFiles( + context.getFilesDir(), new DictFilter(dictNamePrefix))) { + Log.e(TAG, "Cannot remove all existing dictionary files. filesDir: " + + context.getFilesDir().getAbsolutePath() + ", dictNamePrefix: " + + dictNamePrefix); + } + } + } + + private static class DictFilter implements FilenameFilter { + private final String mName; + + DictFilter(final String name) { + mName = name; + } + + @Override + public boolean accept(final File dir, final String name) { + return name.startsWith(mName); } } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java deleted file mode 100644 index 432954453..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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.personalization; - -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; - -import android.content.Context; -import android.content.SharedPreferences; - -public class PersonalizationPredictionDictionary extends DecayingExpandableBinaryDictionaryBase { - private static final String NAME = PersonalizationPredictionDictionary.class.getSimpleName(); - - /* package */ PersonalizationPredictionDictionary(final Context context, final String locale, - final SharedPreferences sp) { - super(context, locale, sp, Dictionary.TYPE_PERSONALIZATION_PREDICTION_IN_JAVA, - getDictionaryFileName(locale)); - } - - private static String getDictionaryFileName(final String locale) { - return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index a60226d7e..8a29c354d 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -16,25 +16,62 @@ package com.android.inputmethod.latin.personalization; +import android.content.Context; + +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; -import android.content.Context; -import android.content.SharedPreferences; +import java.io.File; +import java.util.Locale; /** * Locally gathers stats about the words user types and various other signals like auto-correction * cancellation or manual picks. This allows the keyboard to adapt to the typist over time. */ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase { - /* package for tests */ static final String NAME = - UserHistoryDictionary.class.getSimpleName(); - /* package */ UserHistoryDictionary(final Context context, final String locale, - final SharedPreferences sp) { - super(context, locale, sp, Dictionary.TYPE_USER_HISTORY, getDictionaryFileName(locale)); + /* package */ static final String NAME = UserHistoryDictionary.class.getSimpleName(); + + /* package */ UserHistoryDictionary(final Context context, final Locale locale) { + this(context, locale, null /* dictFile */); + } + + public UserHistoryDictionary(final Context context, final Locale locale, + final File dictFile) { + super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_USER_HISTORY, + dictFile); + } + + @Override + public boolean isValidWord(final String word) { + // Strings out of this dictionary should not be considered existing words. + return false; } - private static String getDictionaryFileName(final String locale) { - return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + /** + * Pair will be added to the user history dictionary. + * + * The first word may be null. That means we don't know the context, in other words, + * it's only a unigram. The first word may also be an empty string : this means start + * context, as in beginning of a sentence for example. + * The second word may not be null (a NullPointerException would be thrown). + */ + public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, + final String word0, final String word1, final boolean isValid, final int timestamp) { + if (word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH || + (word0 != null && word0.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) { + return; + } + final int frequency = isValid ? + FREQUENCY_FOR_WORDS_IN_DICTS : FREQUENCY_FOR_WORDS_NOT_IN_DICTS; + userHistoryDictionary.addWordDynamically(word1, frequency, null /* shortcutTarget */, + 0 /* shortcutFreq */, false /* isNotAWord */, false /* isBlacklisted */, timestamp); + // Do not insert a word as a bigram of itself + if (word1.equals(word0)) { + return; + } + if (null != word0) { + userHistoryDictionary.addBigramDynamically(word0, word1, frequency, timestamp); + } } } diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java deleted file mode 100644 index 55a90ee51..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.personalization; - -import android.util.Log; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.util.HashMap; -import java.util.Set; - -/** - * A store of bigrams which will be updated when the user history dictionary is closed - * All bigrams including stale ones in SQL DB should be stored in this class to avoid adding stale - * bigrams when we write to the SQL DB. - */ -@UsedForTesting -public final class UserHistoryDictionaryBigramList { - public static final byte FORGETTING_CURVE_INITIAL_VALUE = 0; - private static final String TAG = UserHistoryDictionaryBigramList.class.getSimpleName(); - private static final HashMap<String, Byte> EMPTY_BIGRAM_MAP = CollectionUtils.newHashMap(); - private final HashMap<String, HashMap<String, Byte>> mBigramMap = CollectionUtils.newHashMap(); - private int mSize = 0; - - public void evictAll() { - mSize = 0; - mBigramMap.clear(); - } - - /** - * Called when the user typed a word. - */ - @UsedForTesting - public void addBigram(String word1, String word2) { - addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE); - } - - /** - * Called when loaded from the SQL DB. - */ - public void addBigram(String word1, String word2, byte fcValue) { - if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) { - Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue); - } - final HashMap<String, Byte> map; - if (mBigramMap.containsKey(word1)) { - map = mBigramMap.get(word1); - } else { - map = CollectionUtils.newHashMap(); - mBigramMap.put(word1, map); - } - if (!map.containsKey(word2)) { - ++mSize; - map.put(word2, fcValue); - } - } - - /** - * Called when inserted to the SQL DB. - */ - public void updateBigram(String word1, String word2, byte fcValue) { - if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) { - Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue); - } - final HashMap<String, Byte> map; - if (mBigramMap.containsKey(word1)) { - map = mBigramMap.get(word1); - } else { - return; - } - if (!map.containsKey(word2)) { - return; - } - map.put(word2, fcValue); - } - - public int size() { - return mSize; - } - - public boolean isEmpty() { - return mBigramMap.isEmpty(); - } - - public boolean containsKey(String word) { - return mBigramMap.containsKey(word); - } - - public Set<String> keySet() { - return mBigramMap.keySet(); - } - - public HashMap<String, Byte> getBigrams(String word1) { - if (mBigramMap.containsKey(word1)) return mBigramMap.get(word1); - // TODO: lower case according to locale - final String lowerWord1 = word1.toLowerCase(); - if (mBigramMap.containsKey(lowerWord1)) return mBigramMap.get(lowerWord1); - return EMPTY_BIGRAM_MAP; - } - - public boolean removeBigram(String word1, String word2) { - final HashMap<String, Byte> set = getBigrams(word1); - if (set.isEmpty()) { - return false; - } - if (set.containsKey(word2)) { - set.remove(word2); - --mSize; - return true; - } - return false; - } -} diff --git a/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java index 4bf524cbb..39977e76f 100644 --- a/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin.settings; -import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE; - import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -44,10 +42,13 @@ import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.Toast; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.IntentUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -111,7 +112,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { subtype.getLocale(), subtype.hashCode(), subtype.hashCode(), SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype))); } - if (subtype.containsExtraValueKey(ASCII_CAPABLE)) { + if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) { items.add(createItem(context, subtype.getLocale())); } } @@ -287,7 +288,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { final KeyboardLayoutSetItem layout = (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem(); final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype( - locale.first, layout.first, ASCII_CAPABLE); + locale.first, layout.first, Constants.Subtype.ExtraValue.ASCII_CAPABLE); setSubtype(subtype); notifyChanged(); if (isEditing) { @@ -517,7 +518,8 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { private AlertDialog createDialog( @SuppressWarnings("unused") final SubtypePreference subtypePref) { - final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + final AlertDialog.Builder builder = new AlertDialog.Builder( + DialogUtils.getPlatformDialogThemeContext(getActivity())); builder.setTitle(R.string.custom_input_styles_title) .setMessage(R.string.custom_input_style_note_message) .setNegativeButton(R.string.not_now, null) diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index da1fb73fe..c4c1234fc 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -16,19 +16,24 @@ package com.android.inputmethod.latin.settings; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Resources; import android.os.Bundle; import android.os.Process; import android.preference.CheckBoxPreference; import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; -import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.debug.ExternalDictionaryGetterForDebug; import com.android.inputmethod.latin.utils.ApplicationUtils; +import com.android.inputmethod.latin.utils.ResourceUtils; public final class DebugSettings extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -37,11 +42,22 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch"; public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; public static final String PREF_STATISTICS_LOGGING = "enable_logging"; - public static final String PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG = - "use_only_personalization_dictionary_for_debug"; - public static final String PREF_BOOST_PERSONALIZATION_DICTIONARY_FOR_DEBUG = - "boost_personalization_dictionary_for_debug"; + public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE = + "pref_key_preview_show_up_start_scale"; + public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE = + "pref_key_preview_dismiss_end_scale"; + public static final String PREF_KEY_PREVIEW_SHOW_UP_DURATION = + "pref_key_preview_show_up_duration"; + public static final String PREF_KEY_PREVIEW_DISMISS_DURATION = + "pref_key_preview_dismiss_duration"; private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary"; + private static final String PREF_DUMP_CONTACTS_DICT = "dump_contacts_dict"; + private static final String PREF_DUMP_USER_DICT = "dump_user_dict"; + private static final String PREF_DUMP_USER_HISTORY_DICT = "dump_user_history_dict"; + private static final String PREF_DUMP_PERSONALIZATION_DICT = "dump_personalization_dict"; + public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview"; + public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; + private static final boolean SHOW_STATISTICS_LOGGING = false; private boolean mServiceNeedsRestart = false; @@ -85,11 +101,65 @@ public final class DebugSettings extends PreferenceFragment }); } + final OnPreferenceClickListener dictDumpPrefClickListener = + new DictDumpPrefClickListener(this); + findPreference(PREF_DUMP_CONTACTS_DICT).setOnPreferenceClickListener( + dictDumpPrefClickListener); + findPreference(PREF_DUMP_USER_DICT).setOnPreferenceClickListener( + dictDumpPrefClickListener); + findPreference(PREF_DUMP_USER_HISTORY_DICT).setOnPreferenceClickListener( + dictDumpPrefClickListener); + findPreference(PREF_DUMP_PERSONALIZATION_DICT).setOnPreferenceClickListener( + dictDumpPrefClickListener); + final Resources res = getResources(); + setupKeyLongpressTimeoutSettings(prefs, res); + setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_DURATION, + res.getInteger(R.integer.config_key_preview_show_up_duration)); + setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_DISMISS_DURATION, + res.getInteger(R.integer.config_key_preview_dismiss_duration)); + setupKeyPreviewAnimationScale(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, + ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_show_up_start_scale)); + setupKeyPreviewAnimationScale(prefs, res, PREF_KEY_PREVIEW_DISMISS_END_SCALE, + ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_dismiss_end_scale)); + mServiceNeedsRestart = false; mDebugMode = (CheckBoxPreference) findPreference(PREF_DEBUG_MODE); updateDebugMode(); } + private static class DictDumpPrefClickListener implements OnPreferenceClickListener { + final PreferenceFragment mPreferenceFragment; + + public DictDumpPrefClickListener(final PreferenceFragment preferenceFragment) { + mPreferenceFragment = preferenceFragment; + } + + @Override + public boolean onPreferenceClick(final Preference arg0) { + final String dictName; + if (arg0.getKey().equals(PREF_DUMP_CONTACTS_DICT)) { + dictName = Dictionary.TYPE_CONTACTS; + } else if (arg0.getKey().equals(PREF_DUMP_USER_DICT)) { + dictName = Dictionary.TYPE_USER; + } else if (arg0.getKey().equals(PREF_DUMP_USER_HISTORY_DICT)) { + dictName = Dictionary.TYPE_USER_HISTORY; + } else if (arg0.getKey().equals(PREF_DUMP_PERSONALIZATION_DICT)) { + dictName = Dictionary.TYPE_PERSONALIZATION; + } else { + dictName = null; + } + if (dictName != null) { + final Intent intent = + new Intent(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION); + intent.putExtra(DictionaryDumpBroadcastReceiver.DICTIONARY_NAME_KEY, dictName); + mPreferenceFragment.getActivity().sendBroadcast(intent); + } + return true; + } + } + @Override public void onStop() { super.onStop(); @@ -112,8 +182,7 @@ public final class DebugSettings extends PreferenceFragment updateDebugMode(); mServiceNeedsRestart = true; } - } else if (key.equals(PREF_FORCE_NON_DISTINCT_MULTITOUCH) - || key.equals(PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG)) { + } else if (key.equals(PREF_FORCE_NON_DISTINCT_MULTITOUCH)) { mServiceNeedsRestart = true; } } @@ -133,4 +202,130 @@ public final class DebugSettings extends PreferenceFragment mDebugMode.setSummary(version); } } + + private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp, + final Resources res) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( + PREF_KEY_LONGPRESS_TIMEOUT); + if (pref == null) { + return; + } + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { + @Override + public void writeValue(final int value, final String key) { + sp.edit().putInt(key, value).apply(); + } + + @Override + public void writeDefaultValue(final String key) { + sp.edit().remove(key).apply(); + } + + @Override + public int readValue(final String key) { + return Settings.readKeyLongpressTimeout(sp, res); + } + + @Override + public int readDefaultValue(final String key) { + return Settings.readDefaultKeyLongpressTimeout(res); + } + + @Override + public String getValueText(final int value) { + return res.getString(R.string.abbreviation_unit_milliseconds, value); + } + + @Override + public void feedbackValue(final int value) {} + }); + } + + private void setupKeyPreviewAnimationScale(final SharedPreferences sp, final Resources res, + final String prefKey, final float defaultValue) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey); + if (pref == null) { + return; + } + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { + private static final float PERCENTAGE_FLOAT = 100.0f; + + private float getValueFromPercentage(final int percentage) { + return percentage / PERCENTAGE_FLOAT; + } + + private int getPercentageFromValue(final float floatValue) { + return (int)(floatValue * PERCENTAGE_FLOAT); + } + + @Override + public void writeValue(final int value, final String key) { + sp.edit().putFloat(key, getValueFromPercentage(value)).apply(); + } + + @Override + public void writeDefaultValue(final String key) { + sp.edit().remove(key).apply(); + } + + @Override + public int readValue(final String key) { + return getPercentageFromValue( + Settings.readKeyPreviewAnimationScale(sp, key, defaultValue)); + } + + @Override + public int readDefaultValue(final String key) { + return getPercentageFromValue(defaultValue); + } + + @Override + public String getValueText(final int value) { + if (value < 0) { + return res.getString(R.string.settings_system_default); + } + return String.format("%d%%", value); + } + + @Override + public void feedbackValue(final int value) {} + }); + } + + private void setupKeyPreviewAnimationDuration(final SharedPreferences sp, final Resources res, + final String prefKey, final int defaultValue) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey); + if (pref == null) { + return; + } + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { + @Override + public void writeValue(final int value, final String key) { + sp.edit().putInt(key, value).apply(); + } + + @Override + public void writeDefaultValue(final String key) { + sp.edit().remove(key).apply(); + } + + @Override + public int readValue(final String key) { + return Settings.readKeyPreviewAnimationDuration(sp, key, defaultValue); + } + + @Override + public int readDefaultValue(final String key) { + return defaultValue; + } + + @Override + public String getValueText(final int value) { + return res.getString(R.string.abbreviation_unit_milliseconds, value); + } + + @Override + public void feedbackValue(final int value) {} + }); + } } diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index df2c6907f..a3aae8cb3 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -27,13 +27,13 @@ import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; -import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.StringUtils; -import java.util.HashMap; +import java.util.Collections; import java.util.Locale; +import java.util.Set; import java.util.concurrent.locks.ReentrantLock; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -53,10 +53,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; 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_LAST_USER_DICTIONARY_WRITE_TIME = - "last_user_dictionary_write_time"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; + public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "pref_key_use_personalized_dicts"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = "pref_key_use_double_space_period"; public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE = @@ -67,13 +66,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang "pref_include_other_imes_in_language_switch_list"; public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916"; public static final String PREF_CUSTOM_INPUT_STYLES = "custom_input_styles"; + // TODO: consolidate key preview dismiss delay with the key preview animation parameters. public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; public static final String PREF_GESTURE_SETTINGS = "gesture_typing_settings"; public static final String PREF_GESTURE_INPUT = "gesture_input"; - public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview"; - public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; public static final String PREF_KEYPRESS_SOUND_VOLUME = @@ -96,6 +94,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang private static final String PREF_LAST_USED_PERSONALIZATION_TOKEN = "pref_last_used_personalization_token"; + private static final String PREF_LAST_PERSONALIZATION_DICT_WIPED_TIME = + "pref_last_used_personalization_dict_wiped_time"; + private static final String PREF_CORPUS_HANDLES_FOR_PERSONALIZATION = + "pref_corpus_handles_for_personalization"; public static final String PREF_SEND_FEEDBACK = "send_feedback"; public static final String PREF_ABOUT_KEYBOARD = "about_keyboard"; @@ -104,6 +106,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id"; public static final String PREF_LAST_SHOWN_EMOJI_CATEGORY_ID = "last_shown_emoji_category_id"; + private static final float UNDEFINED_PREFERENCE_VALUE_FLOAT = -1.0f; + private static final int UNDEFINED_PREFERENCE_VALUE_INT = -1; + + private Context mContext; private Resources mRes; private SharedPreferences mPrefs; private SettingsValues mSettingsValues; @@ -124,6 +130,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang } private void onCreate(final Context context) { + mContext = context; mRes = context.getResources(); mPrefs = PreferenceManager.getDefaultSharedPreferences(context); mPrefs.registerOnSharedPreferenceChangeListener(this); @@ -143,20 +150,22 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang Log.w(TAG, "onSharedPreferenceChanged called before loadSettings."); return; } - loadSettings(mSettingsValues.mLocale, mSettingsValues.mInputAttributes); + loadSettings(mContext, mSettingsValues.mLocale, mSettingsValues.mInputAttributes); } finally { mSettingsValuesLock.unlock(); } } - public void loadSettings(final Locale locale, final InputAttributes inputAttributes) { + public void loadSettings(final Context context, final Locale locale, + final InputAttributes inputAttributes) { mSettingsValuesLock.lock(); + mContext = context; try { final SharedPreferences prefs = mPrefs; final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { @Override protected SettingsValues job(final Resources res) { - return new SettingsValues(prefs, locale, res, inputAttributes); + return new SettingsValues(context, prefs, res, inputAttributes); } }; mSettingsValues = job.runInLocale(mRes, locale); @@ -174,10 +183,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mSettingsValues.mIsInternal; } - public String getWordSeparators() { - return mSettingsValues.mWordSeparators; - } - public boolean isWordSeparator(final int code) { return mSettingsValues.isWordSeparator(code); } @@ -189,7 +194,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang // Accessed from the settings interface, hence public public static boolean readKeypressSoundEnabled(final SharedPreferences prefs, final Resources res) { - return prefs.getBoolean(Settings.PREF_SOUND_ON, + return prefs.getBoolean(PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); } @@ -209,7 +214,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs, final Resources res) { - return prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE, + return prefs.getBoolean(PREF_BLOCK_POTENTIALLY_OFFENSIVE, res.getBoolean(R.bool.config_block_potentially_offensive)); } @@ -220,25 +225,24 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static boolean readGestureInputEnabled(final SharedPreferences prefs, final Resources res) { return readFromBuildConfigIfGestureInputEnabled(res) - && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true); + && prefs.getBoolean(PREF_GESTURE_INPUT, true); } public static boolean readPhraseGestureEnabled(final SharedPreferences prefs, final Resources res) { - return prefs.getBoolean(Settings.PREF_PHRASE_GESTURE_ENABLED, + return prefs.getBoolean(PREF_PHRASE_GESTURE_ENABLED, res.getBoolean(R.bool.config_default_phrase_gesture_enabled)); } - public static boolean readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption( - final Resources res) { - return res.getBoolean(R.bool.config_enable_show_option_of_key_preview_popup); + public static boolean readFromBuildConfigIfToShowKeyPreviewPopupOption(final Resources res) { + return res.getBoolean(R.bool.config_enable_show_key_preview_popup_option); } public static boolean readKeyPreviewPopupEnabled(final SharedPreferences prefs, final Resources res) { final boolean defaultKeyPreviewPopup = res.getBoolean( R.bool.config_default_key_preview_popup); - if (!readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(res)) { + if (!readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) { return defaultKeyPreviewPopup; } return prefs.getBoolean(PREF_POPUP_ON, defaultKeyPreviewPopup); @@ -263,28 +267,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return prefs.getBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, true); } - public static int readKeyboardThemeIndex(final SharedPreferences prefs, final Resources res) { - final String defaultThemeIndex = res.getString( - R.string.config_default_keyboard_theme_index); - final String themeIndex = prefs.getString(PREF_KEYBOARD_LAYOUT, defaultThemeIndex); - try { - return Integer.valueOf(themeIndex); - } catch (final NumberFormatException e) { - // Format error, returns default keyboard theme index. - Log.e(TAG, "Illegal keyboard theme in preference: " + themeIndex + ", default to " - + defaultThemeIndex, e); - return Integer.valueOf(defaultThemeIndex); - } - } - - public static int resetAndGetDefaultKeyboardThemeIndex(final SharedPreferences prefs, - final Resources res) { - final String defaultThemeIndex = res.getString( - R.string.config_default_keyboard_theme_index); - prefs.edit().putString(PREF_KEYBOARD_LAYOUT, defaultThemeIndex).apply(); - return Integer.valueOf(defaultThemeIndex); - } - public static String readPrefAdditionalSubtypes(final SharedPreferences prefs, final Resources res) { final String predefinedPrefSubtypes = AdditionalSubtypeUtils.createPrefSubtypes( @@ -294,24 +276,32 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static void writePrefAdditionalSubtypes(final SharedPreferences prefs, final String prefSubtypes) { - prefs.edit().putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply(); + prefs.edit().putString(PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply(); } public static float readKeypressSoundVolume(final SharedPreferences prefs, final Resources res) { - final float volume = prefs.getFloat(PREF_KEYPRESS_SOUND_VOLUME, -1.0f); - return (volume >= 0) ? volume : readDefaultKeypressSoundVolume(res); + final float volume = prefs.getFloat( + PREF_KEYPRESS_SOUND_VOLUME, UNDEFINED_PREFERENCE_VALUE_FLOAT); + return (volume != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? volume + : readDefaultKeypressSoundVolume(res); } + // Default keypress sound volume for unknown devices. + // The negative value means system default. + private static final String DEFAULT_KEYPRESS_SOUND_VOLUME = Float.toString(-1.0f); + public static float readDefaultKeypressSoundVolume(final Resources res) { - return Float.parseFloat( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); + return Float.parseFloat(ResourceUtils.getDeviceOverrideValue(res, + R.array.keypress_volumes, DEFAULT_KEYPRESS_SOUND_VOLUME)); } public static int readKeyLongpressTimeout(final SharedPreferences prefs, final Resources res) { - final int ms = prefs.getInt(PREF_KEY_LONGPRESS_TIMEOUT, -1); - return (ms >= 0) ? ms : readDefaultKeyLongpressTimeout(res); + final int milliseconds = prefs.getInt( + DebugSettings.PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT); + return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds + : readDefaultKeyLongpressTimeout(res); } public static int readDefaultKeyLongpressTimeout(final Resources res) { @@ -320,36 +310,35 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static int readKeypressVibrationDuration(final SharedPreferences prefs, final Resources res) { - final int ms = prefs.getInt(PREF_VIBRATION_DURATION_SETTINGS, -1); - return (ms >= 0) ? ms : readDefaultKeypressVibrationDuration(res); + final int milliseconds = prefs.getInt( + PREF_VIBRATION_DURATION_SETTINGS, UNDEFINED_PREFERENCE_VALUE_INT); + return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds + : readDefaultKeypressVibrationDuration(res); } + // Default keypress vibration duration for unknown devices. + // The negative value means system default. + private static final String DEFAULT_KEYPRESS_VIBRATION_DURATION = Integer.toString(-1); + public static int readDefaultKeypressVibrationDuration(final Resources res) { - return Integer.parseInt( - ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); + return Integer.parseInt(ResourceUtils.getDeviceOverrideValue(res, + R.array.keypress_vibration_durations, DEFAULT_KEYPRESS_VIBRATION_DURATION)); } public static boolean readUsabilityStudyMode(final SharedPreferences prefs) { return prefs.getBoolean(DebugSettings.PREF_USABILITY_STUDY_MODE, true); } - public static long readLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String str = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); - if (map.containsKey(locale)) { - return map.get(locale); - } - return 0; + public static float readKeyPreviewAnimationScale(final SharedPreferences prefs, + final String prefKey, final float defaultValue) { + final float fraction = prefs.getFloat(prefKey, UNDEFINED_PREFERENCE_VALUE_FLOAT); + return (fraction != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? fraction : defaultValue; } - public static void writeLastUserHistoryWriteTime(final SharedPreferences prefs, - final String locale) { - final String oldStr = prefs.getString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); - final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); - map.put(locale, System.currentTimeMillis()); - final String newStr = LocaleUtils.localeAndTimeHashMapToStr(map); - prefs.edit().putString(PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + public static int readKeyPreviewAnimationDuration(final SharedPreferences prefs, + final String prefKey, final int defaultValue) { + final int milliseconds = prefs.getInt(prefKey, UNDEFINED_PREFERENCE_VALUE_INT); + return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds : defaultValue; } public static boolean readUseFullscreenMode(final Resources res) { @@ -363,35 +352,27 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang if (!enableSetupWizardByConfig) { return false; } - if (!prefs.contains(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) { + if (!prefs.contains(PREF_SHOW_SETUP_WIZARD_ICON)) { final ApplicationInfo appInfo = context.getApplicationInfo(); final boolean isApplicationInSystemImage = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; // Default value return !isApplicationInSystemImage; } - return prefs.getBoolean(Settings.PREF_SHOW_SETUP_WIZARD_ICON, false); + return prefs.getBoolean(PREF_SHOW_SETUP_WIZARD_ICON, false); } public static boolean isInternal(final SharedPreferences prefs) { - return prefs.getBoolean(Settings.PREF_KEY_IS_INTERNAL, false); - } - - public static boolean readUseOnlyPersonalizationDictionaryForDebug( - final SharedPreferences prefs) { - return prefs.getBoolean( - DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); - } - - public static boolean readBoostPersonalizationDictionaryForDebug( - final SharedPreferences prefs) { - return prefs.getBoolean( - DebugSettings.PREF_BOOST_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); + return prefs.getBoolean(PREF_KEY_IS_INTERNAL, false); } public void writeLastUsedPersonalizationToken(byte[] token) { - final String tokenStr = StringUtils.byteArrayToHexString(token); - mPrefs.edit().putString(PREF_LAST_USED_PERSONALIZATION_TOKEN, tokenStr).apply(); + if (token == null) { + mPrefs.edit().remove(PREF_LAST_USED_PERSONALIZATION_TOKEN).apply(); + } else { + final String tokenStr = StringUtils.byteArrayToHexString(token); + mPrefs.edit().putString(PREF_LAST_USED_PERSONALIZATION_TOKEN, tokenStr).apply(); + } } public byte[] readLastUsedPersonalizationToken() { @@ -399,6 +380,23 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return StringUtils.hexStringToByteArray(tokenStr); } + public void writeLastPersonalizationDictWipedTime(final long timestamp) { + mPrefs.edit().putLong(PREF_LAST_PERSONALIZATION_DICT_WIPED_TIME, timestamp).apply(); + } + + public long readLastPersonalizationDictGeneratedTime() { + return mPrefs.getLong(PREF_LAST_PERSONALIZATION_DICT_WIPED_TIME, 0); + } + + public void writeCorpusHandlesForPersonalization(final Set<String> corpusHandles) { + mPrefs.edit().putStringSet(PREF_CORPUS_HANDLES_FOR_PERSONALIZATION, corpusHandles).apply(); + } + + public Set<String> readCorpusHandlesForPersonalization() { + final Set<String> emptySet = Collections.emptySet(); + return mPrefs.getStringSet(PREF_CORPUS_HANDLES_FOR_PERSONALIZATION, emptySet); + } + public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) { prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply(); } diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java index 5c60a7350..22cbd204c 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java @@ -48,7 +48,6 @@ import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.FeedbackUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; -import com.android.inputmethod.research.ResearchLogger; import com.android.inputmethodcommon.InputMethodSettingsFragment; import java.util.TreeSet; @@ -61,13 +60,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS || Build.VERSION.SDK_INT <= 18 /* Build.VERSION.JELLY_BEAN_MR2 */; - private CheckBoxPreference mVoiceInputKeyPreference; - private ListPreference mShowCorrectionSuggestionsPreference; - private ListPreference mAutoCorrectionThresholdPreference; - private ListPreference mKeyPreviewPopupDismissDelay; - // Use bigrams to predict the next word when there is no input for it yet - private CheckBoxPreference mBigramPrediction; - private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { final Preference preference = findPreference(preferenceKey); if (preference != null) { @@ -75,6 +67,18 @@ public final class SettingsFragment extends InputMethodSettingsFragment } } + private void updateListPreferenceSummaryToCurrentValue(final String prefKey) { + // Because the "%s" summary trick of {@link ListPreference} doesn't work properly before + // KitKat, we need to update the summary programmatically. + final ListPreference listPreference = (ListPreference)findPreference(prefKey); + if (listPreference == null) { + return; + } + final CharSequence entries[] = listPreference.getEntries(); + final int entryIndex = listPreference.findIndexOfValue(listPreference.getValue()); + listPreference.setSummary(entryIndex < 0 ? null : entries[entryIndex]); + } + private static void removePreference(final String preferenceKey, final PreferenceGroup parent) { if (parent == null) { return; @@ -94,7 +98,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment final PreferenceScreen preferenceScreen = getPreferenceScreen(); if (preferenceScreen != null) { preferenceScreen.setTitle( - ApplicationUtils.getAcitivityTitleResId(getActivity(), SettingsActivity.class)); + ApplicationUtils.getActivityTitleResId(getActivity(), SettingsActivity.class)); } final Resources res = getResources(); @@ -107,16 +111,9 @@ public final class SettingsFragment extends InputMethodSettingsFragment SubtypeLocaleUtils.init(context); AudioAndHapticFeedbackManager.init(context); - mVoiceInputKeyPreference = - (CheckBoxPreference) findPreference(Settings.PREF_VOICE_INPUT_KEY); - mShowCorrectionSuggestionsPreference = - (ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING); final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); prefs.registerOnSharedPreferenceChangeListener(this); - mAutoCorrectionThresholdPreference = - (ListPreference) findPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD); - mBigramPrediction = (CheckBoxPreference) findPreference(Settings.PREF_BIGRAM_PREDICTIONS); ensureConsistencyOfAutoCorrectionSettings(); final PreferenceGroup generalSettings = @@ -143,12 +140,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment feedbackSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference pref) { - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - // Use development-only feedback mechanism - ResearchLogger.getInstance().presentFeedbackDialogFromSettings(); - } else { - FeedbackUtils.showFeedbackForm(getActivity()); - } + FeedbackUtils.showFeedbackForm(getActivity()); return true; } }); @@ -167,7 +159,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { - generalSettings.removePreference(mVoiceInputKeyPreference); + removePreference(Settings.PREF_VOICE_INPUT_KEY, generalSettings); } final PreferenceGroup advancedSettings = @@ -177,26 +169,28 @@ public final class SettingsFragment extends InputMethodSettingsFragment removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedSettings); } - mKeyPreviewPopupDismissDelay = - (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); - if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(res)) { + // TODO: consolidate key preview dismiss delay with the key preview animation parameters. + if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) { removePreference(Settings.PREF_POPUP_ON, generalSettings); removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedSettings); } else { + // TODO: Cleanup this setup. + final ListPreference keyPreviewPopupDismissDelay = + (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( R.integer.config_key_preview_linger_timeout)); - mKeyPreviewPopupDismissDelay.setEntries(new String[] { + keyPreviewPopupDismissDelay.setEntries(new String[] { res.getString(R.string.key_preview_popup_dismiss_no_delay), res.getString(R.string.key_preview_popup_dismiss_default_delay), }); - mKeyPreviewPopupDismissDelay.setEntryValues(new String[] { + keyPreviewPopupDismissDelay.setEntryValues(new String[] { "0", popupDismissDelayDefaultValue }); - if (null == mKeyPreviewPopupDismissDelay.getValue()) { - mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); + if (null == keyPreviewPopupDismissDelay.getValue()) { + keyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } - mKeyPreviewPopupDismissDelay.setEnabled( + keyPreviewPopupDismissDelay.setEnabled( Settings.readKeyPreviewPopupEnabled(prefs, res)); } @@ -234,7 +228,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this); - setupKeyLongpressTimeoutSettings(prefs, res); setupKeypressVibrationDurationSettings(prefs, res); setupKeypressSoundVolumeSettings(prefs, res); refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); @@ -243,20 +236,25 @@ public final class SettingsFragment extends InputMethodSettingsFragment @Override public void onResume() { super.onResume(); - final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - if (!isShortcutImeEnabled) { - getPreferenceScreen().removePreference(mVoiceInputKeyPreference); - } final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + final Resources res = getResources(); + final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY); + if (voiceInputKeyOption != null) { + final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance() + .isShortcutImeEnabled(); + voiceInputKeyOption.setEnabled(isShortcutImeEnabled); + voiceInputKeyOption.setSummary(isShortcutImeEnabled ? null + : res.getText(R.string.voice_input_disabled_summary)); + } final CheckBoxPreference showSetupWizardIcon = (CheckBoxPreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON); if (showSetupWizardIcon != null) { showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity())); } - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - updateColorSchemeSummary(prefs, getResources()); - updateCustomInputStylesSummary(); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_SHOW_SUGGESTIONS_SETTING); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_LAYOUT); + updateCustomInputStylesSummary(prefs, res); } @Override @@ -287,50 +285,26 @@ public final class SettingsFragment extends InputMethodSettingsFragment LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity()); } ensureConsistencyOfAutoCorrectionSettings(); - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - updateColorSchemeSummary(prefs, res); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_SHOW_SUGGESTIONS_SETTING); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_LAYOUT); refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); } private void ensureConsistencyOfAutoCorrectionSettings() { final String autoCorrectionOff = getResources().getString( R.string.auto_correction_threshold_mode_index_off); - final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); - mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); - } - - private void updateShowCorrectionSuggestionsSummary() { - mShowCorrectionSuggestionsPreference.setSummary( - getResources().getStringArray(R.array.prefs_suggestion_visibilities) - [mShowCorrectionSuggestionsPreference.findIndexOfValue( - mShowCorrectionSuggestionsPreference.getValue())]); - } - - private void updateColorSchemeSummary(final SharedPreferences prefs, final Resources res) { - // Because the "%s" summary trick of {@link ListPreference} doesn't work properly before - // KitKat, we need to update the summary by code. - final Preference preference = findPreference(Settings.PREF_KEYBOARD_LAYOUT); - if (!(preference instanceof ListPreference)) { - Log.w(TAG, "Can't find Keyboard Color Scheme preference"); - return; - } - final ListPreference colorSchemePreference = (ListPreference)preference; - final int themeIndex = Settings.readKeyboardThemeIndex(prefs, res); - int entryIndex = colorSchemePreference.findIndexOfValue(Integer.toString(themeIndex)); - if (entryIndex < 0) { - final int defaultThemeIndex = Settings.resetAndGetDefaultKeyboardThemeIndex(prefs, res); - entryIndex = colorSchemePreference.findIndexOfValue( - Integer.toString(defaultThemeIndex)); - } - colorSchemePreference.setSummary(colorSchemePreference.getEntries()[entryIndex]); + final ListPreference autoCorrectionThresholdPref = (ListPreference)findPreference( + Settings.PREF_AUTO_CORRECTION_THRESHOLD); + final String currentSetting = autoCorrectionThresholdPref.getValue(); + setPreferenceEnabled( + Settings.PREF_BIGRAM_PREDICTIONS, !currentSetting.equals(autoCorrectionOff)); } - private void updateCustomInputStylesSummary() { + private void updateCustomInputStylesSummary(final SharedPreferences prefs, + final Resources res) { final PreferenceScreen customInputStyles = (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); - final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - final Resources res = getResources(); final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res); final InputMethodSubtype[] subtypes = AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype); @@ -342,13 +316,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment customInputStyles.setSummary(styles); } - private void updateKeyPreviewPopupDelaySummary() { - final ListPreference lp = mKeyPreviewPopupDismissDelay; - final CharSequence[] entries = lp.getEntries(); - if (entries == null || entries.length <= 0) return; - lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); - } - private void refreshEnablingsOfKeypressSoundAndVibrationSettings( final SharedPreferences sp, final Resources res) { setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS, @@ -400,44 +367,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment }); } - private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp, - final Resources res) { - final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( - Settings.PREF_KEY_LONGPRESS_TIMEOUT); - if (pref == null) { - return; - } - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - @Override - public void writeValue(final int value, final String key) { - sp.edit().putInt(key, value).apply(); - } - - @Override - public void writeDefaultValue(final String key) { - sp.edit().remove(key).apply(); - } - - @Override - public int readValue(final String key) { - return Settings.readKeyLongpressTimeout(sp, res); - } - - @Override - public int readDefaultValue(final String key) { - return Settings.readDefaultKeyLongpressTimeout(res); - } - - @Override - public String getValueText(final int value) { - return res.getString(R.string.abbreviation_unit_milliseconds, value); - } - - @Override - public void feedbackValue(final int value) {} - }); - } - private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) { final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( Settings.PREF_KEYPRESS_SOUND_VOLUME); diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index f331c78e5..dde50ccaf 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -16,27 +16,22 @@ package com.android.inputmethod.latin.settings; +import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.PackageInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.util.Log; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.keyboard.internal.KeySpecParser; -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.compat.AppWorkaroundsUtils; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.InputTypeUtils; -import com.android.inputmethod.latin.utils.StringUtils; - -import java.util.ArrayList; +import com.android.inputmethod.latin.utils.AsyncResultHolder; +import com.android.inputmethod.latin.utils.ResourceUtils; +import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; + import java.util.Arrays; import java.util.Locale; @@ -50,27 +45,23 @@ public final class SettingsValues { // Float.NEGATIVE_INFINITE and Float.MAX_VALUE. Currently used for auto-correction settings. private static final String FLOAT_MAX_VALUE_MARKER_STRING = "floatMaxValue"; private static final String FLOAT_NEGATIVE_INFINITY_MARKER_STRING = "floatNegativeInfinity"; + private static final int TIMEOUT_TO_GET_TARGET_PACKAGE = 5; // seconds // From resources: + public final SpacingAndPunctuations mSpacingAndPunctuations; public final int mDelayUpdateOldSuggestions; - public final int[] mSymbolsPrecededBySpace; - public final int[] mSymbolsFollowedBySpace; - public final int[] mWordConnectors; - public final SuggestedWords mSuggestPuncList; - public final String mWordSeparators; - public final int mSentenceSeparator; - public final CharSequence mHintToSaveText; - public final boolean mCurrentLanguageHasSpaces; + public final long mDoubleSpacePeriodTimeout; // 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 mShowsVoiceInputKey; + public final boolean mShowsVoiceInputKey; public final boolean mIncludesOtherImesInLanguageSwitchList; public final boolean mShowsLanguageSwitchKey; public final boolean mUseContactsDict; + public final boolean mUsePersonalizedDicts; public final boolean mUseDoubleSpacePeriod; public final boolean mBlockPotentiallyOffensive; // Use bigrams to predict the next word when there is no input for it yet @@ -94,8 +85,8 @@ public final class SettingsValues { public final float mAutoCorrectionThreshold; public final boolean mCorrectionEnabled; public final int mSuggestionVisibility; - public final boolean mBoostPersonalizationDictionaryForDebug; - public final boolean mUseOnlyPersonalizationDictionaryForDebug; + public final int mDisplayOrientation; + private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds; // Setting values for additional features public final int[] mAdditionalFeaturesSettingValues = @@ -103,28 +94,17 @@ public final class SettingsValues { // Debug settings public final boolean mIsInternal; + public final int mKeyPreviewShowUpDuration; + public final int mKeyPreviewDismissDuration; + public final float mKeyPreviewShowUpStartScale; + public final float mKeyPreviewDismissEndScale; - public SettingsValues(final SharedPreferences prefs, final Locale locale, final Resources res, + public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res, final InputAttributes inputAttributes) { - mLocale = locale; + mLocale = res.getConfiguration().locale; // Get the resources mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); - mSymbolsPrecededBySpace = - StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space)); - Arrays.sort(mSymbolsPrecededBySpace); - mSymbolsFollowedBySpace = - StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space)); - Arrays.sort(mSymbolsFollowedBySpace); - mWordConnectors = - StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors)); - Arrays.sort(mWordConnectors); - final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString( - R.string.suggested_punctuations)); - mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); - mWordSeparators = res.getString(R.string.symbols_word_separators); - mSentenceSeparator = res.getInteger(R.integer.sentence_separator); - mHintToSaveText = res.getText(R.string.hint_add_to_dictionary); - mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces); + mSpacingAndPunctuations = new SpacingAndPunctuations(res); // Store the input attributes if (null == inputAttributes) { @@ -139,7 +119,7 @@ public final class SettingsValues { mSoundOn = Settings.readKeypressSoundEnabled(prefs, res); mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res); mSlidingKeyInputPreviewEnabled = prefs.getBoolean( - Settings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); + DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res); final String autoCorrectionThresholdRawValue = prefs.getString( Settings.PREF_AUTO_CORRECTION_THRESHOLD, @@ -148,10 +128,12 @@ public final class SettingsValues { Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); + mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); + mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout); // Compute other readable settings mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); @@ -173,86 +155,53 @@ public final class SettingsValues { AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray( prefs, mAdditionalFeaturesSettingValues); mIsInternal = Settings.isInternal(prefs); - mBoostPersonalizationDictionaryForDebug = - Settings.readBoostPersonalizationDictionaryForDebug(prefs); - mUseOnlyPersonalizationDictionaryForDebug = - Settings.readUseOnlyPersonalizationDictionaryForDebug(prefs); - } - - // Only for tests - private SettingsValues(final Locale locale) { - // TODO: locale is saved, but not used yet. May have to change this if tests require. - mLocale = locale; - mDelayUpdateOldSuggestions = 0; - mSymbolsPrecededBySpace = new int[] { '(', '[', '{', '&' }; - Arrays.sort(mSymbolsPrecededBySpace); - mSymbolsFollowedBySpace = new int[] { '.', ',', ';', ':', '!', '?', ')', ']', '}', '&' }; - Arrays.sort(mSymbolsFollowedBySpace); - mWordConnectors = new int[] { '\'', '-' }; - Arrays.sort(mWordConnectors); - mSentenceSeparator = Constants.CODE_PERIOD; - final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" }; - mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); - mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\""; - mHintToSaveText = "Touch again to save"; - mCurrentLanguageHasSpaces = true; - mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); - mAutoCap = true; - mVibrateOn = true; - mSoundOn = true; - mKeyPreviewPopupOn = true; - mSlidingKeyInputPreviewEnabled = true; - mShowsVoiceInputKey = true; - mIncludesOtherImesInLanguageSwitchList = false; - mShowsLanguageSwitchKey = true; - mUseContactsDict = true; - mUseDoubleSpacePeriod = true; - mBlockPotentiallyOffensive = true; - mAutoCorrectEnabled = true; - mBigramPredictionEnabled = true; - mKeyLongpressTimeout = 300; - mKeypressVibrationDuration = 5; - mKeypressSoundVolume = 1; - mKeyPreviewPopupDismissDelay = 70; - mAutoCorrectionThreshold = 1; - mGestureInputEnabled = true; - mGestureTrailEnabled = true; - mGestureFloatingPreviewTextEnabled = true; - mPhraseGestureEnabled = true; - mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; - mSuggestionVisibility = 0; - mIsInternal = false; - mBoostPersonalizationDictionaryForDebug = false; - mUseOnlyPersonalizationDictionaryForDebug = false; - } - - @UsedForTesting - public static SettingsValues makeDummySettingsValuesForTest(final Locale locale) { - return new SettingsValues(locale); + mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration( + prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION, + res.getInteger(R.integer.config_key_preview_show_up_duration)); + mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration( + prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, + res.getInteger(R.integer.config_key_preview_dismiss_duration)); + mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE, + ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_show_up_start_scale)); + mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale( + prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, + ResourceUtils.getFloatFromFraction( + res, R.fraction.config_key_preview_dismiss_end_scale)); + mDisplayOrientation = res.getConfiguration().orientation; + mAppWorkarounds = new AsyncResultHolder<AppWorkaroundsUtils>(); + final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( + mInputAttributes.mTargetApplicationPackageName); + if (null != packageInfo) { + mAppWorkarounds.set(new AppWorkaroundsUtils(packageInfo)); + } else { + new TargetPackageInfoGetterTask(context, mAppWorkarounds) + .execute(mInputAttributes.mTargetApplicationPackageName); + } } public boolean isApplicationSpecifiedCompletionsOn() { return mInputAttributes.mApplicationSpecifiedCompletionOn; } - public boolean isSuggestionsRequested(final int displayOrientation) { + public boolean isSuggestionsRequested() { return mInputAttributes.mIsSettingsSuggestionStripOn - && (mCorrectionEnabled - || isSuggestionStripVisibleInOrientation(displayOrientation)); + && (mCorrectionEnabled || isSuggestionStripVisible()); } - public boolean isSuggestionStripVisibleInOrientation(final int orientation) { + public boolean isSuggestionStripVisible() { return (mSuggestionVisibility == SUGGESTION_VISIBILITY_SHOW_VALUE) || (mSuggestionVisibility == SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE - && orientation == Configuration.ORIENTATION_PORTRAIT); + && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT); } public boolean isWordSeparator(final int code) { - return mWordSeparators.contains(String.valueOf((char)code)); + return mSpacingAndPunctuations.isWordSeparator(code); } public boolean isWordConnector(final int code) { - return Arrays.binarySearch(mWordConnectors, code) >= 0; + return mSpacingAndPunctuations.isWordConnector(code); } public boolean isWordCodePoint(final int code) { @@ -260,24 +209,17 @@ public final class SettingsValues { } public boolean isUsuallyPrecededBySpace(final int code) { - return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0; + return mSpacingAndPunctuations.isUsuallyPrecededBySpace(code); } public boolean isUsuallyFollowedBySpace(final int code) { - return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0; + return mSpacingAndPunctuations.isUsuallyFollowedBySpace(code); } public boolean shouldInsertSpacesAutomatically() { return mInputAttributes.mShouldInsertSpacesAutomatically; } - public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) { - final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; - return shortcutImeEnabled && mShowsVoiceInputKey - && !InputTypeUtils.isPasswordInputType(inputType); - } - public boolean isLanguageSwitchKeyEnabled() { if (!mShowsLanguageSwitchKey) { return false; @@ -294,25 +236,20 @@ public final class SettingsValues { return mInputAttributes.isSameInputType(editorInfo); } - // Helper functions to create member values. - private static SuggestedWords createSuggestPuncList(final String[] puncs) { - final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList(); - if (puncs != null) { - for (final String puncSpec : puncs) { - // TODO: Stop using KeySpceParser.getLabel(). - puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, - Dictionary.DICTIONARY_HARDCODED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); - } - } - return new SuggestedWords(puncList, - false /* typedWordValid */, - false /* hasAutoCorrectionCandidate */, - true /* isPunctuationSuggestions */, - false /* isObsoleteSuggestions */, - false /* isPrediction */); + public boolean hasSameOrientation(final Configuration configuration) { + return mDisplayOrientation == configuration.orientation; + } + + public boolean isBeforeJellyBean() { + final AppWorkaroundsUtils appWorkaroundUtils + = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); + return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBeforeJellyBean(); + } + + public boolean isBrokenByRecorrection() { + final AppWorkaroundsUtils appWorkaroundUtils + = mAppWorkarounds.get(null, TIMEOUT_TO_GET_TARGET_PACKAGE); + return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection(); } private static final int SUGGESTION_VISIBILITY_SHOW_VALUE = @@ -350,7 +287,7 @@ public final class SettingsValues { // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. final float autoCorrectionThreshold; try { - final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); + final int arrayIndex = Integer.parseInt(currentAutoCorrectionSetting); if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { final String val = autoCorrectionThresholdValues[arrayIndex]; if (FLOAT_MAX_VALUE_MARKER_STRING.equals(val)) { @@ -374,17 +311,101 @@ public final class SettingsValues { return autoCorrectionThreshold; } - private static boolean needsToShowVoiceInputKey(SharedPreferences prefs, Resources res) { - final String voiceModeMain = res.getString(R.string.voice_mode_main); - final String voiceMode = prefs.getString(Settings.PREF_VOICE_MODE_OBSOLETE, voiceModeMain); - final boolean showsVoiceInputKey = voiceMode == null || voiceMode.equals(voiceModeMain); - if (!showsVoiceInputKey) { - // Migrate settings from PREF_VOICE_MODE_OBSOLETE to PREF_VOICE_INPUT_KEY - // Set voiceModeMain as a value of obsolete voice mode settings. - prefs.edit().putString(Settings.PREF_VOICE_MODE_OBSOLETE, voiceModeMain).apply(); - // Disable voice input key. - prefs.edit().putBoolean(Settings.PREF_VOICE_INPUT_KEY, false).apply(); + private static boolean needsToShowVoiceInputKey(final SharedPreferences prefs, + final Resources res) { + if (!prefs.contains(Settings.PREF_VOICE_INPUT_KEY)) { + // Migrate preference from {@link Settings#PREF_VOICE_MODE_OBSOLETE} to + // {@link Settings#PREF_VOICE_INPUT_KEY}. + final String voiceModeMain = res.getString(R.string.voice_mode_main); + final String voiceMode = prefs.getString( + Settings.PREF_VOICE_MODE_OBSOLETE, voiceModeMain); + final boolean shouldShowVoiceInputKey = voiceModeMain.equals(voiceMode); + prefs.edit().putBoolean(Settings.PREF_VOICE_INPUT_KEY, shouldShowVoiceInputKey).apply(); + } + // Remove the obsolete preference if exists. + if (prefs.contains(Settings.PREF_VOICE_MODE_OBSOLETE)) { + prefs.edit().remove(Settings.PREF_VOICE_MODE_OBSOLETE).apply(); } return prefs.getBoolean(Settings.PREF_VOICE_INPUT_KEY, true); } + + public String dump() { + final StringBuilder sb = new StringBuilder("Current settings :"); + sb.append("\n mSpacingAndPunctuations = "); + sb.append("" + mSpacingAndPunctuations.dump()); + sb.append("\n mDelayUpdateOldSuggestions = "); + sb.append("" + mDelayUpdateOldSuggestions); + sb.append("\n mAutoCap = "); + sb.append("" + mAutoCap); + sb.append("\n mVibrateOn = "); + sb.append("" + mVibrateOn); + sb.append("\n mSoundOn = "); + sb.append("" + mSoundOn); + sb.append("\n mKeyPreviewPopupOn = "); + sb.append("" + mKeyPreviewPopupOn); + sb.append("\n mShowsVoiceInputKey = "); + sb.append("" + mShowsVoiceInputKey); + sb.append("\n mIncludesOtherImesInLanguageSwitchList = "); + sb.append("" + mIncludesOtherImesInLanguageSwitchList); + sb.append("\n mShowsLanguageSwitchKey = "); + sb.append("" + mShowsLanguageSwitchKey); + sb.append("\n mUseContactsDict = "); + sb.append("" + mUseContactsDict); + sb.append("\n mUsePersonalizedDicts = "); + sb.append("" + mUsePersonalizedDicts); + sb.append("\n mUseDoubleSpacePeriod = "); + sb.append("" + mUseDoubleSpacePeriod); + sb.append("\n mBlockPotentiallyOffensive = "); + sb.append("" + mBlockPotentiallyOffensive); + sb.append("\n mBigramPredictionEnabled = "); + sb.append("" + mBigramPredictionEnabled); + sb.append("\n mGestureInputEnabled = "); + sb.append("" + mGestureInputEnabled); + sb.append("\n mGestureTrailEnabled = "); + sb.append("" + mGestureTrailEnabled); + sb.append("\n mGestureFloatingPreviewTextEnabled = "); + sb.append("" + mGestureFloatingPreviewTextEnabled); + sb.append("\n mSlidingKeyInputPreviewEnabled = "); + sb.append("" + mSlidingKeyInputPreviewEnabled); + sb.append("\n mPhraseGestureEnabled = "); + sb.append("" + mPhraseGestureEnabled); + sb.append("\n mKeyLongpressTimeout = "); + sb.append("" + mKeyLongpressTimeout); + sb.append("\n mLocale = "); + sb.append("" + mLocale); + sb.append("\n mInputAttributes = "); + sb.append("" + mInputAttributes); + sb.append("\n mKeypressVibrationDuration = "); + sb.append("" + mKeypressVibrationDuration); + sb.append("\n mKeypressSoundVolume = "); + sb.append("" + mKeypressSoundVolume); + sb.append("\n mKeyPreviewPopupDismissDelay = "); + sb.append("" + mKeyPreviewPopupDismissDelay); + sb.append("\n mAutoCorrectEnabled = "); + sb.append("" + mAutoCorrectEnabled); + sb.append("\n mAutoCorrectionThreshold = "); + sb.append("" + mAutoCorrectionThreshold); + sb.append("\n mCorrectionEnabled = "); + sb.append("" + mCorrectionEnabled); + sb.append("\n mSuggestionVisibility = "); + sb.append("" + mSuggestionVisibility); + sb.append("\n mDisplayOrientation = "); + sb.append("" + mDisplayOrientation); + sb.append("\n mAppWorkarounds = "); + final AppWorkaroundsUtils awu = mAppWorkarounds.get(null, 0); + sb.append("" + (null == awu ? "null" : awu.toString())); + sb.append("\n mAdditionalFeaturesSettingValues = "); + sb.append("" + Arrays.toString(mAdditionalFeaturesSettingValues)); + sb.append("\n mIsInternal = "); + sb.append("" + mIsInternal); + sb.append("\n mKeyPreviewShowUpDuration = "); + sb.append("" + mKeyPreviewShowUpDuration); + sb.append("\n mKeyPreviewDismissDuration = "); + sb.append("" + mKeyPreviewDismissDuration); + sb.append("\n mKeyPreviewShowUpStartScale = "); + sb.append("" + mKeyPreviewShowUpStartScale); + sb.append("\n mKeyPreviewDismissEndScale = "); + sb.append("" + mKeyPreviewDismissEndScale); + return sb.toString(); + } } diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java new file mode 100644 index 000000000..796921f71 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014 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.settings; + +import android.content.res.Resources; + +import com.android.inputmethod.keyboard.internal.MoreKeySpec; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.PunctuationSuggestions; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.StringUtils; + +import java.util.Arrays; +import java.util.Locale; + +public final class SpacingAndPunctuations { + private final int[] mSortedSymbolsPrecededBySpace; + private final int[] mSortedSymbolsFollowedBySpace; + private final int[] mSortedWordConnectors; + public final int[] mSortedWordSeparators; + public final PunctuationSuggestions mSuggestPuncList; + private final int mSentenceSeparator; + public final String mSentenceSeparatorAndSpace; + public final boolean mCurrentLanguageHasSpaces; + public final boolean mUsesAmericanTypography; + public final boolean mUsesGermanRules; + + public SpacingAndPunctuations(final Resources res) { + // To be able to binary search the code point. See {@link #isUsuallyPrecededBySpace(int)}. + mSortedSymbolsPrecededBySpace = StringUtils.toSortedCodePointArray( + res.getString(R.string.symbols_preceded_by_space)); + // To be able to binary search the code point. See {@link #isUsuallyFollowedBySpace(int)}. + mSortedSymbolsFollowedBySpace = StringUtils.toSortedCodePointArray( + res.getString(R.string.symbols_followed_by_space)); + // To be able to binary search the code point. See {@link #isWordConnector(int)}. + mSortedWordConnectors = StringUtils.toSortedCodePointArray( + res.getString(R.string.symbols_word_connectors)); + mSortedWordSeparators = StringUtils.toSortedCodePointArray( + res.getString(R.string.symbols_word_separators)); + mSentenceSeparator = res.getInteger(R.integer.sentence_separator); + mSentenceSeparatorAndSpace = new String(new int[] { + mSentenceSeparator, Constants.CODE_SPACE }, 0, 2); + mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces); + final Locale locale = res.getConfiguration().locale; + // Heuristic: we use American Typography rules because it's the most common rules for all + // English variants. German rules (not "German typography") also have small gotchas. + mUsesAmericanTypography = Locale.ENGLISH.getLanguage().equals(locale.getLanguage()); + mUsesGermanRules = Locale.GERMAN.getLanguage().equals(locale.getLanguage()); + final String[] suggestPuncsSpec = MoreKeySpec.splitKeySpecs( + res.getString(R.string.suggested_punctuations)); + mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec); + } + + public boolean isWordSeparator(final int code) { + return Arrays.binarySearch(mSortedWordSeparators, code) >= 0; + } + + public boolean isWordConnector(final int code) { + return Arrays.binarySearch(mSortedWordConnectors, code) >= 0; + } + + public boolean isWordCodePoint(final int code) { + return Character.isLetter(code) || isWordConnector(code); + } + + public boolean isUsuallyPrecededBySpace(final int code) { + return Arrays.binarySearch(mSortedSymbolsPrecededBySpace, code) >= 0; + } + + public boolean isUsuallyFollowedBySpace(final int code) { + return Arrays.binarySearch(mSortedSymbolsFollowedBySpace, code) >= 0; + } + + public boolean isSentenceSeparator(final int code) { + return code == mSentenceSeparator; + } + + public String dump() { + final StringBuilder sb = new StringBuilder(); + sb.append("mSortedSymbolsPrecededBySpace = "); + sb.append("" + Arrays.toString(mSortedSymbolsPrecededBySpace)); + sb.append("\n mSortedSymbolsFollowedBySpace = "); + sb.append("" + Arrays.toString(mSortedSymbolsFollowedBySpace)); + sb.append("\n mSortedWordConnectors = "); + sb.append("" + Arrays.toString(mSortedWordConnectors)); + sb.append("\n mSortedWordSeparators = "); + sb.append("" + Arrays.toString(mSortedWordSeparators)); + sb.append("\n mSuggestPuncList = "); + sb.append("" + mSuggestPuncList); + sb.append("\n mSentenceSeparator = "); + sb.append("" + mSentenceSeparator); + sb.append("\n mSentenceSeparatorAndSpace = "); + sb.append("" + mSentenceSeparatorAndSpace); + sb.append("\n mCurrentLanguageHasSpaces = "); + sb.append("" + mCurrentLanguageHasSpaces); + sb.append("\n mUsesAmericanTypography = "); + sb.append("" + mUsesAmericanTypography); + sb.append("\n mUsesGermanRules = "); + sb.append("" + mUsesGermanRules); + return sb.toString(); + } +} diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java index c4a813c24..5072fabd6 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java @@ -38,7 +38,7 @@ import com.android.inputmethod.compat.ViewCompatUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.settings.SettingsActivity; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; import java.util.ArrayList; @@ -74,21 +74,21 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL private SettingsPoolingHandler mHandler; private static final class SettingsPoolingHandler - extends StaticInnerHandlerWrapper<SetupWizardActivity> { + extends LeakGuardHandlerWrapper<SetupWizardActivity> { private static final int MSG_POLLING_IME_SETTINGS = 0; private static final long IME_SETTINGS_POLLING_INTERVAL = 200; private final InputMethodManager mImmInHandler; - public SettingsPoolingHandler(final SetupWizardActivity outerInstance, + public SettingsPoolingHandler(final SetupWizardActivity ownerInstance, final InputMethodManager imm) { - super(outerInstance); + super(ownerInstance); mImmInHandler = imm; } @Override public void handleMessage(final Message msg) { - final SetupWizardActivity setupWizardActivity = getOuterInstance(); + final SetupWizardActivity setupWizardActivity = getOwnerInstance(); if (setupWizardActivity == null) { return; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 503b18b1b..65ebcf5f1 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -33,10 +33,9 @@ import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryCollection; import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary; -import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary; import com.android.inputmethod.latin.UserBinaryDictionary; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.StringUtils; @@ -267,6 +266,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + // Weak <- insertIndex == 0, ..., insertIndex == mLength -> Strong if (insertIndex == 0 && mLength >= mMaxLength) { // In the future, we may want to keep track of the best suggestion score even if // we are asked for 0 suggestions. In this case, we can use the following @@ -284,11 +284,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService // } return true; } - if (insertIndex >= mMaxLength) { - // We found a suggestion, but its score is too weak to be kept considering - // the suggestion limit. - return true; - } final String wordString = new String(word, wordOffset, wordLength); if (mLength < mMaxLength) { @@ -296,12 +291,13 @@ public final class AndroidSpellCheckerService extends SpellCheckerService ++mLength; System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen); mSuggestions.add(insertIndex, wordString); + mScores[insertIndex] = score; } else { - System.arraycopy(mScores, 1, mScores, 0, insertIndex); + System.arraycopy(mScores, 1, mScores, 0, insertIndex - 1); mSuggestions.add(insertIndex, wordString); mSuggestions.remove(0); + mScores[insertIndex - 1] = score; } - mScores[insertIndex] = score; return true; } @@ -320,7 +316,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService hasRecommendedSuggestions = false; } else { gatheredSuggestions = EMPTY_STRING_ARRAY; - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( mOriginalText, mBestSuggestion, mBestScore); hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); } @@ -355,7 +351,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService final int bestScore = mScores[mLength - 1]; final String bestSuggestion = mSuggestions.get(0); final float normalizedScore = - BinaryDictionary.calcNormalizedScore( + BinaryDictionaryUtils.calcNormalizedScore( mOriginalText, bestSuggestion.toString(), bestScore); hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); if (DBG) { @@ -383,6 +379,8 @@ public final class AndroidSpellCheckerService extends SpellCheckerService new Thread("spellchecker_close_dicts") { @Override public void run() { + // Contacts dictionary can be closed multiple times here. If the dictionary is + // already closed, extra closings are no-ops, so it's safe. for (DictionaryPool pool : oldPools.values()) { pool.close(); } @@ -428,7 +426,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService final String localeStr = locale.toString(); UserBinaryDictionary userDictionary = mUserDictionaries.get(localeStr); if (null == userDictionary) { - userDictionary = new SynchronouslyLoadedUserBinaryDictionary(this, localeStr, true); + userDictionary = new SynchronouslyLoadedUserBinaryDictionary(this, locale, true); mUserDictionaries.put(localeStr, userDictionary); } dictionaryCollection.addDictionary(userDictionary); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index d6e5b75ad..69d092751 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -28,11 +28,13 @@ import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer; +import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.StringUtils; @@ -312,16 +314,21 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { false /* reportAsTypo */); } final WordComposer composer = new WordComposer(); - final int length = text.length(); - for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { - final int codePoint = text.codePointAt(i); - composer.addKeyInfo(codePoint, dictInfo.getKeyboard(codePoint)); + final int[] codePoints = StringUtils.toCodePointArray(text); + final int[] coordinates; + if (null == dictInfo.mKeyboard) { + coordinates = CoordinateUtils.newCoordinateArray(codePoints.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } else { + coordinates = dictInfo.mKeyboard.getCoordinates(codePoints); } + composer.setComposingWord(codePoints, coordinates, null /* previousWord */); // TODO: make a spell checker option to block offensive words or not final ArrayList<SuggestedWordInfo> suggestions = dictInfo.mDictionary.getSuggestions(composer, prevWord, dictInfo.getProximityInfo(), true /* blockOffensiveWords */, - null /* additionalFeaturesOptions */); + null /* additionalFeaturesOptions */, + null /* inOutLanguageWeight */); if (suggestions != null) { for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java index b77f3e2c5..1ffe50681 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java @@ -27,7 +27,7 @@ import com.android.inputmethod.keyboard.ProximityInfo; */ public final class DictAndKeyboard { public final Dictionary mDictionary; - private final Keyboard mKeyboard; + public final Keyboard mKeyboard; private final Keyboard mManualShiftedKeyboard; public DictAndKeyboard( @@ -43,13 +43,6 @@ public final class DictAndKeyboard { keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED); } - public Keyboard getKeyboard(final int codePoint) { - if (mKeyboard == null) { - return null; - } - return mKeyboard.getKey(codePoint) != null ? mKeyboard : mManualShiftedKeyboard; - } - public ProximityInfo getProximityInfo() { return mKeyboard == null ? null : mKeyboard.getProximityInfo(); } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java index a0aed2829..c99264347 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java @@ -49,10 +49,12 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> { final static ArrayList<SuggestedWordInfo> noSuggestions = CollectionUtils.newArrayList(); private final static DictAndKeyboard dummyDict = new DictAndKeyboard( new Dictionary(Dictionary.TYPE_MAIN) { + // TODO: this dummy dictionary should be a singleton in the Dictionary class. @Override public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, final String prevWord, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { return noSuggestions; } @Override diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java index 999ca775b..186dafd29 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java @@ -39,7 +39,7 @@ public final class SpellCheckerSettingsFragment extends PreferenceFragment { addPreferencesFromResource(R.xml.spell_checker_settings); final PreferenceScreen preferenceScreen = getPreferenceScreen(); if (preferenceScreen != null) { - preferenceScreen.setTitle(ApplicationUtils.getAcitivityTitleResId( + preferenceScreen.setTitle(ApplicationUtils.getActivityTitleResId( getActivity(), SpellCheckerSettingsActivity.class)); } } diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/spellcheck/SynchronouslyLoadedContactsBinaryDictionary.java index 3213c92c7..a694bf47d 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/SynchronouslyLoadedContactsBinaryDictionary.java @@ -14,45 +14,41 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.spellcheck; import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.ContactsBinaryDictionary; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.WordComposer; import java.util.ArrayList; import java.util.Locale; public final class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryDictionary { - private boolean mClosed; + private static final String NAME = "spellcheck_contacts"; + private final Object mLock = new Object(); public SynchronouslyLoadedContactsBinaryDictionary(final Context context, final Locale locale) { - super(context, locale); + super(context, locale, null /* dictFile */, NAME); } @Override - public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, + public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, final String prevWordForBigrams, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { - reloadDictionaryIfRequired(); - return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions); + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { + synchronized (mLock) { + return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, + blockOffensiveWords, additionalFeaturesOptions, inOutLanguageWeight); + } } @Override - public synchronized boolean isValidWord(final String word) { - reloadDictionaryIfRequired(); - return isValidWordInner(word); - } - - // Protect against multiple closing - @Override - public synchronized void close() { - // Actually with the current implementation of ContactsDictionary it's safe to close - // several times, so the following protection is really only for foolproofing - if (mClosed) return; - mClosed = true; - super.close(); + public boolean isValidWord(final String word) { + synchronized (mLock) { + return super.isValidWord(word); + } } } diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/spellcheck/SynchronouslyLoadedUserBinaryDictionary.java index 6405b5e46..1a6dd5818 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/SynchronouslyLoadedUserBinaryDictionary.java @@ -14,38 +14,46 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.spellcheck; import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.UserBinaryDictionary; +import com.android.inputmethod.latin.WordComposer; import java.util.ArrayList; +import java.util.Locale; public final class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionary { + private static final String NAME = "spellcheck_user"; + private final Object mLock = new Object(); - public SynchronouslyLoadedUserBinaryDictionary(final Context context, final String locale) { - this(context, locale, false); + public SynchronouslyLoadedUserBinaryDictionary(final Context context, final Locale locale) { + this(context, locale, false /* alsoUseMoreRestrictiveLocales */); } - public SynchronouslyLoadedUserBinaryDictionary(final Context context, final String locale, + public SynchronouslyLoadedUserBinaryDictionary(final Context context, final Locale locale, final boolean alsoUseMoreRestrictiveLocales) { - super(context, locale, alsoUseMoreRestrictiveLocales); + super(context, locale, alsoUseMoreRestrictiveLocales, null /* dictFile */, NAME); } @Override - public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, + public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, final String prevWordForBigrams, final ProximityInfo proximityInfo, - final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) { - reloadDictionaryIfRequired(); - return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords, - additionalFeaturesOptions); + final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, + final float[] inOutLanguageWeight) { + synchronized (mLock) { + return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, + blockOffensiveWords, additionalFeaturesOptions, inOutLanguageWeight); + } } @Override - public synchronized boolean isValidWord(final String word) { - reloadDictionaryIfRequired(); - return isValidWordInner(word); + public boolean isValidWord(final String word) { + synchronized (mLock) { + return super.isValidWord(word); + } } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index acd47450b..5a325ea82 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -47,10 +47,10 @@ public final class MoreSuggestions extends Keyboard { } private static final class MoreSuggestionsParam extends KeyboardParams { - private final int[] mWidths = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mRowNumbers = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mColumnOrders = new int[SuggestionStripView.MAX_SUGGESTIONS]; - private final int[] mNumColumnsInRow = new int[SuggestionStripView.MAX_SUGGESTIONS]; + private final int[] mWidths = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mRowNumbers = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mColumnOrders = new int[SuggestedWords.MAX_SUGGESTIONS]; + private final int[] mNumColumnsInRow = new int[SuggestedWords.MAX_SUGGESTIONS]; private static final int MAX_COLUMNS_IN_ROW = 3; private int mNumRows; public Drawable mDivider; @@ -66,16 +66,23 @@ public final class MoreSuggestions extends Keyboard { clearKeys(); mDivider = res.getDrawable(R.drawable.more_suggestions_divider); mDividerWidth = mDivider.getIntrinsicWidth(); - final float padding = res.getDimension(R.dimen.more_suggestions_key_horizontal_padding); + final float padding = res.getDimension( + R.dimen.config_more_suggestions_key_horizontal_padding); int row = 0; int index = fromIndex; int rowStartIndex = fromIndex; - final int size = Math.min(suggestedWords.size(), SuggestionStripView.MAX_SUGGESTIONS); + final int size = Math.min(suggestedWords.size(), SuggestedWords.MAX_SUGGESTIONS); while (index < size) { - final String word = suggestedWords.getWord(index); + final String word; + if (isIndexSubjectToAutoCorrection(suggestedWords, index)) { + // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped. + word = suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD); + } else { + word = suggestedWords.getLabel(index); + } // TODO: Should take care of text x-scaling. - mWidths[index] = (int)(TypefaceUtils.getLabelWidth(word, paint) + padding); + mWidths[index] = (int)(TypefaceUtils.getStringWidth(word, paint) + padding); final int numColumn = index - rowStartIndex + 1; final int columnWidth = (maxWidth - mDividerWidth * (numColumn - 1)) / numColumn; @@ -171,6 +178,11 @@ public final class MoreSuggestions extends Keyboard { } } + private static boolean isIndexSubjectToAutoCorrection(final SuggestedWords suggestedWords, + final int index) { + return suggestedWords.mWillAutoCorrect && index == SuggestedWords.INDEX_OF_AUTO_CORRECTION; + } + public static final class Builder extends KeyboardBuilder<MoreSuggestionsParam> { private final MoreSuggestionsView mPaneView; private SuggestedWords mSuggestedWords; @@ -188,7 +200,6 @@ public final class MoreSuggestions extends Keyboard { final int xmlId = R.xml.kbd_suggestions_pane_template; load(xmlId, parentKeyboard.mId); mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2; - mPaneView.updateKeyboardGeometry(mParams.mDefaultRowHeight); final int count = mParams.layout(suggestedWords, fromIndex, maxWidth, minWidth, maxRow, mPaneView.newLabelPaint(null /* key */), mResources); @@ -205,13 +216,21 @@ public final class MoreSuggestions extends Keyboard { final int x = params.getX(index); final int y = params.getY(index); final int width = params.getWidth(index); - final String word = mSuggestedWords.getWord(index); - final String info = mSuggestedWords.getDebugString(index); + final String word; + final String info; + if (isIndexSubjectToAutoCorrection(mSuggestedWords, index)) { + // INDEX_OF_AUTO_CORRECTION and INDEX_OF_TYPED_WORD got swapped. + word = mSuggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD); + info = mSuggestedWords.getDebugString(SuggestedWords.INDEX_OF_TYPED_WORD); + } else { + word = mSuggestedWords.getLabel(index); + info = mSuggestedWords.getDebugString(index); + } final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE; - final Key key = new Key( - params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions, - null /* outputText */, x, y, width, params.mDefaultRowHeight, - 0 /* labelFlags */, Key.BACKGROUND_TYPE_NORMAL); + final Key key = new Key(word, KeyboardIconsSet.ICON_UNDEFINED, + indexInMoreSuggestions, null /* outputText */, info, 0 /* labelFlags */, + Key.BACKGROUND_TYPE_NORMAL, x, y, width, params.mDefaultRowHeight, + params.mHorizontalGap, params.mVerticalGap); params.markAsEdgeKey(key, index); params.onAddKey(key); final int columnNumber = params.getColumnNumber(index); diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index 0ebe37782..549ff0d9d 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -54,7 +54,7 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView { public void adjustVerticalCorrectionForModalMode() { // Set vertical correction to zero (Reset more keys keyboard sliding allowance - // {@link R#dimen.more_keys_keyboard_slide_allowance}). + // {@link R#dimen.config_more_keys_keyboard_slide_allowance}). mKeyDetector.setKeyboard(getKeyboard(), -getPaddingLeft(), -getPaddingTop()); } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index faa5560e4..1d84bb59f 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -28,6 +28,7 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.support.v4.view.ViewCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -38,18 +39,18 @@ import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import android.util.AttributeSet; import android.view.Gravity; -import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; import java.util.ArrayList; @@ -64,7 +65,7 @@ final class SuggestionStripLayoutHelper { public final int mPadding; public final int mDividerWidth; public final int mSuggestionsStripHeight; - public final int mSuggestionsCountInStrip; + private final int mSuggestionsCountInStrip; public final int mMoreSuggestionsRowHeight; private int mMaxMoreSuggestionsRow; public final float mMinMoreSuggestionsWidth; @@ -89,21 +90,18 @@ final class SuggestionStripLayoutHelper { private final Drawable mMoreSuggestionsHint; private static final String MORE_SUGGESTIONS_HINT = "\u2026"; private static final String LEFTWARDS_ARROW = "\u2190"; + private static final String RIGHTWARDS_ARROW = "\u2192"; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); - private final int mSuggestionStripOption; + private final int mSuggestionStripOptions; // These constants are the flag values of - // {@link R.styleable#SuggestionStripView_suggestionStripOption} attribute. + // {@link R.styleable#SuggestionStripView_suggestionStripOptions} attribute. private static final int AUTO_CORRECT_BOLD = 0x01; private static final int AUTO_CORRECT_UNDERLINE = 0x02; private static final int VALID_TYPED_WORD_BOLD = 0x04; - private final TextView mWordToSaveView; - private final TextView mLeftwardsArrowView; - private final TextView mHintToSaveView; - public SuggestionStripLayoutHelper(final Context context, final AttributeSet attrs, final int defStyle, final ArrayList<TextView> wordViews, final ArrayList<View> dividerViews, final ArrayList<TextView> debugInfoViews) { @@ -119,12 +117,13 @@ final class SuggestionStripLayoutHelper { mDividerWidth = dividerView.getMeasuredWidth(); final Resources res = wordView.getResources(); - mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); + mSuggestionsStripHeight = res.getDimensionPixelSize( + R.dimen.config_suggestions_strip_height); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripView); - mSuggestionStripOption = a.getInt( - R.styleable.SuggestionStripView_suggestionStripOption, 0); + mSuggestionStripOptions = a.getInt( + R.styleable.SuggestionStripView_suggestionStripOptions, 0); mAlphaObsoleted = ResourceUtils.getFraction(a, R.styleable.SuggestionStripView_alphaObsoleted, 1.0f); mColorValidTypedWord = a.getColor(R.styleable.SuggestionStripView_colorValidTypedWord, 0); @@ -145,20 +144,17 @@ final class SuggestionStripLayoutHelper { a.recycle(); mMoreSuggestionsHint = getMoreSuggestionsHint(res, - res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect); + res.getDimension(R.dimen.config_more_suggestions_hint_text_size), + mColorAutoCorrect); mCenterPositionInStrip = mSuggestionsCountInStrip / 2; // Assuming there are at least three suggestions. Also, note that the suggestions are // laid out according to script direction, so this is left of the center for LTR scripts // and right of the center for RTL scripts. mTypedWordPositionWhenAutocorrect = mCenterPositionInStrip - 1; mMoreSuggestionsBottomGap = res.getDimensionPixelOffset( - R.dimen.more_suggestions_bottom_gap); - mMoreSuggestionsRowHeight = res.getDimensionPixelSize(R.dimen.more_suggestions_row_height); - - final LayoutInflater inflater = LayoutInflater.from(context); - mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); - mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); - mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); + R.dimen.config_more_suggestions_bottom_gap); + mMoreSuggestionsRowHeight = res.getDimensionPixelSize( + R.dimen.config_more_suggestions_row_height); } public int getMaxMoreSuggestionsRow() { @@ -203,23 +199,25 @@ final class SuggestionStripLayoutHelper { if (indexInSuggestedWords >= suggestedWords.size()) { return null; } - final String word = suggestedWords.getWord(indexInSuggestedWords); - final boolean isAutoCorrect = indexInSuggestedWords == 1 - && suggestedWords.willAutoCorrect(); - final boolean isTypedWordValid = indexInSuggestedWords == 0 - && suggestedWords.mTypedWordValid; - if (!isAutoCorrect && !isTypedWordValid) { + final String word = suggestedWords.getLabel(indexInSuggestedWords); + // TODO: don't use the index to decide whether this is the auto-correction/typed word, as + // this is brittle + final boolean isAutoCorrection = suggestedWords.mWillAutoCorrect + && indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION; + final boolean isTypedWordValid = suggestedWords.mTypedWordValid + && indexInSuggestedWords == SuggestedWords.INDEX_OF_TYPED_WORD; + if (!isAutoCorrection && !isTypedWordValid) { return word; } final int len = word.length(); final Spannable spannedWord = new SpannableString(word); - final int option = mSuggestionStripOption; - if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) - || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { + final int options = mSuggestionStripOptions; + if ((isAutoCorrection && (options & AUTO_CORRECT_BOLD) != 0) + || (isTypedWordValid && (options & VALID_TYPED_WORD_BOLD) != 0)) { spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } - if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { + if (isAutoCorrection && (options & AUTO_CORRECT_UNDERLINE) != 0) { spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } return spannedWord; @@ -229,7 +227,7 @@ final class SuggestionStripLayoutHelper { final SuggestedWords suggestedWords) { final int indexToDisplayMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion; - if (suggestedWords.willAutoCorrect()) { + if (suggestedWords.mWillAutoCorrect) { indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD; } else { @@ -246,35 +244,36 @@ final class SuggestionStripLayoutHelper { return indexInSuggestedWords; } - private int getSuggestionTextColor(final int indexInSuggestedWords, - final SuggestedWords suggestedWords) { + private int getSuggestionTextColor(final SuggestedWords suggestedWords, + final int indexInSuggestedWords) { final int positionInStrip = getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords); - // TODO: Need to revisit this logic with bigram suggestions - final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD); + // Use identity for strings, not #equals : it's the typed word if it's the same object + final boolean isTypedWord = + suggestedWords.getWord(indexInSuggestedWords) == suggestedWords.mTypedWord; final int color; - if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) { + if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { color = mColorAutoCorrect; - } else if (positionInStrip == mCenterPositionInStrip && suggestedWords.mTypedWordValid) { + } else if (isTypedWord && suggestedWords.mTypedWordValid) { color = mColorValidTypedWord; - } else if (isSuggested) { - color = mColorSuggested; - } else { + } else if (isTypedWord) { color = mColorTypedWord; + } else { + color = mColorSuggested; } if (LatinImeLogger.sDBG && suggestedWords.size() > 1) { // If we auto-correct, then the autocorrection is in slot 0 and the typed word // is in slot 1. if (positionInStrip == mCenterPositionInStrip && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet( - suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION), - suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD))) { + suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION), + suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) { return 0xFFFF0000; } } - if (suggestedWords.mIsObsoleteSuggestions && isSuggested) { + if (suggestedWords.mIsObsoleteSuggestions && !isTypedWord) { return applyAlpha(color, mAlphaObsoleted); } return color; @@ -292,54 +291,65 @@ final class SuggestionStripLayoutHelper { params.gravity = Gravity.CENTER; } - public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView, - final ViewGroup placerView) { - if (suggestedWords.mIsPunctuationSuggestions) { - layoutPunctuationSuggestions(suggestedWords, stripView); - return; + /** + * Layout suggestions to the suggestions strip. And returns the number of suggestions displayed + * in the suggestions strip. + * + * @param suggestedWords suggestions to be shown in the suggestions strip. + * @param stripView the suggestions strip view. + * @param placerView the view where the debug info will be placed. + * @return the number of suggestions displayed in the suggestions strip + */ + public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords, + final ViewGroup stripView, final ViewGroup placerView) { + if (suggestedWords.isPunctuationSuggestions()) { + return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + (PunctuationSuggestions)suggestedWords, stripView); } - final int countInStrip = mSuggestionsCountInStrip; - setupWordViewsTextAndColor(suggestedWords, countInStrip); + setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip); final TextView centerWordView = mWordViews.get(mCenterPositionInStrip); final int availableStripWidth = placerView.getWidth() - placerView.getPaddingRight() - placerView.getPaddingLeft(); final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, availableStripWidth); - if (getTextScaleX(centerWordView.getText(), centerWidth, centerWordView.getPaint()) - < MIN_TEXT_XSCALE) { + final int countInStrip; + if (suggestedWords.size() == 1 || getTextScaleX(centerWordView.getText(), centerWidth, + centerWordView.getPaint()) < MIN_TEXT_XSCALE) { // Layout only the most relevant suggested word at the center of the suggestion strip // by consolidating all slots in the strip. - mMoreSuggestionsAvailable = (suggestedWords.size() > 1); + countInStrip = 1; + mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); layoutWord(mCenterPositionInStrip, availableStripWidth - mPadding); stripView.addView(centerWordView); setLayoutWeight(centerWordView, 1.0f, ViewGroup.LayoutParams.MATCH_PARENT); if (SuggestionStripView.DBG) { layoutDebugInfo(mCenterPositionInStrip, placerView, availableStripWidth); } - return; - } - - mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); - int x = 0; - for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { - if (positionInStrip != 0) { - final View divider = mDividerViews.get(positionInStrip); - // Add divider if this isn't the left most suggestion in suggestions strip. - addDivider(stripView, divider); - x += divider.getMeasuredWidth(); - } - - final int width = getSuggestionWidth(positionInStrip, availableStripWidth); - final TextView wordView = layoutWord(positionInStrip, width); - stripView.addView(wordView); - setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), - ViewGroup.LayoutParams.MATCH_PARENT); - x += wordView.getMeasuredWidth(); - - if (SuggestionStripView.DBG) { - layoutDebugInfo(positionInStrip, placerView, x); + } else { + countInStrip = mSuggestionsCountInStrip; + mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + int x = 0; + for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { + if (positionInStrip != 0) { + final View divider = mDividerViews.get(positionInStrip); + // Add divider if this isn't the left most suggestion in suggestions strip. + addDivider(stripView, divider); + x += divider.getMeasuredWidth(); + } + + final int width = getSuggestionWidth(positionInStrip, availableStripWidth); + final TextView wordView = layoutWord(positionInStrip, width); + stripView.addView(wordView); + setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), + ViewGroup.LayoutParams.MATCH_PARENT); + x += wordView.getMeasuredWidth(); + + if (SuggestionStripView.DBG) { + layoutDebugInfo(positionInStrip, placerView, x); + } } } + return countInStrip; } /** @@ -431,7 +441,7 @@ final class SuggestionStripLayoutHelper { // {@link SuggestionStripView#onClick(View)}. wordView.setTag(indexInSuggestedWords); wordView.setText(getStyledSuggestedWord(suggestedWords, indexInSuggestedWords)); - wordView.setTextColor(getSuggestionTextColor(positionInStrip, suggestedWords)); + wordView.setTextColor(getSuggestionTextColor(suggestedWords, indexInSuggestedWords)); if (SuggestionStripView.DBG) { mDebugInfoViews.get(positionInStrip).setText( suggestedWords.getDebugString(indexInSuggestedWords)); @@ -439,9 +449,9 @@ final class SuggestionStripLayoutHelper { } } - private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords, - final ViewGroup stripView) { - final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP); + private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) { + final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP); for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { if (positionInStrip != 0) { // Add divider if this isn't the left most suggestion in suggestions strip. @@ -454,66 +464,63 @@ final class SuggestionStripLayoutHelper { // {@link TextView#getTag()} is used to get the index in suggestedWords at // {@link SuggestionStripView#onClick(View)}. wordView.setTag(positionInStrip); - wordView.setText(suggestedWords.getWord(positionInStrip)); + wordView.setText(punctuationSuggestions.getLabel(positionInStrip)); wordView.setTextScaleX(1.0f); wordView.setCompoundDrawables(null, null, null, null); stripView.addView(wordView); setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight); } - mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + mMoreSuggestionsAvailable = (punctuationSuggestions.size() > countInStrip); + return countInStrip; } - public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView, - final int stripWidth, final CharSequence hintText, final OnClickListener listener) { + public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip, + final int stripWidth) { final int width = stripWidth - mDividerWidth - mPadding * 2; - final TextView wordView = mWordToSaveView; + final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); wordView.setTextColor(mColorTypedWord); final int wordWidth = (int)(width * mCenterSuggestionWeight); - final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); + final CharSequence wordToSave = getEllipsizedText(word, wordWidth, wordView.getPaint()); final float wordScaleX = wordView.getTextScaleX(); - // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word - // will be extracted at {@link #getAddToDictionaryWord()}. - wordView.setTag(word); - wordView.setText(text); + wordView.setText(wordToSave); wordView.setTextScaleX(wordScaleX); - stripView.addView(wordView); setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); - stripView.addView(mDividerViews.get(0)); - - final TextView leftArrowView = mLeftwardsArrowView; - leftArrowView.setTextColor(mColorAutoCorrect); - leftArrowView.setText(LEFTWARDS_ARROW); - stripView.addView(leftArrowView); - - final TextView hintView = mHintToSaveView; - hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + final TextView hintView = (TextView)addToDictionaryStrip.findViewById( + R.id.hint_add_to_dictionary); hintView.setTextColor(mColorAutoCorrect); - final int hintWidth = width - wordWidth - leftArrowView.getWidth(); - final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); - hintView.setText(hintText); + final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) + == ViewCompat.LAYOUT_DIRECTION_RTL); + final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; + final Resources res = addToDictionaryStrip.getResources(); + final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale); + final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary); + final String hintWithArrow = (isRtlLanguage == isRtlSystem) + ? (arrow + hintText) : (hintText + arrow); + final int hintWidth = width - wordWidth; + hintView.setTextScaleX(1.0f); // Reset textScaleX. + final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint()); + hintView.setText(hintWithArrow); hintView.setTextScaleX(hintScaleX); - stripView.addView(hintView); setLayoutWeight( hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); - - wordView.setOnClickListener(listener); - leftArrowView.setOnClickListener(listener); - hintView.setOnClickListener(listener); - } - - public String getAddToDictionaryWord() { - // String tag is set at - // {@link #layoutAddToDictionaryHint(String,ViewGroup,int,CharSequence,OnClickListener}. - return (String)mWordToSaveView.getTag(); } - public boolean isAddToDictionaryShowing(final View v) { - return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView; + public void layoutImportantNotice(final View importantNoticeStrip, + final String importantNoticeTitle) { + final TextView titleView = (TextView)importantNoticeStrip.findViewById( + R.id.important_notice_title); + final int width = titleView.getWidth() - titleView.getPaddingLeft() + - titleView.getPaddingRight(); + titleView.setTextColor(mColorAutoCorrect); + titleView.setText(importantNoticeTitle); + titleView.setTextScaleX(1.0f); // Reset textScaleX. + final float titleScaleX = getTextScaleX(importantNoticeTitle, width, titleView.getPaint()); + titleView.setTextScaleX(titleScaleX); } - private static void setLayoutWeight(final View v, final float weight, final int height) { + static void setLayoutWeight(final View v, final float weight, final int height) { final ViewGroup.LayoutParams lp = v.getLayoutParams(); if (lp instanceof LinearLayout.LayoutParams) { final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; @@ -527,7 +534,7 @@ final class SuggestionStripLayoutHelper { final TextPaint paint) { paint.setTextScaleX(1.0f); final int width = getTextWidth(text, paint); - if (width <= maxWidth) { + if (width <= maxWidth || maxWidth <= 0) { return 1.0f; } return maxWidth / (float)width; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 75f17c559..a0793b133 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -18,7 +18,11 @@ package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.content.res.Resources; +import android.graphics.Color; +import android.support.v4.view.ViewCompat; +import android.text.TextUtils; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -26,22 +30,25 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.RelativeLayout; import android.widget.TextView; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.MoreKeysPanel; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.InputAttributes; 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; import com.android.inputmethod.latin.define.ProductionFlag; +import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import com.android.inputmethod.research.ResearchLogger; import java.util.ArrayList; @@ -50,15 +57,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick OnLongClickListener { public interface Listener { public void addWordToUserDictionary(String word); + public void showImportantNoticeContents(); public void pickSuggestionManually(int index, SuggestedWordInfo word); } - // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. - public static final int MAX_SUGGESTIONS = 18; - static final boolean DBG = LatinImeLogger.sDBG; + private static final float DEBUG_INFO_TEXT_SIZE_IN_DIP = 6.0f; private final ViewGroup mSuggestionsStrip; + private final ViewGroup mAddToDictionaryStrip; + private final View mImportantNoticeStrip; MainKeyboardView mMainKeyboardView; private final View mMoreSuggestionsContainer; @@ -71,8 +79,54 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick Listener mListener; private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; + private int mSuggestionsCountInStrip; private final SuggestionStripLayoutHelper mLayoutHelper; + private final StripVisibilityGroup mStripVisibilityGroup; + + private static class StripVisibilityGroup { + private final View mSuggestionsStrip; + private final View mAddToDictionaryStrip; + private final View mImportantNoticeStrip; + + public StripVisibilityGroup(final View suggestionsStrip, final View addToDictionaryStrip, + final View importantNoticeStrip) { + mSuggestionsStrip = suggestionsStrip; + mAddToDictionaryStrip = addToDictionaryStrip; + mImportantNoticeStrip = importantNoticeStrip; + showSuggestionsStrip(); + } + + public void setLayoutDirection(final boolean isRtlLanguage) { + final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL + : ViewCompat.LAYOUT_DIRECTION_LTR; + ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection); + ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection); + ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection); + } + + public void showSuggestionsStrip() { + mSuggestionsStrip.setVisibility(VISIBLE); + mAddToDictionaryStrip.setVisibility(INVISIBLE); + mImportantNoticeStrip.setVisibility(INVISIBLE); + } + + public void showAddToDictionaryStrip() { + mSuggestionsStrip.setVisibility(INVISIBLE); + mAddToDictionaryStrip.setVisibility(VISIBLE); + mImportantNoticeStrip.setVisibility(INVISIBLE); + } + + public void showImportantNoticeStrip() { + mSuggestionsStrip.setVisibility(INVISIBLE); + mAddToDictionaryStrip.setVisibility(INVISIBLE); + mImportantNoticeStrip.setVisibility(VISIBLE); + } + + public boolean isShowingAddToDictionaryStrip() { + return mAddToDictionaryStrip.getVisibility() == VISIBLE; + } + } /** * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user. @@ -91,15 +145,23 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick inflater.inflate(R.layout.suggestions_strip, this); mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); - for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { - final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); + mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip); + mImportantNoticeStrip = findViewById(R.id.important_notice_strip); + mStripVisibilityGroup = new StripVisibilityGroup(mSuggestionsStrip, mAddToDictionaryStrip, + mImportantNoticeStrip); + + for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) { + final TextView word = new TextView(context, null, R.attr.suggestionWordStyle); word.setOnClickListener(this); word.setOnLongClickListener(this); mWordViews.add(word); final View divider = inflater.inflate(R.layout.suggestion_divider, null); divider.setOnClickListener(this); mDividerViews.add(divider); - mDebugInfoViews.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); + final TextView info = new TextView(context, null, R.attr.suggestionWordStyle); + info.setTextColor(Color.WHITE); + info.setTextSize(TypedValue.COMPLEX_UNIT_DIP, DEBUG_INFO_TEXT_SIZE_IN_DIP); + mDebugInfoViews.add(info); } mLayoutHelper = new SuggestionStripLayoutHelper( @@ -112,7 +174,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final Resources res = context.getResources(); mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset( - R.dimen.more_suggestions_modal_tolerance); + R.dimen.config_more_suggestions_modal_tolerance); mMoreSuggestionsSlidingDetector = new GestureDetector( context, mMoreSuggestionsSlidingListener); } @@ -126,13 +188,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view); } - public void setSuggestions(final SuggestedWords suggestedWords) { + public void setSuggestions(final SuggestedWords suggestedWords, final boolean isRtlLanguage) { clear(); + mStripVisibilityGroup.setLayoutDirection(isRtlLanguage); mSuggestedWords = suggestedWords; - mLayoutHelper.layout(mSuggestedWords, mSuggestionsStrip, this); + mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip( + mSuggestedWords, mSuggestionsStrip, this); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords); } + mStripVisibilityGroup.showSuggestionsStrip(); } public int setMoreSuggestionsHeight(final int remainingHeight) { @@ -140,14 +205,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } public boolean isShowingAddToDictionaryHint() { - return mSuggestionsStrip.getChildCount() > 0 - && mLayoutHelper.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0)); + return mStripVisibilityGroup.isShowingAddToDictionaryStrip(); } - public void showAddToDictionaryHint(final String word, final CharSequence hintText) { - clear(); - mLayoutHelper.layoutAddToDictionaryHint( - word, mSuggestionsStrip, getWidth(), hintText, this); + public void showAddToDictionaryHint(final String word) { + mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, getWidth()); + // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word + // will be extracted at {@link #onClick(View)}. + mAddToDictionaryStrip.setTag(word); + mAddToDictionaryStrip.setOnClickListener(this); + mStripVisibilityGroup.showAddToDictionaryStrip(); } public boolean dismissAddToDictionaryHint() { @@ -158,31 +225,65 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return false; } + // This method checks if we should show the important notice (checks on permanent storage if + // it has been shown once already or not, and if in the setup wizard). If applicable, it shows + // the notice. In all cases, it returns true if it was shown, false otherwise. + public boolean maybeShowImportantNoticeTitle(final InputAttributes inputAttributes) { + if (!ImportantNoticeUtils.shouldShowImportantNotice(getContext(), inputAttributes)) { + return false; + } + if (getWidth() <= 0) { + return false; + } + final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle( + getContext()); + if (TextUtils.isEmpty(importantNoticeTitle)) { + return false; + } + if (isShowingMoreSuggestionPanel()) { + dismissMoreSuggestionsPanel(); + } + mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, importantNoticeTitle); + mStripVisibilityGroup.showImportantNoticeStrip(); + mImportantNoticeStrip.setOnClickListener(this); + return true; + } + public void clear() { mSuggestionsStrip.removeAllViews(); - removeAllViews(); - addView(mSuggestionsStrip); - mMoreSuggestionsView.dismissMoreKeysPanel(); + removeAllDebugInfoViews(); + mStripVisibilityGroup.showSuggestionsStrip(); + dismissMoreSuggestionsPanel(); + } + + private void removeAllDebugInfoViews() { + // The debug info views may be placed as children views of this {@link SuggestionStripView}. + for (final View debugInfoView : mDebugInfoViews) { + final ViewParent parent = debugInfoView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup)parent).removeView(debugInfoView); + } + } } private final MoreSuggestionsListener mMoreSuggestionsListener = new MoreSuggestionsListener() { @Override public void onSuggestionSelected(final int index, final SuggestedWordInfo wordInfo) { mListener.pickSuggestionManually(index, wordInfo); - mMoreSuggestionsView.dismissMoreKeysPanel(); + dismissMoreSuggestionsPanel(); } @Override public void onCancelInput() { - mMoreSuggestionsView.dismissMoreKeysPanel(); + dismissMoreSuggestionsPanel(); } }; private final MoreKeysPanel.Controller mMoreSuggestionsController = new MoreKeysPanel.Controller() { @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { - mMainKeyboardView.onDismissMoreKeysPanel(panel); + public void onDismissMoreKeysPanel() { + mMainKeyboardView.onDismissMoreKeysPanel(); } @Override @@ -191,11 +292,19 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { - mMoreSuggestionsView.dismissMoreKeysPanel(); + public void onCancelMoreKeysPanel() { + dismissMoreSuggestionsPanel(); } }; + public boolean isShowingMoreSuggestionPanel() { + return mMoreSuggestionsView.isShowingInParent(); + } + + public void dismissMoreSuggestionsPanel() { + mMoreSuggestionsView.dismissMoreKeysPanel(); + } + @Override public boolean onLongClick(final View view) { AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback( @@ -204,7 +313,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } boolean showMoreSuggestions() { - final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard(); + final Keyboard parentKeyboard = mMainKeyboardView.getKeyboard(); if (parentKeyboard == null) { return false; } @@ -212,11 +321,17 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick if (!layoutHelper.mMoreSuggestionsAvailable) { return false; } + // Dismiss another {@link MoreKeysPanel} that may be being showed, for example + // {@link MoreKeysKeyboardView}. + mMainKeyboardView.onDismissMoreKeysPanel(); + // Dismiss all key previews and sliding key input preview that may be being showed. + mMainKeyboardView.dismissAllKeyPreviews(); + mMainKeyboardView.dismissSlidingKeyInputPreview(); final int stripWidth = getWidth(); final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; - builder.layout(mSuggestedWords, layoutHelper.mSuggestionsCountInStrip, maxWidth, + builder.layout(mSuggestedWords, mSuggestionsCountInStrip, maxWidth, (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth), layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard); mMoreSuggestionsView.setKeyboard(builder.build()); @@ -227,20 +342,16 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final int pointY = -layoutHelper.mMoreSuggestionsBottomGap; moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY, mMoreSuggestionsListener); - mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING; mOriginX = mLastX; mOriginY = mLastY; - for (int i = 0; i < layoutHelper.mSuggestionsCountInStrip; i++) { + for (int i = 0; i < mSuggestionsCountInStrip; i++) { mWordViews.get(i).setPressed(false); } return true; } - // Working variables for onLongClick and dispatchTouchEvent. - private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; - private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0; - private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1; - private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2; + // Working variables for {@link #onLongClick(View)} and + // {@link onInterceptTouchEvent(MotionEvent)}. private int mLastX; private int mLastY; private int mOriginX; @@ -260,36 +371,39 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick }; @Override - public boolean dispatchTouchEvent(final MotionEvent me) { + public boolean onInterceptTouchEvent(final MotionEvent me) { if (!mMoreSuggestionsView.isShowingInParent()) { mLastX = (int)me.getX(); mLastY = (int)me.getY(); - if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) { - return true; - } - return super.dispatchTouchEvent(me); + return mMoreSuggestionsSlidingDetector.onTouchEvent(me); } final int action = me.getAction(); final int index = me.getActionIndex(); final int x = (int)me.getX(index); final int y = (int)me.getY(index); - - if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) { - if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance - || mOriginY - y >= mMoreSuggestionsModalTolerance) { - // Decided to be in the sliding input mode only when the touch point has been moved - // upward. - mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE; - } 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; - mMoreSuggestionsView.adjustVerticalCorrectionForModalMode(); - } + if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance + || mOriginY - y >= mMoreSuggestionsModalTolerance) { + // Decided to be in the sliding input mode only when the touch point has been moved + // upward. Further {@link MotionEvent}s will be delivered to + // {@link #onTouchEvent(MotionEvent)}. return true; } - // MORE_SUGGESTIONS_IN_SLIDING_MODE + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { + // Decided to be in the modal input mode. + mMoreSuggestionsView.adjustVerticalCorrectionForModalMode(); + } + return false; + } + + @Override + public boolean onTouchEvent(final MotionEvent me) { + // In the sliding input mode. {@link MotionEvent} should be forwarded to + // {@link MoreSuggestionsView}. + final int index = me.getActionIndex(); + final int x = (int)me.getX(index); + final int y = (int)me.getY(index); me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y)); mMoreSuggestionsView.onTouchEvent(me); return true; @@ -297,31 +411,44 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick @Override public void onClick(final View view) { - if (mLayoutHelper.isAddToDictionaryShowing(view)) { - mListener.addWordToUserDictionary(mLayoutHelper.getAddToDictionaryWord()); + if (view == mImportantNoticeStrip) { + mListener.showImportantNoticeContents(); + return; + } + final Object tag = view.getTag(); + // {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}. + if (tag instanceof String) { + final String wordToSave = (String)tag; + mListener.addWordToUserDictionary(wordToSave); clear(); return; } - final Object tag = view.getTag(); - // Integer tag is set at + // {@link Integer} tag is set at // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup} - if (!(tag instanceof Integer)) { - return; - } - final int index = (Integer) tag; - if (index >= mSuggestedWords.size()) { - return; + if (tag instanceof Integer) { + final int index = (Integer) tag; + if (index >= mSuggestedWords.size()) { + return; + } + final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); + mListener.pickSuggestionManually(index, wordInfo); } - - final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); - mListener.pickSuggestionManually(index, wordInfo); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mMoreSuggestionsView.dismissMoreKeysPanel(); + dismissMoreSuggestionsPanel(); + } + + @Override + protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { + // Called by the framework when the size is known. Show the important notice if applicable. + // This may be overriden by showing suggestions later, if applicable. + if (oldw <= 0 && w > 0) { + maybeShowImportantNoticeTitle(Settings.getInstance().getCurrent().mInputAttributes); + } } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java new file mode 100644 index 000000000..52708455e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 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.suggestions; + +import com.android.inputmethod.latin.SuggestedWords; + +/** + * An object that gives basic control of a suggestion strip and some info on it. + */ +public interface SuggestionStripViewAccessor { + public void showAddToDictionaryHint(final String word); + public boolean isShowingAddToDictionaryHint(); + public void dismissAddToDictionaryHint(); + public void setNeutralSuggestionStrip(); + public void showSuggestionStrip(final SuggestedWords suggestedWords); +} diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java index 32c4950da..97a924d7b 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java @@ -53,20 +53,24 @@ public class UserDictionaryList extends PreferenceFragment { } public static TreeSet<String> getUserDictionaryLocalesSet(Activity activity) { - @SuppressWarnings("deprecation") - final Cursor cursor = activity.managedQuery(UserDictionary.Words.CONTENT_URI, + final Cursor cursor = activity.getContentResolver().query(UserDictionary.Words.CONTENT_URI, new String[] { UserDictionary.Words.LOCALE }, null, null, null); final TreeSet<String> localeSet = new TreeSet<String>(); if (null == cursor) { // The user dictionary service is not present or disabled. Return null. return null; - } else if (cursor.moveToFirst()) { - final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE); - do { - final String locale = cursor.getString(columnIndex); - localeSet.add(null != locale ? locale : ""); - } while (cursor.moveToNext()); + } + try { + if (cursor.moveToFirst()) { + final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE); + do { + final String locale = cursor.getString(columnIndex); + localeSet.add(null != locale ? locale : ""); + } while (cursor.moveToNext()); + } + } finally { + cursor.close(); } if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { // For ICS, we need to show "For all languages" in case that the keyboard locale diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java index 7571e87c5..cf2014a1a 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java @@ -140,6 +140,11 @@ public class UserDictionarySettings extends ListFragment { } mLocale = locale; + // WARNING: The following cursor is never closed! TODO: don't put that in a member, and + // make sure all cursors are correctly closed. Also, this comes from a call to + // Activity#managedQuery, which has been deprecated for a long time (and which FORBIDS + // closing the cursor, so take care when resolving this TODO). We should either use a + // regular query and close the cursor, or switch to a LoaderManager and a CursorLoader. mCursor = createCursor(locale); TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); emptyView.setText(R.string.user_dict_settings_empty_text); diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java index d87f6f3c4..2bb30a2ba 100644 --- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java @@ -17,32 +17,43 @@ package com.android.inputmethod.latin.utils; import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; +import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.EMOJI_CAPABLE; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME; import android.os.Build; import android.text.TextUtils; +import android.util.Log; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; -import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import java.util.ArrayList; +import java.util.Arrays; public final class AdditionalSubtypeUtils { + private static final String TAG = AdditionalSubtypeUtils.class.getSimpleName(); + private static final InputMethodSubtype[] EMPTY_SUBTYPE_ARRAY = new InputMethodSubtype[0]; private AdditionalSubtypeUtils() { // This utility class is not publicly instantiable. } + @UsedForTesting public static boolean isAdditionalSubtype(final InputMethodSubtype subtype) { return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE); } private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":"; + private static final int INDEX_OF_LOCALE = 0; + private static final int INDEX_OF_KEYBOARD_LAYOUT = 1; + private static final int INDEX_OF_EXTRA_VALUE = 2; + private static final int LENGTH_WITHOUT_EXTRA_VALUE = (INDEX_OF_KEYBOARD_LAYOUT + 1); + private static final int LENGTH_WITH_EXTRA_VALUE = (INDEX_OF_EXTRA_VALUE + 1); private static final String PREF_SUBTYPE_SEPARATOR = ";"; public static InputMethodSubtype createAdditionalSubtype(final String localeString, @@ -79,17 +90,6 @@ public final class AdditionalSubtypeUtils { : basePrefSubtype + LOCALE_AND_LAYOUT_SEPARATOR + extraValue; } - public static InputMethodSubtype createAdditionalSubtype(final String prefSubtype) { - final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR); - if (elems.length < 2 || elems.length > 3) { - throw new RuntimeException("Unknown additional subtype specified: " + prefSubtype); - } - final String localeString = elems[0]; - final String keyboardLayoutSetName = elems[1]; - final String extraValue = (elems.length == 3) ? elems[2] : null; - return createAdditionalSubtype(localeString, keyboardLayoutSetName, extraValue); - } - public static InputMethodSubtype[] createAdditionalSubtypesArray(final String prefSubtypes) { if (TextUtils.isEmpty(prefSubtypes)) { return EMPTY_SUBTYPE_ARRAY; @@ -98,7 +98,19 @@ public final class AdditionalSubtypeUtils { final ArrayList<InputMethodSubtype> subtypesList = CollectionUtils.newArrayList(prefSubtypeArray.length); for (final String prefSubtype : prefSubtypeArray) { - final InputMethodSubtype subtype = createAdditionalSubtype(prefSubtype); + final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR); + if (elems.length != LENGTH_WITHOUT_EXTRA_VALUE + && elems.length != LENGTH_WITH_EXTRA_VALUE) { + Log.w(TAG, "Unknown additional subtype specified: " + prefSubtype + " in " + + prefSubtypes); + continue; + } + final String localeString = elems[INDEX_OF_LOCALE]; + final String keyboardLayoutSetName = elems[INDEX_OF_KEYBOARD_LAYOUT]; + final String extraValue = (elems.length == LENGTH_WITH_EXTRA_VALUE) + ? elems[INDEX_OF_EXTRA_VALUE] : null; + final InputMethodSubtype subtype = createAdditionalSubtype( + localeString, keyboardLayoutSetName, extraValue); if (subtype.getNameResId() == SubtypeLocaleUtils.UNKNOWN_KEYBOARD_LAYOUT) { // Skip unknown keyboard layout subtype. This may happen when predefined keyboard // layout has been removed. @@ -137,31 +149,36 @@ public final class AdditionalSubtypeUtils { return sb.toString(); } - private static InputMethodSubtype buildInputMethodSubtype(int nameId, String localeString, - String layoutExtraValue, String additionalSubtypeExtraValue) { - // CAVEAT! If you want to change subtypeId after changing the extra values, - // you must change "getInputMethodSubtypeId". But it will remove the additional keyboard - // from the current users. So, you should be really careful to change it. - final int subtypeId = getInputMethodSubtypeId(nameId, localeString, layoutExtraValue, - additionalSubtypeExtraValue); + private static InputMethodSubtype buildInputMethodSubtype(final int nameId, + final String localeString, final String layoutExtraValue, + final String additionalSubtypeExtraValue) { + // To preserve additional subtype settings and user's selection across OS updates, subtype + // id shouldn't be changed. New attributes, such as emojiCapable, are carefully excluded + // from the calculation of subtype id. + final String compatibleExtraValue = StringUtils.joinCommaSplittableText( + layoutExtraValue, additionalSubtypeExtraValue); + final int compatibleSubtypeId = getInputMethodSubtypeId(localeString, compatibleExtraValue); final String extraValue; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue - + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE - + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + // Color Emoji is supported from KitKat. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + extraValue = StringUtils.appendToCommaSplittableTextIfNotExists( + EMOJI_CAPABLE, compatibleExtraValue); } else { - extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue; + extraValue = compatibleExtraValue; } return InputMethodSubtypeCompatUtils.newInputMethodSubtype(nameId, R.drawable.ic_ime_switcher_dark, localeString, KEYBOARD_MODE, extraValue, - false, false, subtypeId); + false, false, compatibleSubtypeId); } - private static int getInputMethodSubtypeId(int nameId, String localeString, - String layoutExtraValue, String additionalSubtypeExtraValue) { - // TODO: Use InputMethodSubtypeBuilder once we use SDK version 19. - return (new InputMethodSubtype(nameId, R.drawable.ic_ime_switcher_dark, - localeString, KEYBOARD_MODE, layoutExtraValue + "," + additionalSubtypeExtraValue, - false, false)).hashCode(); + private static int getInputMethodSubtypeId(final String localeString, final String extraValue) { + // From the compatibility point of view, the calculation of subtype id has been copied from + // {@link InputMethodSubtype} of JellyBean MR2. + return Arrays.hashCode(new Object[] { + localeString, + KEYBOARD_MODE, + extraValue, + false /* isAuxiliary */, + false /* overrideImplicitlyEnabledSubtype */ }); } } diff --git a/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java index 08a2a8c5a..7a4150def 100644 --- a/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java @@ -31,7 +31,7 @@ public final class ApplicationUtils { // This utility class is not publicly instantiable. } - public static int getAcitivityTitleResId(final Context context, + public static int getActivityTitleResId(final Context context, final Class<? extends Activity> cls) { final ComponentName cn = new ComponentName(context, cls); try { @@ -62,4 +62,22 @@ public final class ApplicationUtils { } return ""; } + + /** + * A utility method to get the application's PackageInfo.versionCode + * @return the application's PackageInfo.versionCode + */ + public static int getVersionCode(final Context context) { + try { + if (context == null) { + return 0; + } + final String packageName = context.getPackageName(); + final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + return info.versionCode; + } catch (final NameNotFoundException e) { + Log.e(TAG, "Could not find version info.", e); + } + return 0; + } } diff --git a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java index c2e97a36f..d12aad639 100644 --- a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java +++ b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java @@ -20,7 +20,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** - * This class is a holder of a result of asynchronous computation. + * This class is a holder of the result of an asynchronous computation. * * @param <E> the type of the result. */ @@ -36,9 +36,9 @@ public class AsyncResultHolder<E> { } /** - * Sets the result value to this holder. + * Sets the result value of this holder. * - * @param result the value which is set. + * @param result the value to set. */ public void set(final E result) { synchronized(mLock) { @@ -54,12 +54,12 @@ public class AsyncResultHolder<E> { * Causes the current thread to wait unless the value is set or the specified time is elapsed. * * @param defaultValue the default value. - * @param timeOut the time to wait. - * @return if the result is set until the time limit then the result, otherwise defaultValue. + * @param timeOut the maximum time to wait. + * @return if the result is set before the time limit then the result, otherwise defaultValue. */ public E get(final E defaultValue, final long timeOut) { try { - if(mLatch.await(timeOut, TimeUnit.MILLISECONDS)) { + if (mLatch.await(timeOut, TimeUnit.MILLISECONDS)) { return mResult; } else { return defaultValue; diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java index 066c5fd32..22b9b77d2 100644 --- a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java @@ -17,16 +17,11 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.latin.BinaryDictionary; -import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import android.text.TextUtils; import android.util.Log; -import java.util.concurrent.ConcurrentHashMap; - public final class AutoCorrectionUtils { private static final boolean DBG = LatinImeLogger.sDBG; private static final String TAG = AutoCorrectionUtils.class.getSimpleName(); @@ -36,48 +31,6 @@ public final class AutoCorrectionUtils { // Purely static class: can't instantiate. } - public static boolean isValidWord(final Suggest suggest, final String word, - final boolean ignoreCase) { - if (TextUtils.isEmpty(word)) { - return false; - } - final ConcurrentHashMap<String, Dictionary> dictionaries = suggest.getUnigramDictionaries(); - final String lowerCasedWord = word.toLowerCase(suggest.mLocale); - for (final String key : dictionaries.keySet()) { - 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; - } - } - return false; - } - - public static int getMaxFrequency(final ConcurrentHashMap<String, Dictionary> dictionaries, - final String word) { - if (TextUtils.isEmpty(word)) { - return Dictionary.NOT_A_PROBABILITY; - } - int maxFreq = -1; - for (final String key : dictionaries.keySet()) { - final Dictionary dictionary = dictionaries.get(key); - if (null == dictionary) continue; - final int tempFreq = dictionary.getFrequency(word); - if (tempFreq >= maxFreq) { - maxFreq = tempFreq; - } - } - return maxFreq; - } - public static boolean suggestionExceedsAutoCorrectionThreshold( final SuggestedWordInfo suggestion, final String consideredWord, final float autoCorrectionThreshold) { @@ -87,7 +40,7 @@ public final class AutoCorrectionUtils { final int autoCorrectionSuggestionScore = suggestion.mScore; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( consideredWord, suggestion.mWord, autoCorrectionSuggestionScore); if (DBG) { Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + "," @@ -118,9 +71,8 @@ public final class AutoCorrectionUtils { if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) { return false; } - final int maxEditDistanceOfNativeDictionary = - (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; - final int distance = BinaryDictionary.editDistance(typedWord, suggestion); + final int maxEditDistanceOfNativeDictionary = (typedWordLength / 2) + 1; + final int distance = BinaryDictionaryUtils.editDistance(typedWord, suggestion); if (DBG) { Log.d(TAG, "Autocorrected edit distance = " + distance + ", " + maxEditDistanceOfNativeDictionary); diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java new file mode 100644 index 000000000..5d7deba15 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 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.utils; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.personalization.PersonalizationHelper; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class BinaryDictionaryUtils { + private static final String TAG = BinaryDictionaryUtils.class.getSimpleName(); + + private BinaryDictionaryUtils() { + // This utility class is not publicly instantiable. + } + + static { + JniUtils.loadNativeLibrary(); + } + + private static native boolean createEmptyDictFileNative(String filePath, long dictVersion, + String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); + private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); + private static native int editDistanceNative(int[] before, int[] after); + private static native int setCurrentTimeForTestNative(int currentTime); + + public static DictionaryHeader getHeader(final File dictFile) + throws IOException, UnsupportedFormatException { + return getHeaderWithOffsetAndLength(dictFile, 0 /* offset */, dictFile.length()); + } + + public static DictionaryHeader getHeaderWithOffsetAndLength(final File dictFile, + final long offset, final long length) throws IOException, UnsupportedFormatException { + // dictType is never used for reading the header. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + dictFile.getAbsolutePath(), offset, length, + true /* useFullEditDistance */, null /* locale */, "" /* dictType */, + false /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); + if (header == null) { + throw new IOException(); + } + return header; + } + + public static boolean renameDict(final File dictFile, final File newDictFile) { + if (dictFile.isFile()) { + return dictFile.renameTo(newDictFile); + } else if (dictFile.isDirectory()) { + final String dictName = dictFile.getName(); + final String newDictName = newDictFile.getName(); + if (newDictFile.exists()) { + return false; + } + for (final File file : dictFile.listFiles()) { + if (!file.isFile()) { + continue; + } + final String fileName = file.getName(); + final String newFileName = fileName.replaceFirst( + Pattern.quote(dictName), Matcher.quoteReplacement(newDictName)); + if (!file.renameTo(new File(dictFile, newFileName))) { + return false; + } + } + return dictFile.renameTo(newDictFile); + } + return false; + } + + @UsedForTesting + public static boolean createEmptyDictFile(final String filePath, final long dictVersion, + final Locale locale, final Map<String, String> attributeMap) { + final String[] keyArray = new String[attributeMap.size()]; + final String[] valueArray = new String[attributeMap.size()]; + int index = 0; + for (final String key : attributeMap.keySet()) { + keyArray[index] = key; + valueArray[index] = attributeMap.get(key); + index++; + } + return createEmptyDictFileNative(filePath, dictVersion, locale.toString(), keyArray, + valueArray); + } + + public static float calcNormalizedScore(final String before, final String after, + final int score) { + return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), + StringUtils.toCodePointArray(after), score); + } + + public static int editDistance(final String before, final String after) { + if (before == null || after == null) { + throw new IllegalArgumentException(); + } + return editDistanceNative(StringUtils.toCodePointArray(before), + StringUtils.toCodePointArray(after)); + } + + /** + * Control the current time to be used in the native code. If currentTime >= 0, this method sets + * the current time and gets into test mode. + * In test mode, set timestamp is used as the current time in the native code. + * If currentTime < 0, quit the test mode and returns to using time() to get the current time. + * + * @param currentTime seconds since the unix epoch + * @return current time got in the native code. + */ + @UsedForTesting + public static int setCurrentTimeForTest(final int currentTime) { + final int currentNativeTimestamp = setCurrentTimeForTestNative(currentTime); + PersonalizationHelper.currentTimeChangedForTesting(currentNativeTimestamp); + return currentNativeTimestamp; + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java b/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java deleted file mode 100644 index ae1fd3f79..000000000 --- a/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.utils; - -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; - -import java.util.Collection; -import java.util.Comparator; -import java.util.TreeSet; - -/** - * A TreeSet that is bounded in size and throws everything that's smaller than its limit - */ -public final class BoundedTreeSet extends TreeSet<SuggestedWordInfo> { - private final int mCapacity; - public BoundedTreeSet(final Comparator<SuggestedWordInfo> comparator, final int capacity) { - super(comparator); - mCapacity = capacity; - } - - @Override - public boolean add(final SuggestedWordInfo e) { - if (size() < mCapacity) return super.add(e); - if (comparator().compare(e, last()) > 0) return false; - super.add(e); - pollLast(); // removes the last element - return true; - } - - @Override - public boolean addAll(final Collection<? extends SuggestedWordInfo> e) { - if (null == e) return false; - return super.addAll(e); - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java index 3d4404a98..702688f93 100644 --- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java @@ -21,7 +21,7 @@ import android.text.TextUtils; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.WordComposer; -import com.android.inputmethod.latin.settings.SettingsValues; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.util.Locale; @@ -74,7 +74,7 @@ public final class CapsModeUtils { * @param reqModes The modes to be checked: may be any combination of * {@link TextUtils#CAP_MODE_CHARACTERS}, {@link TextUtils#CAP_MODE_WORDS}, and * {@link TextUtils#CAP_MODE_SENTENCES}. - * @param settingsValues The current settings values. + * @param spacingAndPunctuations The current spacing and punctuations settings. * @param hasSpaceBefore Whether we should consider there is a space inserted at the end of cs * * @return Returns the actual capitalization modes that can be in effect @@ -83,7 +83,7 @@ public final class CapsModeUtils { * {@link TextUtils#CAP_MODE_SENTENCES}. */ public static int getCapsMode(final CharSequence cs, final int reqModes, - final SettingsValues settingsValues, final boolean hasSpaceBefore) { + final SpacingAndPunctuations spacingAndPunctuations, final boolean hasSpaceBefore) { // Quick description of what we want to do: // CAP_MODE_CHARACTERS is always on. // CAP_MODE_WORDS is on if there is some whitespace before the cursor. @@ -139,6 +139,20 @@ public final class CapsModeUtils { j--; } if (j <= 0 || Character.isWhitespace(prevChar)) { + if (spacingAndPunctuations.mUsesGermanRules) { + // In German typography rules, there is a specific case that the first character + // of a new line should not be capitalized if the previous line ends in a comma. + boolean hasNewLine = false; + while (--j >= 0 && Character.isWhitespace(prevChar)) { + if (Constants.CODE_ENTER == prevChar) { + hasNewLine = true; + } + prevChar = cs.charAt(j); + } + if (Constants.CODE_COMMA == prevChar && hasNewLine) { + return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes; + } + } // There are only spacing chars between the start of the paragraph and the cursor, // defined as a isWhitespace() char that is neither a isSpaceChar() nor a tab. Both // MODE_WORDS and MODE_SENTENCES should be active. @@ -167,8 +181,7 @@ public final class CapsModeUtils { // No other language has such a rule as far as I know, instead putting inside the quotation // mark as the exact thing quoted and handling the surrounding punctuation independently, // e.g. <<Did he say, "let's go home"?>> - // Hence, specifically for English, we treat this special case here. - if (Locale.ENGLISH.getLanguage().equals(settingsValues.mLocale.getLanguage())) { + if (spacingAndPunctuations.mUsesAmericanTypography) { for (; j > 0; j--) { // Here we look to go over any closing punctuation. This is because in dominant // variants of English, the final period is placed within double quotes and maybe @@ -191,7 +204,7 @@ public final class CapsModeUtils { if (c == Constants.CODE_QUESTION_MARK || c == Constants.CODE_EXCLAMATION_MARK) { return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_SENTENCES) & reqModes; } - if (settingsValues.mSentenceSeparator != c || j <= 0) { + if (!spacingAndPunctuations.isSentenceSeparator(c) || j <= 0) { return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes; } @@ -241,7 +254,7 @@ public final class CapsModeUtils { case WORD: if (Character.isLetter(c)) { state = WORD; - } else if (settingsValues.mSentenceSeparator == c) { + } else if (spacingAndPunctuations.isSentenceSeparator(c)) { state = PERIOD; } else { return caps; @@ -257,7 +270,7 @@ public final class CapsModeUtils { case LETTER: if (Character.isLetter(c)) { state = LETTER; - } else if (settingsValues.mSentenceSeparator == c) { + } else if (spacingAndPunctuations.isSentenceSeparator(c)) { state = PERIOD; } else { return noCaps; diff --git a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java index cc25102ce..bbfa0f091 100644 --- a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java @@ -102,4 +102,19 @@ public final class CollectionUtils { public static <E> SparseArray<E> newSparseArray() { return new SparseArray<E>(); } + + public static <E> ArrayList<E> arrayAsList(final E[] array, final int start, final int end) { + if (array == null) { + throw new NullPointerException(); + } + if (start < 0 || start > end || end > array.length) { + throw new IllegalArgumentException(); + } + + final ArrayList<E> list = newArrayList(end - start); + for (int i = start; i < end; i++) { + list.add(array[i]); + } + return list; + } } diff --git a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java new file mode 100644 index 000000000..c66007537 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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.utils; + +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; + +import java.util.HashMap; + +public class CombinedFormatUtils { + public static final String DICTIONARY_TAG = "dictionary"; + public static final String BIGRAM_TAG = "bigram"; + public static final String SHORTCUT_TAG = "shortcut"; + public static final String PROBABILITY_TAG = "f"; + public static final String HISTORICAL_INFO_TAG = "historicalInfo"; + public static final String HISTORICAL_INFO_SEPARATOR = ":"; + public static final String WORD_TAG = "word"; + public static final String NOT_A_WORD_TAG = "not_a_word"; + public static final String BLACKLISTED_TAG = "blacklisted"; + + public static String formatAttributeMap(final HashMap<String, String> attributeMap) { + final StringBuilder builder = new StringBuilder(); + builder.append(DICTIONARY_TAG + "="); + if (attributeMap.containsKey(DictionaryHeader.DICTIONARY_ID_KEY)) { + builder.append(attributeMap.get(DictionaryHeader.DICTIONARY_ID_KEY)); + } + for (final String key : attributeMap.keySet()) { + if (key.equals(DictionaryHeader.DICTIONARY_ID_KEY)) { + continue; + } + final String value = attributeMap.get(key); + builder.append("," + key + "=" + value); + } + builder.append("\n"); + return builder.toString(); + } + + public static String formatWordProperty(final WordProperty wordProperty) { + final StringBuilder builder = new StringBuilder(); + builder.append(" " + WORD_TAG + "=" + wordProperty.mWord); + builder.append(","); + builder.append(formatProbabilityInfo(wordProperty.mProbabilityInfo)); + if (wordProperty.mIsNotAWord) { + builder.append("," + NOT_A_WORD_TAG + "=true"); + } + if (wordProperty.mIsBlacklistEntry) { + builder.append("," + BLACKLISTED_TAG + "=true"); + } + builder.append("\n"); + if (wordProperty.mShortcutTargets != null) { + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + builder.append(" " + SHORTCUT_TAG + "=" + shortcutTarget.mWord); + builder.append(","); + builder.append(formatProbabilityInfo(shortcutTarget.mProbabilityInfo)); + builder.append("\n"); + } + } + if (wordProperty.mBigrams != null) { + for (final WeightedString bigram : wordProperty.mBigrams) { + builder.append(" " + BIGRAM_TAG + "=" + bigram.mWord); + builder.append(","); + builder.append(formatProbabilityInfo(bigram.mProbabilityInfo)); + builder.append("\n"); + } + } + return builder.toString(); + } + + public static String formatProbabilityInfo(final ProbabilityInfo probabilityInfo) { + final StringBuilder builder = new StringBuilder(); + builder.append(PROBABILITY_TAG + "=" + probabilityInfo.mProbability); + if (probabilityInfo.hasHistoricalInfo()) { + builder.append(","); + builder.append(HISTORICAL_INFO_TAG + "="); + builder.append(probabilityInfo.mTimestamp); + builder.append(HISTORICAL_INFO_SEPARATOR); + builder.append(probabilityInfo.mLevel); + builder.append(HISTORICAL_INFO_SEPARATOR); + builder.append(probabilityInfo.mCount); + } + return builder.toString(); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java index 72f2cd2d9..87df013a6 100644 --- a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java @@ -16,17 +16,19 @@ package com.android.inputmethod.latin.utils; +import java.util.Arrays; + public final class CoordinateUtils { private static final int INDEX_X = 0; private static final int INDEX_Y = 1; - private static final int ARRAY_SIZE = INDEX_Y + 1; + private static final int ELEMENT_SIZE = INDEX_Y + 1; private CoordinateUtils() { // This utility class is not publicly instantiable. } public static int[] newInstance() { - return new int[ARRAY_SIZE]; + return new int[ELEMENT_SIZE]; } public static int x(final int[] coords) { @@ -46,4 +48,44 @@ public final class CoordinateUtils { destination[INDEX_X] = source[INDEX_X]; destination[INDEX_Y] = source[INDEX_Y]; } + + public static int[] newCoordinateArray(final int arraySize) { + return new int[ELEMENT_SIZE * arraySize]; + } + + public static int[] newCoordinateArray(final int arraySize, + final int defaultX, final int defaultY) { + final int[] result = new int[ELEMENT_SIZE * arraySize]; + for (int i = 0; i < arraySize; ++i) { + setXYInArray(result, i, defaultX, defaultY); + } + return result; + } + + public static int xFromArray(final int[] coordsArray, final int index) { + return coordsArray[ELEMENT_SIZE * index + INDEX_X]; + } + + public static int yFromArray(final int[] coordsArray, final int index) { + return coordsArray[ELEMENT_SIZE * index + INDEX_Y]; + } + + public static int[] coordinateFromArray(final int[] coordsArray, final int index) { + final int baseIndex = ELEMENT_SIZE * index; + return Arrays.copyOfRange(coordsArray, baseIndex, baseIndex + ELEMENT_SIZE); + } + + public static void setXYInArray(final int[] coordsArray, final int index, + final int x, final int y) { + final int baseIndex = ELEMENT_SIZE * index; + coordsArray[baseIndex + INDEX_X] = x; + coordsArray[baseIndex + INDEX_Y] = y; + } + + public static void setCoordinateInArray(final int[] coordsArray, final int index, + final int[] coords) { + final int baseIndex = ELEMENT_SIZE * index; + coordsArray[baseIndex + INDEX_X] = coords[INDEX_X]; + coordsArray[baseIndex + INDEX_Y] = coords[INDEX_Y]; + } } diff --git a/java/src/com/android/inputmethod/latin/utils/CsvUtils.java b/java/src/com/android/inputmethod/latin/utils/CsvUtils.java index 36b927eea..b18a1d83b 100644 --- a/java/src/com/android/inputmethod/latin/utils/CsvUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CsvUtils.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.Constants; import java.util.ArrayList; @@ -57,9 +58,9 @@ public final class CsvUtils { // Note that none of these characters match high or low surrogate characters, so we need not // take care of matching by code point. - private static final char COMMA = ','; - private static final char SPACE = ' '; - private static final char QUOTE = '"'; + private static final char COMMA = Constants.CODE_COMMA; + private static final char SPACE = Constants.CODE_SPACE; + private static final char QUOTE = Constants.CODE_DOUBLE_QUOTE; @SuppressWarnings("serial") public static class CsvParseException extends RuntimeException { diff --git a/java/src/com/android/inputmethod/latin/utils/DialogUtils.java b/java/src/com/android/inputmethod/latin/utils/DialogUtils.java new file mode 100644 index 000000000..a05c932d0 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/DialogUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.content.Context; +import android.view.ContextThemeWrapper; + +import com.android.inputmethod.latin.R; + +public final class DialogUtils { + private DialogUtils() { + // This utility class is not publicly instantiable. + } + + public static Context getPlatformDialogThemeContext(final Context context) { + // Because {@link AlertDialog.Builder.create()} doesn't honor the specified theme with + // createThemeContextWrapper=false, the result dialog box has unneeded paddings around it. + return new ContextThemeWrapper(context, R.style.platformDialogTheme); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java index 021bf0825..315913e2f 100644 --- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java @@ -20,15 +20,19 @@ import android.content.ContentValues; import android.content.Context; import android.content.res.AssetManager; import android.content.res.Resources; +import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.latin.AssetFileAddress; import com.android.inputmethod.latin.BinaryDictionaryGetter; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; @@ -278,14 +282,36 @@ public class DictionaryInfoUtils { BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale.getLanguage().toString(); } - public static FileHeader getDictionaryFileHeaderOrNull(final File file) { - return BinaryDictIOUtils.getDictionaryFileHeaderOrNull(file, 0, file.length()); + public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file) { + return getDictionaryFileHeaderOrNull(file, 0, file.length()); } + private static DictionaryHeader getDictionaryFileHeaderOrNull(final File file, + final long offset, final long length) { + try { + final DictionaryHeader header = + BinaryDictionaryUtils.getHeaderWithOffsetAndLength(file, offset, length); + return header; + } catch (UnsupportedFormatException e) { + return null; + } catch (IOException e) { + return null; + } + } + + /** + * Returns information of the dictionary. + * + * @param fileAddress the asset dictionary file address. + * @return information of the specified dictionary. + */ private static DictionaryInfo createDictionaryInfoFromFileAddress( final AssetFileAddress fileAddress) { - final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeaderOrNull( + final DictionaryHeader header = getDictionaryFileHeaderOrNull( new File(fileAddress.mFilename), fileAddress.mOffset, fileAddress.mLength); + if (header == null) { + return null; + } final String id = header.getId(); final Locale locale = LocaleUtils.constructLocaleFromString(header.getLocaleString()); final String description = header.getDescription(); @@ -328,7 +354,7 @@ public class DictionaryInfoUtils { // Protect against cases of a less-specific dictionary being found, like an // en dictionary being used for an en_US locale. In this case, the en dictionary // should be used for en_US but discounted for listing purposes. - if (!dictionaryInfo.mLocale.equals(locale)) continue; + if (dictionaryInfo == null || !dictionaryInfo.mLocale.equals(locale)) continue; addOrUpdateDictInfo(dictList, dictionaryInfo); } } @@ -355,4 +381,32 @@ public class DictionaryInfoUtils { return dictList; } + + public static boolean looksValidForDictionaryInsertion(final CharSequence text, + final SpacingAndPunctuations spacingAndPunctuations) { + if (TextUtils.isEmpty(text)) return false; + final int length = text.length(); + // TODO: Make this test "length > Constants.DICTIONARY_MAX_WORD_LENGTH". + if (length >= Constants.DICTIONARY_MAX_WORD_LENGTH) { + return false; + } + int i = 0; + int digitCount = 0; + while (i < length) { + final int codePoint = Character.codePointAt(text, i); + final int charCount = Character.charCount(codePoint); + i += charCount; + if (Character.isDigit(codePoint)) { + // Count digits: see below + digitCount += charCount; + continue; + } + if (!spacingAndPunctuations.isWordCodePoint(codePoint)) return false; + } + // We reject strings entirely comprised of digits to avoid using PIN codes or credit + // card numbers. It would come in handy for word prediction though; a good example is + // when writing one's address where the street number is usually quite discriminative, + // as well as the postal code. + return digitCount < length; + } } diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java new file mode 100644 index 000000000..f2a1e524d --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 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.utils; + +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.Suggest; + +/** + * This class is used to prevent distracters/misspellings being added to personalization + * or user history dictionaries + */ +public class DistracterFilter { + private final Suggest mSuggest; + private final Keyboard mKeyboard; + + /** + * Create a DistracterFilter instance. + * + * @param suggest an instance of Suggest which will be used to obtain a list of suggestions + * for a potential distracter/misspelling + * @param keyboard the keyboard that is currently being used. This information is needed + * when calling mSuggest.getSuggestedWords(...) to obtain a list of suggestions. + */ + public DistracterFilter(final Suggest suggest, final Keyboard keyboard) { + mSuggest = suggest; + mKeyboard = keyboard; + } + + public boolean isDistractorToWordsInDictionaries(final String prevWord, + final String targetWord) { + // TODO: to be implemented + return false; + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java new file mode 100644 index 000000000..ed502ed3d --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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.utils; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * Utilities to manage executors. + */ +public class ExecutorUtils { + private static final ConcurrentHashMap<String, PrioritizedSerialExecutor> + sExecutorMap = CollectionUtils.newConcurrentHashMap(); + /** + * Gets the executor for the given dictionary name. + */ + public static PrioritizedSerialExecutor getExecutor(final String dictName) { + PrioritizedSerialExecutor executor = sExecutorMap.get(dictName); + if (executor == null) { + synchronized(sExecutorMap) { + executor = new PrioritizedSerialExecutor(); + sExecutorMap.put(dictName, executor); + } + } + return executor; + } + + /** + * Shutdowns all executors and removes all executors from the executor map for testing. + */ + @UsedForTesting + public static void shutdownAllExecutors() { + synchronized(sExecutorMap) { + for (final PrioritizedSerialExecutor executor : sExecutorMap.values()) { + executor.execute(new Runnable() { + @Override + public void run() { + executor.shutdown(); + sExecutorMap.remove(executor); + } + }); + } + } + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/FileUtils.java b/java/src/com/android/inputmethod/latin/utils/FileUtils.java new file mode 100644 index 000000000..f1106a6c6 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/FileUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 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.utils; + +import java.io.File; +import java.io.FilenameFilter; + +/** + * A simple class to help with removing directories recursively. + */ +public class FileUtils { + public static boolean deleteRecursively(final File path) { + if (path.isDirectory()) { + final File[] files = path.listFiles(); + if (files != null) { + for (final File child : files) { + deleteRecursively(child); + } + } + } + return path.delete(); + } + + public static boolean deleteFilteredFiles(final File dir, final FilenameFilter fileNameFilter) { + if (!dir.isDirectory()) { + return false; + } + final File[] files = dir.listFiles(fileNameFilter); + if (files == null) { + return false; + } + boolean hasDeletedAllFiles = true; + for (final File file : files) { + if (!deleteRecursively(file)) { + hasDeletedAllFiles = false; + } + } + return hasDeletedAllFiles; + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java new file mode 100644 index 000000000..7d937a9d2 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.text.TextUtils; +import android.util.Log; + +import com.android.inputmethod.latin.InputAttributes; +import com.android.inputmethod.latin.R; + +public final class ImportantNoticeUtils { + private static final String TAG = ImportantNoticeUtils.class.getSimpleName(); + + // {@link SharedPreferences} name to save the last important notice version that has been + // displayed to users. + private static final String PREFERENCE_NAME = "important_notice_pref"; + private static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version"; + public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 1; + + // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key. + // The value is zero until each multiuser completes system setup wizard. + // Caveat: This is a hidden API. + private static final String Settings_Secure_USER_SETUP_COMPLETE = "user_setup_complete"; + private static final int USER_SETUP_IS_NOT_COMPLETE = 0; + + private ImportantNoticeUtils() { + // This utility class is not publicly instantiable. + } + + private static boolean isInSystemSetupWizard(final Context context) { + try { + final int userSetupComplete = Settings.Secure.getInt( + context.getContentResolver(), Settings_Secure_USER_SETUP_COMPLETE); + return userSetupComplete == USER_SETUP_IS_NOT_COMPLETE; + } catch (final SettingNotFoundException e) { + Log.w(TAG, "Can't find settings in Settings.Secure: key=" + + Settings_Secure_USER_SETUP_COMPLETE); + return false; + } + } + + private static SharedPreferences getImportantNoticePreferences(final Context context) { + return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + } + + private static int getCurrentImportantNoticeVersion(final Context context) { + return context.getResources().getInteger(R.integer.config_important_notice_version); + } + + private static int getLastImportantNoticeVersion(final Context context) { + return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0); + } + + public static int getNextImportantNoticeVersion(final Context context) { + return getLastImportantNoticeVersion(context) + 1; + } + + private static boolean hasNewImportantNotice(final Context context) { + final int lastVersion = getLastImportantNoticeVersion(context); + return getCurrentImportantNoticeVersion(context) > lastVersion; + } + + public static boolean shouldShowImportantNotice(final Context context, + final InputAttributes inputAttributes) { + if (inputAttributes == null || inputAttributes.mIsPasswordField) { + return false; + } + if (isInSystemSetupWizard(context)) { + return false; + } + if (!hasNewImportantNotice(context)) { + return false; + } + final String importantNoticeTitle = getNextImportantNoticeTitle(context); + if (TextUtils.isEmpty(importantNoticeTitle)) { + return false; + } + return true; + } + + public static void updateLastImportantNoticeVersion(final Context context) { + getImportantNoticePreferences(context) + .edit() + .putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context)) + .apply(); + } + + public static String getNextImportantNoticeTitle(final Context context) { + final int nextVersion = getCurrentImportantNoticeVersion(context); + final String[] importantNoticeTitleArray = context.getResources().getStringArray( + R.array.important_notice_title_array); + if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) { + return importantNoticeTitleArray[nextVersion]; + } + return null; + } + + public static String getNextImportantNoticeContents(final Context context) { + final int nextVersion = getNextImportantNoticeVersion(context); + final String[] importantNoticeContentsArray = context.getResources().getStringArray( + R.array.important_notice_contents_array); + if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) { + return importantNoticeContentsArray[nextVersion]; + } + return null; + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/JsonUtils.java b/java/src/com/android/inputmethod/latin/utils/JsonUtils.java new file mode 100644 index 000000000..764ef72ce --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/JsonUtils.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 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.utils; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import java.io.Closeable; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class JsonUtils { + private static final String TAG = JsonUtils.class.getSimpleName(); + + private static final String INTEGER_CLASS_NAME = Integer.class.getSimpleName(); + private static final String STRING_CLASS_NAME = String.class.getSimpleName(); + + private static final String EMPTY_STRING = ""; + + public static List<Object> jsonStrToList(final String s) { + final ArrayList<Object> list = CollectionUtils.newArrayList(); + final JsonReader reader = new JsonReader(new StringReader(s)); + try { + reader.beginArray(); + while (reader.hasNext()) { + reader.beginObject(); + while (reader.hasNext()) { + final String name = reader.nextName(); + if (name.equals(INTEGER_CLASS_NAME)) { + list.add(reader.nextInt()); + } else if (name.equals(STRING_CLASS_NAME)) { + list.add(reader.nextString()); + } else { + Log.w(TAG, "Invalid name: " + name); + reader.skipValue(); + } + } + reader.endObject(); + } + reader.endArray(); + return list; + } catch (final IOException e) { + } finally { + close(reader); + } + return Collections.<Object>emptyList(); + } + + public static String listToJsonStr(final List<Object> list) { + if (list == null || list.isEmpty()) { + return EMPTY_STRING; + } + final StringWriter sw = new StringWriter(); + final JsonWriter writer = new JsonWriter(sw); + try { + writer.beginArray(); + for (final Object o : list) { + writer.beginObject(); + if (o instanceof Integer) { + writer.name(INTEGER_CLASS_NAME).value((Integer)o); + } else if (o instanceof String) { + writer.name(STRING_CLASS_NAME).value((String)o); + } + writer.endObject(); + } + writer.endArray(); + return sw.toString(); + } catch (final IOException e) { + } finally { + close(writer); + } + return EMPTY_STRING; + } + + private static void close(final Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (final IOException e) { + // Ignore + } + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java new file mode 100644 index 000000000..5ce977d5e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.util.Log; + +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; + +import java.util.ArrayList; +import java.util.Locale; + +// Note: this class is used as a parameter type of a native method. You should be careful when you +// rename this class or field name. See BinaryDictionary#addMultipleDictionaryEntriesNative(). +public final class LanguageModelParam { + private static final String TAG = LanguageModelParam.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final boolean DEBUG_TOKEN = false; + + // For now, these probability values are being referred to only when we add new entries to + // decaying dynamic binary dictionaries. When these are referred to, what matters is 0 or + // non-0. Thus, it's not meaningful to compare 10, 100, and so on. + // TODO: Revise the logic in ForgettingCurveUtils in native code. + private static final int UNIGRAM_PROBABILITY_FOR_VALID_WORD = 100; + private static final int UNIGRAM_PROBABILITY_FOR_OOV_WORD = Dictionary.NOT_A_PROBABILITY; + private static final int BIGRAM_PROBABILITY_FOR_VALID_WORD = 10; + private static final int BIGRAM_PROBABILITY_FOR_OOV_WORD = Dictionary.NOT_A_PROBABILITY; + + public final String mTargetWord; + public final int[] mWord0; + public final int[] mWord1; + // TODO: this needs to be a list of shortcuts + public final int[] mShortcutTarget; + public final int mUnigramProbability; + public final int mBigramProbability; + public final int mShortcutProbability; + public final boolean mIsNotAWord; + public final boolean mIsBlacklisted; + // Time stamp in seconds. + public final int mTimestamp; + + // Constructor for unigram. TODO: support shortcuts + public LanguageModelParam(final String word, final int unigramProbability, + final int timestamp) { + this(null /* word0 */, word, unigramProbability, Dictionary.NOT_A_PROBABILITY, timestamp); + } + + // Constructor for unigram and bigram. + public LanguageModelParam(final String word0, final String word1, + final int unigramProbability, final int bigramProbability, + final int timestamp) { + mTargetWord = word1; + mWord0 = (word0 == null) ? null : StringUtils.toCodePointArray(word0); + mWord1 = StringUtils.toCodePointArray(word1); + mShortcutTarget = null; + mUnigramProbability = unigramProbability; + mBigramProbability = bigramProbability; + mShortcutProbability = Dictionary.NOT_A_PROBABILITY; + mIsNotAWord = false; + mIsBlacklisted = false; + mTimestamp = timestamp; + } + + // Process a list of words and return a list of {@link LanguageModelParam} objects. + public static ArrayList<LanguageModelParam> createLanguageModelParamsFrom( + final ArrayList<String> tokens, final int timestamp, + final DictionaryFacilitatorForSuggest dictionaryFacilitator, + final SpacingAndPunctuations spacingAndPunctuations) { + final ArrayList<LanguageModelParam> languageModelParams = + CollectionUtils.newArrayList(); + final int N = tokens.size(); + String prevWord = null; + for (int i = 0; i < N; ++i) { + final String tempWord = tokens.get(i); + if (StringUtils.isEmptyStringOrWhiteSpaces(tempWord)) { + // just skip this token + if (DEBUG_TOKEN) { + Log.d(TAG, "--- isEmptyStringOrWhiteSpaces: \"" + tempWord + "\""); + } + continue; + } + if (!DictionaryInfoUtils.looksValidForDictionaryInsertion( + tempWord, spacingAndPunctuations)) { + if (DEBUG_TOKEN) { + Log.d(TAG, "--- not looksValidForDictionaryInsertion: \"" + + tempWord + "\""); + } + // Sentence terminator found. Split. + prevWord = null; + continue; + } + if (DEBUG_TOKEN) { + Log.d(TAG, "--- word: \"" + tempWord + "\""); + } + final LanguageModelParam languageModelParam = + detectWhetherVaildWordOrNotAndGetLanguageModelParam( + prevWord, tempWord, timestamp, dictionaryFacilitator); + if (languageModelParam == null) { + continue; + } + languageModelParams.add(languageModelParam); + prevWord = languageModelParam.mTargetWord; + } + return languageModelParams; + } + + private static LanguageModelParam detectWhetherVaildWordOrNotAndGetLanguageModelParam( + final String prevWord, final String targetWord, final int timestamp, + final DictionaryFacilitatorForSuggest dictionaryFacilitator) { + final Locale locale = dictionaryFacilitator.getLocale(); + if (locale == null) { + return null; + } + if (!dictionaryFacilitator.isValidWord(targetWord, true /* ignoreCase */)) { + // OOV word. + return createAndGetLanguageModelParamOfWord(prevWord, targetWord, timestamp, + false /* isValidWord */, locale); + } + if (dictionaryFacilitator.isValidWord(targetWord, false /* ignoreCase */)) { + return createAndGetLanguageModelParamOfWord(prevWord, targetWord, timestamp, + true /* isValidWord */, locale); + } + final String lowerCaseTargetWord = targetWord.toLowerCase(locale); + if (dictionaryFacilitator.isValidWord(lowerCaseTargetWord, false /* ignoreCase */)) { + // Add the lower-cased word. + return createAndGetLanguageModelParamOfWord(prevWord, lowerCaseTargetWord, + timestamp, true /* isValidWord */, locale); + } + // Treat the word as an OOV word. + return createAndGetLanguageModelParamOfWord(prevWord, targetWord, timestamp, + false /* isValidWord */, locale); + } + + private static LanguageModelParam createAndGetLanguageModelParamOfWord( + final String prevWord, final String targetWord, final int timestamp, + final boolean isValidWord, final Locale locale) { + final String word; + if (StringUtils.getCapitalizationType(targetWord) == StringUtils.CAPITALIZE_FIRST + && prevWord == null && !isValidWord) { + word = targetWord.toLowerCase(locale); + } else { + word = targetWord; + } + final int unigramProbability = isValidWord ? + UNIGRAM_PROBABILITY_FOR_VALID_WORD : UNIGRAM_PROBABILITY_FOR_OOV_WORD; + if (prevWord == null) { + if (DEBUG) { + Log.d(TAG, "--- add unigram: current(" + + (isValidWord ? "Valid" : "OOV") + ") = " + word); + } + return new LanguageModelParam(word, unigramProbability, timestamp); + } + if (DEBUG) { + Log.d(TAG, "--- add bigram: prev = " + prevWord + ", current(" + + (isValidWord ? "Valid" : "OOV") + ") = " + word); + } + final int bigramProbability = isValidWord ? + BIGRAM_PROBABILITY_FOR_VALID_WORD : BIGRAM_PROBABILITY_FOR_OOV_WORD; + return new LanguageModelParam(prevWord, word, unigramProbability, + bigramProbability, timestamp); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java b/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java index e958a7e71..d14ba508b 100644 --- a/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java @@ -35,7 +35,7 @@ public final class LatinImeLoggerUtils { public static void onSeparator(final int code, final int x, final int y) { // Helper method to log a single code point separator // TODO: cache this mapping of a code point to a string in a sparse array in StringUtils - onSeparator(new String(new int[]{code}, 0, 1), x, y); + onSeparator(StringUtils.newSingleCodePointString(code), x, y); } public static void onSeparator(final String separator, final int x, final int y) { diff --git a/java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java b/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java index 44e5d17b4..8469c87b0 100644 --- a/java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java +++ b/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java @@ -21,22 +21,22 @@ import android.os.Looper; import java.lang.ref.WeakReference; -public class StaticInnerHandlerWrapper<T> extends Handler { - private final WeakReference<T> mOuterInstanceRef; +public class LeakGuardHandlerWrapper<T> extends Handler { + private final WeakReference<T> mOwnerInstanceRef; - public StaticInnerHandlerWrapper(final T outerInstance) { - this(outerInstance, Looper.myLooper()); + public LeakGuardHandlerWrapper(final T ownerInstance) { + this(ownerInstance, Looper.myLooper()); } - public StaticInnerHandlerWrapper(final T outerInstance, final Looper looper) { + public LeakGuardHandlerWrapper(final T ownerInstance, final Looper looper) { super(looper); - if (outerInstance == null) { - throw new NullPointerException("outerInstance is null"); + if (ownerInstance == null) { + throw new NullPointerException("ownerInstance is null"); } - mOuterInstanceRef = new WeakReference<T>(outerInstance); + mOwnerInstanceRef = new WeakReference<T>(ownerInstance); } - public T getOuterInstance() { - return mOuterInstanceRef.get(); + public T getOwnerInstance() { + return mOwnerInstanceRef.get(); } } diff --git a/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java index 22045aa38..0c55484b4 100644 --- a/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java @@ -30,9 +30,6 @@ import java.util.Locale; * dictionary pack. */ public final class LocaleUtils { - private static final HashMap<String, Long> EMPTY_LT_HASH_MAP = CollectionUtils.newHashMap(); - private static final String LOCALE_AND_TIME_STR_SEPARATER = ","; - private LocaleUtils() { // Intentional empty constructor for utility class. } @@ -168,12 +165,14 @@ public final class LocaleUtils { * Creates a locale from a string specification. */ public static Locale constructLocaleFromString(final String localeStr) { - if (localeStr == null) + if (localeStr == null) { return null; + } synchronized (sLocaleCache) { - if (sLocaleCache.containsKey(localeStr)) - return sLocaleCache.get(localeStr); - Locale retval = null; + Locale retval = sLocaleCache.get(localeStr); + if (retval != null) { + return retval; + } String[] localeParams = localeStr.split("_", 3); if (localeParams.length == 1) { retval = new Locale(localeParams[0]); @@ -188,38 +187,4 @@ public final class LocaleUtils { return retval; } } - - public static HashMap<String, Long> localeAndTimeStrToHashMap(String str) { - if (TextUtils.isEmpty(str)) { - return EMPTY_LT_HASH_MAP; - } - final String[] ss = str.split(LOCALE_AND_TIME_STR_SEPARATER); - final int N = ss.length; - if (N < 2 || N % 2 != 0) { - return EMPTY_LT_HASH_MAP; - } - final HashMap<String, Long> retval = CollectionUtils.newHashMap(); - for (int i = 0; i < N / 2; ++i) { - final String localeStr = ss[i * 2]; - final long time = Long.valueOf(ss[i * 2 + 1]); - retval.put(localeStr, time); - } - return retval; - } - - public static String localeAndTimeHashMapToStr(HashMap<String, Long> map) { - if (map == null || map.isEmpty()) { - return ""; - } - final StringBuilder builder = new StringBuilder(); - for (String localeStr : map.keySet()) { - if (builder.length() > 0) { - builder.append(LOCALE_AND_TIME_STR_SEPARATER); - } - final Long time = map.get(localeStr); - builder.append(localeStr).append(LOCALE_AND_TIME_STR_SEPARATER); - builder.append(String.valueOf(time)); - } - return builder.toString(); - } } diff --git a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java index 201a70d42..bf38abc95 100644 --- a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java +++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.utils; +import com.android.inputmethod.annotations.UsedForTesting; + import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -47,16 +49,6 @@ public class PrioritizedSerialExecutor { } /** - * Clears all queued tasks. - */ - public void clearAllTasks() { - synchronized(mLock) { - mTasks.clear(); - mPrioritizedTasks.clear(); - } - } - - /** * Enqueues the given task into the task queue. * @param r the enqueued task */ @@ -84,6 +76,7 @@ public class PrioritizedSerialExecutor { * Enqueues the given task into the prioritized task queue. * @param r the enqueued task */ + @UsedForTesting public void executePrioritized(final Runnable r) { synchronized(mLock) { if (!mIsShutdown) { @@ -120,32 +113,10 @@ public class PrioritizedSerialExecutor { } } - public void remove(final Runnable r) { - synchronized(mLock) { - mTasks.remove(r); - mPrioritizedTasks.remove(r); - } - } - - public void replaceAndExecute(final Runnable oldTask, final Runnable newTask) { - synchronized(mLock) { - if (oldTask != null) remove(oldTask); - execute(newTask); - } - } - public void shutdown() { synchronized(mLock) { mIsShutdown = true; - } - } - - public boolean isTerminated() { - synchronized(mLock) { - if (!mIsShutdown) { - return false; - } - return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null; + mThreadPoolExecutor.shutdown(); } } } diff --git a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java index 0f5cd80db..4521ec531 100644 --- a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java +++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java @@ -37,12 +37,12 @@ public class RecapitalizeStatus { CAPS_MODE_ALL_UPPER }; - private static final int getStringMode(final String string, final String separators) { + private static final int getStringMode(final String string, final int[] sortedSeparators) { if (StringUtils.isIdenticalAfterUpcase(string)) { return CAPS_MODE_ALL_UPPER; } else if (StringUtils.isIdenticalAfterDowncase(string)) { return CAPS_MODE_ALL_LOWER; - } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, separators)) { + } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, sortedSeparators)) { return CAPS_MODE_FIRST_WORD_UPPER; } else { return CAPS_MODE_ORIGINAL_MIXED_CASE; @@ -60,26 +60,28 @@ public class RecapitalizeStatus { private int mRotationStyleCurrentIndex; private boolean mSkipOriginalMixedCaseMode; private Locale mLocale; - private String mSeparators; + private int[] mSortedSeparators; private String mStringAfter; private boolean mIsActive; + private static final int[] EMPTY_STORTED_SEPARATORS = {}; + public RecapitalizeStatus() { // By default, initialize with dummy values that won't match any real recapitalize. - initialize(-1, -1, "", Locale.getDefault(), ""); + initialize(-1, -1, "", Locale.getDefault(), EMPTY_STORTED_SEPARATORS); deactivate(); } public void initialize(final int cursorStart, final int cursorEnd, final String string, - final Locale locale, final String separators) { + final Locale locale, final int[] sortedSeparators) { mCursorStartBefore = cursorStart; mStringBefore = string; mCursorStartAfter = cursorStart; mCursorEndAfter = cursorEnd; mStringAfter = string; - final int initialMode = getStringMode(mStringBefore, separators); + final int initialMode = getStringMode(mStringBefore, sortedSeparators); mLocale = locale; - mSeparators = separators; + mSortedSeparators = sortedSeparators; if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) { mRotationStyleCurrentIndex = 0; mSkipOriginalMixedCaseMode = false; @@ -131,7 +133,7 @@ public class RecapitalizeStatus { mStringAfter = mStringBefore.toLowerCase(mLocale); break; case CAPS_MODE_FIRST_WORD_UPPER: - mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators, + mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSortedSeparators, mLocale); break; case CAPS_MODE_ALL_UPPER: diff --git a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java index 7c6fe93ac..64c9e2cff 100644 --- a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java +++ b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java @@ -34,7 +34,7 @@ public final class ResizableIntArray { throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } - public void add(final int index, final int val) { + public void addAt(final int index, final int val) { if (index < mLength) { mArray[index] = val; } else { diff --git a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java index 22c92446a..49f4929b4 100644 --- a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java @@ -67,7 +67,8 @@ public final class ResourceUtils { sBuildKeyValuesDebugString = "[" + TextUtils.join(" ", keyValuePairs) + "]"; } - public static String getDeviceOverrideValue(final Resources res, final int overrideResId) { + public static String getDeviceOverrideValue(final Resources res, final int overrideResId, + final String defaultValue) { final int orientation = res.getConfiguration().orientation; final String key = overrideResId + "-" + orientation; if (sDeviceOverrideValueMap.containsKey(key)) { @@ -86,23 +87,6 @@ public final class ResourceUtils { return overrideValue; } - String defaultValue = null; - try { - defaultValue = findDefaultConstant(overrideArray); - // The defaultValue might be an empty string. - if (defaultValue == null) { - Log.w(TAG, "Couldn't find override value nor default value:" - + " resource="+ res.getResourceEntryName(overrideResId) - + " build=" + sBuildKeyValuesDebugString); - } else { - Log.i(TAG, "Found default value:" - + " resource="+ res.getResourceEntryName(overrideResId) - + " build=" + sBuildKeyValuesDebugString - + " default=" + defaultValue); - } - } catch (final DeviceOverridePatternSyntaxError e) { - Log.w(TAG, "Syntax error, ignored", e); - } sDeviceOverrideValueMap.put(key, defaultValue); return defaultValue; } @@ -152,8 +136,7 @@ public final class ResourceUtils { } final String condition = conditionConstant.substring(0, posComma); if (condition.isEmpty()) { - // Default condition. The default condition should be searched by - // {@link #findConstantForDefault(String[])}. + Log.w(TAG, "Array element has no condition: " + conditionConstant); continue; } try { @@ -199,24 +182,6 @@ public final class ResourceUtils { return matchedAll; } - @UsedForTesting - static String findDefaultConstant(final String[] conditionConstantArray) - throws DeviceOverridePatternSyntaxError { - if (conditionConstantArray == null) { - return null; - } - for (final String condition : conditionConstantArray) { - final int posComma = condition.indexOf(','); - if (posComma < 0) { - throw new DeviceOverridePatternSyntaxError("Array element has no comma", condition); - } - if (posComma == 0) { // condition is empty. - return condition.substring(posComma + 1); - } - } - return null; - } - public static int getDefaultKeyboardWidth(final Resources res) { final DisplayMetrics dm = res.getDisplayMetrics(); return dm.widthPixels; @@ -224,22 +189,23 @@ public final class ResourceUtils { public static int getDefaultKeyboardHeight(final Resources res) { final DisplayMetrics dm = res.getDisplayMetrics(); - final String keyboardHeightString = getDeviceOverrideValue(res, R.array.keyboard_heights); + final String keyboardHeightInDp = getDeviceOverrideValue( + res, R.array.keyboard_heights, null /* defaultValue */); final float keyboardHeight; - if (TextUtils.isEmpty(keyboardHeightString)) { - keyboardHeight = res.getDimension(R.dimen.keyboardHeight); + if (TextUtils.isEmpty(keyboardHeightInDp)) { + keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height); } else { - keyboardHeight = Float.parseFloat(keyboardHeightString) * dm.density; + keyboardHeight = Float.parseFloat(keyboardHeightInDp) * dm.density; } final float maxKeyboardHeight = res.getFraction( - R.fraction.maxKeyboardHeight, dm.heightPixels, dm.heightPixels); + R.fraction.config_max_keyboard_height, dm.heightPixels, dm.heightPixels); float minKeyboardHeight = res.getFraction( - R.fraction.minKeyboardHeight, dm.heightPixels, dm.heightPixels); + R.fraction.config_min_keyboard_height, dm.heightPixels, dm.heightPixels); if (minKeyboardHeight < 0.0f) { // Specified fraction was negative, so it should be calculated against display // width. minKeyboardHeight = -res.getFraction( - R.fraction.minKeyboardHeight, dm.widthPixels, dm.widthPixels); + R.fraction.config_min_keyboard_height, dm.widthPixels, dm.widthPixels); } // Keyboard height will not exceed maxKeyboardHeight and will not be less than // minKeyboardHeight. @@ -260,6 +226,10 @@ public final class ResourceUtils { return dimension >= 0; } + public static float getFloatFromFraction(final Resources res, final int fractionResId) { + return res.getFraction(fractionResId, 1, 1); + } + public static float getFraction(final TypedArray a, final int index, final float defValue) { final TypedValue value = a.peekValue(index); if (value == null || !isFractionValue(value)) { diff --git a/java/src/com/android/inputmethod/latin/utils/RunInLocale.java b/java/src/com/android/inputmethod/latin/utils/RunInLocale.java index 2c9e3b191..1ea16e6ef 100644 --- a/java/src/com/android/inputmethod/latin/utils/RunInLocale.java +++ b/java/src/com/android/inputmethod/latin/utils/RunInLocale.java @@ -30,25 +30,23 @@ public abstract class RunInLocale<T> { * Execute {@link #job(Resources)} method in specified system locale exclusively. * * @param res the resources to use. - * @param newLocale the locale to change to. + * @param newLocale the locale to change to. Run in system locale if null. * @return the value returned from {@link #job(Resources)}. */ public T runInLocale(final Resources res, final Locale newLocale) { synchronized (sLockForRunInLocale) { final Configuration conf = res.getConfiguration(); - final Locale oldLocale = conf.locale; - final boolean needsChange = (newLocale != null && !newLocale.equals(oldLocale)); + if (newLocale == null || newLocale.equals(conf.locale)) { + return job(res); + } + final Locale savedLocale = conf.locale; try { - if (needsChange) { - conf.locale = newLocale; - res.updateConfiguration(conf, null); - } + conf.locale = newLocale; + res.updateConfiguration(conf, null); return job(res); } finally { - if (needsChange) { - conf.locale = oldLocale; - res.updateConfiguration(conf, null); - } + conf.locale = savedLocale; + res.updateConfiguration(conf, null); } } } diff --git a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java new file mode 100644 index 000000000..1ca895fdb --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.view.inputmethod.InputMethodSubtype; + +public final class SpacebarLanguageUtils { + private SpacebarLanguageUtils() { + // Intentional empty constructor for utility class. + } + + // InputMethodSubtype's display name for spacebar text in its locale. + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ ------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss T Deutsch Deutsch (Schweiz) + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // zz azerty T AZERTY AZERTY + // Get InputMethodSubtype's full display name in its locale. + public static String getFullDisplayName(final InputMethodSubtype subtype) { + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); + } + return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); + } + + // Get InputMethodSubtype's middle display name in its locale. + public static String getMiddleDisplayName(final InputMethodSubtype subtype) { + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); + } + return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(subtype.getLocale()); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java index b51fd9377..38164cb36 100644 --- a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java @@ -22,6 +22,7 @@ import android.text.Spanned; import android.text.SpannedString; import android.text.TextUtils; import android.text.style.SuggestionSpan; +import android.text.style.URLSpan; public final class SpannableStringUtils { /** @@ -40,12 +41,17 @@ public final class SpannableStringUtils { * are out of range in <code>dest</code>. */ public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end, - Spannable dest, int destoff) { + Spannable dest, int destoff) { Object[] spans = source.getSpans(start, end, SuggestionSpan.class); for (int i = 0; i < spans.length; i++) { int fl = source.getSpanFlags(spans[i]); - if (0 != (fl & Spannable.SPAN_PARAGRAPH)) continue; + // We don't care about the PARAGRAPH flag in LatinIME code. However, if this flag + // is set, Spannable#setSpan will throw an exception unless the span is on the edge + // of a word. But the spans have been split into two by the getText{Before,After}Cursor + // methods, so after concatenation they may end in the middle of a word. + // Since we don't use them, we can just remove them and avoid crashing. + fl &= ~Spannable.SPAN_PARAGRAPH; int st = source.getSpanStart(spans[i]); int en = source.getSpanEnd(spans[i]); @@ -107,4 +113,16 @@ public final class SpannableStringUtils { return new SpannedString(ss); } + + public static boolean hasUrlSpans(final CharSequence text, + final int startIndex, final int endIndex) { + if (!(text instanceof Spanned)) { + return false; // Not spanned, so no link + } + final Spanned spanned = (Spanned)text; + // getSpans(x, y) does not return spans that start on x or end on y. x-1, y+1 does the + // trick, and works in all cases even if startIndex <= 0 or endIndex >= text.length(). + final URLSpan[] spans = spanned.getSpans(startIndex - 1, endIndex + 1, URLSpan.class); + return null != spans && spans.length > 0; + } } diff --git a/java/src/com/android/inputmethod/latin/utils/StatsUtils.java b/java/src/com/android/inputmethod/latin/utils/StatsUtils.java new file mode 100644 index 000000000..a059f877b --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/StatsUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.android.inputmethod.latin.settings.Settings; + +public final class StatsUtils { + private static final String TAG = StatsUtils.class.getSimpleName(); + private static final StatsUtils sInstance = new StatsUtils(); + + public static void onCreateCompleted(final Context context) { + sInstance.onCreateCompletedInternal(context); + } + + private void onCreateCompletedInternal(final Context context) { + mContext = context; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + final Boolean usePersonalizedDict = + prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true); + Log.d(TAG, "onCreateCompleted. context: " + context.toString() + "usePersonalizedDict: " + + usePersonalizedDict); + } + + public static void onDestroy() { + sInstance.onDestroyInternal(); + } + + private void onDestroyInternal() { + Log.d(TAG, "onDestroy. context: " + mContext.toString()); + mContext = null; + } + + private Context mContext; +} diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java index a36548392..374badc19 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java @@ -16,21 +16,15 @@ package com.android.inputmethod.latin.utils; -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.settings.SettingsValues; +import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; import android.text.TextUtils; -import android.util.JsonReader; -import android.util.JsonWriter; -import android.util.Log; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.Constants; + import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Arrays; import java.util.Locale; public final class StringUtils { @@ -39,6 +33,8 @@ public final class StringUtils { public static final int CAPITALIZE_FIRST = 1; // First only public static final int CAPITALIZE_ALL = 2; // All caps + private static final String EMPTY_STRING = ""; + private StringUtils() { // This utility class is not publicly instantiable. } @@ -50,7 +46,7 @@ public final class StringUtils { public static String newSingleCodePointString(int codePoint) { if (Character.charCount(codePoint) == 1) { - // Optimization: avoid creating an temporary array for characters that are + // Optimization: avoid creating a temporary array for characters that are // represented by a single char value return String.valueOf((char) codePoint); } @@ -80,6 +76,20 @@ public final class StringUtils { return containsInArray(text, extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT)); } + public static String joinCommaSplittableText(final String head, final String tail) { + if (TextUtils.isEmpty(head) && TextUtils.isEmpty(tail)) { + return EMPTY_STRING; + } + // Here either head or tail is not null. + if (TextUtils.isEmpty(head)) { + return tail; + } + if (TextUtils.isEmpty(tail)) { + return head; + } + return head + SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT + tail; + } + public static String appendToCommaSplittableTextIfNotExists(final String text, final String extraValues) { if (TextUtils.isEmpty(extraValues)) { @@ -94,7 +104,7 @@ public final class StringUtils { public static String removeFromCommaSplittableTextIfExists(final String text, final String extraValues) { if (TextUtils.isEmpty(extraValues)) { - return ""; + return EMPTY_STRING; } final String[] elements = extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT); if (!containsInArray(text, elements)) { @@ -162,20 +172,87 @@ public final class StringUtils { private static final int[] EMPTY_CODEPOINTS = {}; - public static int[] toCodePointArray(final String string) { - final int length = string.length(); + public static int[] toCodePointArray(final CharSequence charSequence) { + return toCodePointArray(charSequence, 0, charSequence.length()); + } + + /** + * Converts a range of a string to an array of code points. + * @param charSequence the source string. + * @param startIndex the start index inside the string in java chars, inclusive. + * @param endIndex the end index inside the string in java chars, exclusive. + * @return a new array of code points. At most endIndex - startIndex, but possibly less. + */ + public static int[] toCodePointArray(final CharSequence charSequence, + final int startIndex, final int endIndex) { + final int length = charSequence.length(); if (length <= 0) { return EMPTY_CODEPOINTS; } - final int[] codePoints = new int[string.codePointCount(0, length)]; + final int[] codePoints = + new int[Character.codePointCount(charSequence, startIndex, endIndex)]; + copyCodePointsAndReturnCodePointCount(codePoints, charSequence, startIndex, endIndex, + false /* downCase */); + return codePoints; + } + + /** + * Copies the codepoints in a CharSequence to an int array. + * + * This method assumes there is enough space in the array to store the code points. The size + * can be measured with Character#codePointCount(CharSequence, int, int) before passing to this + * method. If the int array is too small, an ArrayIndexOutOfBoundsException will be thrown. + * Also, this method makes no effort to be thread-safe. Do not modify the CharSequence while + * this method is running, or the behavior is undefined. + * This method can optionally downcase code points before copying them, but it pays no attention + * to locale while doing so. + * + * @param destination the int array. + * @param charSequence the CharSequence. + * @param startIndex the start index inside the string in java chars, inclusive. + * @param endIndex the end index inside the string in java chars, exclusive. + * @param downCase if this is true, code points will be downcased before being copied. + * @return the number of copied code points. + */ + public static int copyCodePointsAndReturnCodePointCount(final int[] destination, + final CharSequence charSequence, final int startIndex, final int endIndex, + final boolean downCase) { int destIndex = 0; - for (int index = 0; index < length; index = string.offsetByCodePoints(index, 1)) { - codePoints[destIndex] = string.codePointAt(index); + for (int index = startIndex; index < endIndex; + index = Character.offsetByCodePoints(charSequence, index, 1)) { + final int codePoint = Character.codePointAt(charSequence, index); + // TODO: stop using this, as it's not aware of the locale and does not always do + // the right thing. + destination[destIndex] = downCase ? Character.toLowerCase(codePoint) : codePoint; destIndex++; } + return destIndex; + } + + public static int[] toSortedCodePointArray(final String string) { + final int[] codePoints = toCodePointArray(string); + Arrays.sort(codePoints); return codePoints; } + /** + * Construct a String from a code point array + * + * @param codePoints a code point array that is null terminated when its logical length is + * shorter than the array length. + * @return a string constructed from the code point array. + */ + public static String getStringFromNullTerminatedCodePointArray(final int[] codePoints) { + int stringLength = codePoints.length; + for (int i = 0; i < codePoints.length; i++) { + if (codePoints[i] == 0) { + stringLength = i; + break; + } + } + return new String(codePoints, 0 /* offset */, stringLength); + } + // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. public static int getCapitalizationType(final String text) { // If the first char is not uppercase, then the word is either all lower case or @@ -239,65 +316,58 @@ public final class StringUtils { return true; } - @UsedForTesting - public static boolean looksValidForDictionaryInsertion(final CharSequence text, - final SettingsValues settings) { - if (TextUtils.isEmpty(text)) return false; + /** + * Returns true if all code points in text are whitespace, false otherwise. Empty is true. + */ + // Interestingly enough, U+00A0 NO-BREAK SPACE and U+200B ZERO-WIDTH SPACE are not considered + // whitespace, while EN SPACE, EM SPACE and IDEOGRAPHIC SPACES are. + public static boolean containsOnlyWhitespace(final String text) { final int length = text.length(); int i = 0; - int digitCount = 0; while (i < length) { - final int codePoint = Character.codePointAt(text, i); - final int charCount = Character.charCount(codePoint); - i += charCount; - if (Character.isDigit(codePoint)) { - // Count digits: see below - digitCount += charCount; - continue; + final int codePoint = text.codePointAt(i); + if (!Character.isWhitespace(codePoint)) { + return false; } - if (!settings.isWordCodePoint(codePoint)) return false; + i += Character.charCount(codePoint); } - // We reject strings entirely comprised of digits to avoid using PIN codes or credit - // card numbers. It would come in handy for word prediction though; a good example is - // when writing one's address where the street number is usually quite discriminative, - // as well as the postal code. - return digitCount < length; + return true; } public static boolean isIdenticalAfterCapitalizeEachWord(final String text, - final String separators) { - boolean needCapsNext = true; + final int[] sortedSeparators) { + boolean needsCapsNext = true; final int len = text.length(); for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) { final int codePoint = text.codePointAt(i); if (Character.isLetter(codePoint)) { - if ((needCapsNext && !Character.isUpperCase(codePoint)) - || (!needCapsNext && !Character.isLowerCase(codePoint))) { + if ((needsCapsNext && !Character.isUpperCase(codePoint)) + || (!needsCapsNext && !Character.isLowerCase(codePoint))) { return false; } } // We need a capital letter next if this is a separator. - needCapsNext = (-1 != separators.indexOf(codePoint)); + needsCapsNext = (Arrays.binarySearch(sortedSeparators, codePoint) >= 0); } return true; } // TODO: like capitalizeFirst*, this does not work perfectly for Dutch because of the IJ digraph // which should be capitalized together in *some* cases. - public static String capitalizeEachWord(final String text, final String separators, + public static String capitalizeEachWord(final String text, final int[] sortedSeparators, final Locale locale) { final StringBuilder builder = new StringBuilder(); - boolean needCapsNext = true; + boolean needsCapsNext = true; final int len = text.length(); for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) { final String nextChar = text.substring(i, text.offsetByCodePoints(i, 1)); - if (needCapsNext) { + if (needsCapsNext) { builder.append(nextChar.toUpperCase(locale)); } else { builder.append(nextChar.toLowerCase(locale)); } // We need a capital letter next if this is a separator. - needCapsNext = (-1 != separators.indexOf(nextChar.codePointAt(0))); + needsCapsNext = (Arrays.binarySearch(sortedSeparators, nextChar.codePointAt(0)) >= 0); } return builder.toString(); } @@ -328,7 +398,7 @@ public final class StringUtils { boolean hasPeriod = false; int codePoint = 0; while (i > 0) { - codePoint = Character.codePointBefore(text, i); + codePoint = Character.codePointBefore(text, i); if (codePoint < Constants.CODE_PERIOD || codePoint > 'z') { // Handwavy heuristic to see if that's a URL character. Anything between period // and z. This includes all lower- and upper-case ascii letters, period, @@ -367,7 +437,49 @@ public final class StringUtils { return false; } - public static boolean isEmptyStringOrWhiteSpaces(String s) { + /** + * Examines the string and returns whether we're inside a double quote. + * + * This is used to decide whether we should put an automatic space before or after a double + * quote character. If we're inside a quotation, then we want to close it, so we want a space + * after and not before. Otherwise, we want to open the quotation, so we want a space before + * and not after. Exception: after a digit, we never want a space because the "inch" or + * "minutes" use cases is dominant after digits. + * In the practice, we determine whether we are in a quotation or not by finding the previous + * double quote character, and looking at whether it's followed by whitespace. If so, that + * was a closing quotation mark, so we're not inside a double quote. If it's not followed + * by whitespace, then it was an opening quotation mark, and we're inside a quotation. + * + * @param text the text to examine. + * @return whether we're inside a double quote. + */ + public static boolean isInsideDoubleQuoteOrAfterDigit(final CharSequence text) { + int i = text.length(); + if (0 == i) return false; + int codePoint = Character.codePointBefore(text, i); + if (Character.isDigit(codePoint)) return true; + int prevCodePoint = 0; + while (i > 0) { + codePoint = Character.codePointBefore(text, i); + if (Constants.CODE_DOUBLE_QUOTE == codePoint) { + // If we see a double quote followed by whitespace, then that + // was a closing quote. + if (Character.isWhitespace(prevCodePoint)) return false; + } + if (Character.isWhitespace(codePoint) && Constants.CODE_DOUBLE_QUOTE == prevCodePoint) { + // If we see a double quote preceded by whitespace, then that + // was an opening quote. No need to continue seeking. + return true; + } + i -= Character.charCount(codePoint); + prevCodePoint = codePoint; + } + // We reached the start of text. If the first char is a double quote, then we're inside + // a double quote. Otherwise we're not. + return Constants.CODE_DOUBLE_QUOTE == codePoint; + } + + public static boolean isEmptyStringOrWhiteSpaces(final String s) { final int N = codePointCount(s); for (int i = 0; i < N; ++i) { if (!Character.isWhitespace(s.codePointAt(i))) { @@ -378,9 +490,9 @@ public final class StringUtils { } @UsedForTesting - public static String byteArrayToHexString(byte[] bytes) { + public static String byteArrayToHexString(final byte[] bytes) { if (bytes == null || bytes.length == 0) { - return ""; + return EMPTY_STRING; } final StringBuilder sb = new StringBuilder(); for (byte b : bytes) { @@ -393,7 +505,7 @@ public final class StringUtils { * Convert hex string to byte array. The string length must be an even number. */ @UsedForTesting - public static byte[] hexStringToByteArray(String hexString) { + public static byte[] hexStringToByteArray(final String hexString) { if (TextUtils.isEmpty(hexString)) { return null; } @@ -410,66 +522,59 @@ public final class StringUtils { return bytes; } - public static List<Object> jsonStrToList(String s) { - final ArrayList<Object> retval = CollectionUtils.newArrayList(); - final JsonReader reader = new JsonReader(new StringReader(s)); - try { - reader.beginArray(); - while(reader.hasNext()) { - reader.beginObject(); - while (reader.hasNext()) { - final String name = reader.nextName(); - if (name.equals(Integer.class.getSimpleName())) { - retval.add(reader.nextInt()); - } else if (name.equals(String.class.getSimpleName())) { - retval.add(reader.nextString()); - } else { - Log.w(TAG, "Invalid name: " + name); - reader.skipValue(); - } - } - reader.endObject(); - } - reader.endArray(); - return retval; - } catch (IOException e) { - } finally { - try { - reader.close(); - } catch (IOException e) { + public static String toUpperCaseOfStringForLocale(final String text, + final boolean needsToUpperCase, final Locale locale) { + if (text == null || !needsToUpperCase) return text; + return text.toUpperCase(locale); + } + + public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase, + final Locale locale) { + if (!Constants.isLetterCode(code) || !needsToUpperCase) return code; + final String text = newSingleCodePointString(code); + final String casedText = toUpperCaseOfStringForLocale( + text, needsToUpperCase, locale); + return codePointCount(casedText) == 1 + ? casedText.codePointAt(0) : CODE_UNSPECIFIED; + } + + @UsedForTesting + public static class Stringizer<E> { + public String stringize(final E element) { + return element != null ? element.toString() : "null"; + } + + @UsedForTesting + public final String join(final E[] array) { + return joinStringArray(toStringArray(array), null /* delimiter */); + } + + @UsedForTesting + public final String join(final E[] array, final String delimiter) { + return joinStringArray(toStringArray(array), delimiter); + } + + protected String[] toStringArray(final E[] array) { + final String[] stringArray = new String[array.length]; + for (int index = 0; index < array.length; index++) { + stringArray[index] = stringize(array[index]); } + return stringArray; } - return Collections.<Object>emptyList(); - } - public static String listToJsonStr(List<Object> list) { - if (list == null || list.isEmpty()) { - return ""; - } - final StringWriter sw = new StringWriter(); - final JsonWriter writer = new JsonWriter(sw); - try { - writer.beginArray(); - for (final Object o : list) { - writer.beginObject(); - if (o instanceof Integer) { - writer.name(Integer.class.getSimpleName()).value((Integer)o); - } else if (o instanceof String) { - writer.name(String.class.getSimpleName()).value((String)o); - } - writer.endObject(); + protected String joinStringArray(final String[] stringArray, final String delimiter) { + if (stringArray == null) { + return "null"; } - writer.endArray(); - return sw.toString(); - } catch (IOException e) { - } finally { - try { - if (writer != null) { - writer.close(); - } - } catch (IOException e) { + if (delimiter == null) { + return Arrays.toString(stringArray); + } + final StringBuilder sb = new StringBuilder(); + for (int index = 0; index < stringArray.length; index++) { + sb.append(index == 0 ? "[" : delimiter); + sb.append(stringArray[index]); } + return sb + "]"; } - return ""; } } diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 102a41b4e..b37779bdc 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -25,17 +25,18 @@ import android.os.Build; import android.util.Log; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; +import java.util.Arrays; import java.util.HashMap; import java.util.Locale; public final class SubtypeLocaleUtils { - static final String TAG = SubtypeLocaleUtils.class.getSimpleName(); - // This class must be located in the same package as LatinIME.java. - private static final String RESOURCE_PACKAGE_NAME = - DictionaryFactory.class.getPackage().getName(); + private static final String TAG = SubtypeLocaleUtils.class.getSimpleName(); + + // This reference class {@link Constants} must be located in the same package as LatinIME.java. + private static final String RESOURCE_PACKAGE_NAME = Constants.class.getPackage().getName(); // Special language code to represent "no language". public static final String NO_LANGUAGE = "zz"; @@ -43,7 +44,8 @@ public final class SubtypeLocaleUtils { public static final String EMOJI = "emoji"; public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic; - private static boolean sInitialized = false; + private static volatile boolean sInitialized = false; + private static final Object sInitializeLock = new Object(); private static Resources sResources; private static String[] sPredefinedKeyboardLayoutSet; // Keyboard layout to its display name map. @@ -76,9 +78,16 @@ public final class SubtypeLocaleUtils { } // Note that this initialization method can be called multiple times. - public static synchronized void init(final Context context) { - if (sInitialized) return; + public static void init(final Context context) { + synchronized (sInitializeLock) { + if (sInitialized == false) { + initLocked(context); + sInitialized = true; + } + } + } + private static void initLocked(final Context context) { final Resources res = context.getResources(); sResources = res; @@ -121,8 +130,6 @@ public final class SubtypeLocaleUtils { final String keyboardLayoutSet = keyboardLayoutSetMap[i + 1]; sLocaleAndExtraValueToKeyboardLayoutSetMap.put(key, keyboardLayoutSet); } - - sInitialized = true; } public static String[] getPredefinedKeyboardLayoutSet() { @@ -166,8 +173,18 @@ public final class SubtypeLocaleUtils { return getSubtypeLocaleDisplayNameInternal(localeString, displayLocale); } + public static String getSubtypeLanguageDisplayName(final String localeString) { + final Locale locale = LocaleUtils.constructLocaleFromString(localeString); + final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString); + return getSubtypeLocaleDisplayNameInternal(locale.getLanguage(), displayLocale); + } + private static String getSubtypeLocaleDisplayNameInternal(final String localeString, final Locale displayLocale) { + if (NO_LANGUAGE.equals(localeString)) { + // No language subtype should be displayed in system locale. + return sResources.getString(R.string.subtype_no_language); + } final Integer exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString); final String displayName; if (exceptionalNameResId != null) { @@ -178,9 +195,6 @@ public final class SubtypeLocaleUtils { } }; displayName = getExceptionalName.runInLocale(sResources, displayLocale); - } else if (NO_LANGUAGE.equals(localeString)) { - // No language subtype should be displayed in system locale. - return sResources.getString(R.string.subtype_no_language); } else { final Locale locale = LocaleUtils.constructLocaleFromString(localeString); displayName = locale.getDisplayName(displayLocale); @@ -197,12 +211,14 @@ public final class SubtypeLocaleUtils { // es_US spanish F Español (EE.UU.) exception // fr azerty F Français // fr_CA qwerty F Français (Canada) + // fr_CH swiss F Français (Suisse) // de qwertz F Deutsch - // zz qwerty F No language (QWERTY) in system locale + // de_CH swiss T Deutsch (Schweiz) + // zz qwerty F Alphabet (QWERTY) in system locale // fr qwertz T Français (QWERTZ) // de qwerty T Deutsch (QWERTY) // en_US azerty T English (US) (AZERTY) exception - // zz azerty T No language (AZERTY) in system locale + // zz azerty T Alphabet (AZERTY) in system locale private static String getReplacementString(final InputMethodSubtype subtype, final Locale displayLocale) { @@ -289,45 +305,23 @@ public final class SubtypeLocaleUtils { return keyboardLayoutSet; } - // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Short Middle Full - // ------ ------- - ---- --------- ---------------------- - // en_US qwerty F En English English (US) exception - // en_GB qwerty F En English English (UK) exception - // es_US spanish F Es Español Español (EE.UU.) exception - // fr azerty F Fr Français Français - // fr_CA qwerty F Fr Français Français (Canada) - // de qwertz F De Deutsch Deutsch - // zz qwerty F QWERTY QWERTY - // fr qwertz T Fr Français Français - // de qwerty T De Deutsch Deutsch - // en_US azerty T En English English (US) - // zz azerty T AZERTY AZERTY - - // Get InputMethodSubtype's full display name in its locale. - public static String getFullDisplayName(final InputMethodSubtype subtype) { - if (isNoLanguage(subtype)) { - return getKeyboardLayoutSetDisplayName(subtype); - } - return getSubtypeLocaleDisplayName(subtype.getLocale()); + // TODO: Get this information from the framework instead of maintaining here by ourselves. + // Sorted list of known Right-To-Left language codes. + private static final String[] SORTED_RTL_LANGUAGES = { + "ar", // Arabic + "fa", // Persian + "iw", // Hebrew + }; + static { + Arrays.sort(SORTED_RTL_LANGUAGES); } - // Get InputMethodSubtype's middle display name in its locale. - public static String getMiddleDisplayName(final InputMethodSubtype subtype) { - if (isNoLanguage(subtype)) { - return getKeyboardLayoutSetDisplayName(subtype); - } - final Locale locale = getSubtypeLocale(subtype); - return getSubtypeLocaleDisplayName(locale.getLanguage()); + public static boolean isRtlLanguage(final Locale locale) { + final String language = locale.getLanguage(); + return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0; } - // Get InputMethodSubtype's short display name in its locale. - public static String getShortDisplayName(final InputMethodSubtype subtype) { - if (isNoLanguage(subtype)) { - return ""; - } - final Locale locale = getSubtypeLocale(subtype); - return StringUtils.capitalizeFirstCodePoint(locale.getLanguage(), locale); + public static boolean isRtlLanguage(final InputMethodSubtype subtype) { + return isRtlLanguage(getSubtypeLocale(subtype)); } } diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java new file mode 100644 index 000000000..0b362c48a --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 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.utils; + +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Locale; +import java.util.TreeSet; + +/** + * A TreeSet of SuggestedWordInfo that is bounded in size and throws everything that's smaller + * than its limit + */ +public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { + public final Locale mLocale; + private final int mCapacity; + + public SuggestionResults(final Locale locale, final int capacity) { + this(locale, sSuggestedWordInfoComparator, capacity); + } + + public SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator, + final int capacity) { + super(comparator); + mLocale = locale; + mCapacity = capacity; + } + + @Override + public boolean add(final SuggestedWordInfo e) { + if (size() < mCapacity) return super.add(e); + if (comparator().compare(e, last()) > 0) return false; + super.add(e); + pollLast(); // removes the last element + return true; + } + + @Override + public boolean addAll(final Collection<? extends SuggestedWordInfo> e) { + if (null == e) return false; + return super.addAll(e); + } + + private static final class SuggestedWordInfoComparator + implements Comparator<SuggestedWordInfo> { + // This comparator ranks the word info with the higher frequency first. That's because + // that's the order we want our elements in. + @Override + public int compare(final SuggestedWordInfo o1, final SuggestedWordInfo o2) { + if (o1.mScore > o2.mScore) return -1; + if (o1.mScore < o2.mScore) return 1; + if (o1.mCodePointCount < o2.mCodePointCount) return -1; + if (o1.mCodePointCount > o2.mCodePointCount) return 1; + return o1.mWord.compareTo(o2.mWord); + } + } + + private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator = + new SuggestedWordInfoComparator(); +} diff --git a/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java b/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java index afbe2ecad..42ea3c959 100644 --- a/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java +++ b/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java @@ -22,6 +22,8 @@ import android.content.pm.PackageManager; import android.os.AsyncTask; import android.util.LruCache; +import com.android.inputmethod.compat.AppWorkaroundsUtils; + public final class TargetPackageInfoGetterTask extends AsyncTask<String, Void, PackageInfo> { private static final int MAX_CACHE_ENTRIES = 64; // arbitrary @@ -37,17 +39,13 @@ public final class TargetPackageInfoGetterTask extends sCache.remove(packageName); } - public interface OnTargetPackageInfoKnownListener { - public void onTargetPackageInfoKnown(final PackageInfo info); - } - private Context mContext; - private final OnTargetPackageInfoKnownListener mListener; + private final AsyncResultHolder<AppWorkaroundsUtils> mResult; public TargetPackageInfoGetterTask(final Context context, - final OnTargetPackageInfoKnownListener listener) { + final AsyncResultHolder<AppWorkaroundsUtils> result) { mContext = context; - mListener = listener; + mResult = result; } @Override @@ -65,6 +63,6 @@ public final class TargetPackageInfoGetterTask extends @Override protected void onPostExecute(final PackageInfo info) { - mListener.onTargetPackageInfoKnown(info); + mResult.set(new AppWorkaroundsUtils(info)); } } diff --git a/java/src/com/android/inputmethod/latin/utils/TextRange.java b/java/src/com/android/inputmethod/latin/utils/TextRange.java index 48b443ddd..dbf3b5060 100644 --- a/java/src/com/android/inputmethod/latin/utils/TextRange.java +++ b/java/src/com/android/inputmethod/latin/utils/TextRange.java @@ -31,6 +31,7 @@ public final class TextRange { private final int mCursorIndex; public final CharSequence mWord; + public final boolean mHasUrlSpans; public int getNumberOfCharsInWordBeforeCursor() { return mCursorIndex - mWordAtCursorStartIndex; @@ -95,7 +96,7 @@ public final class TextRange { } } if (spanStart == mWordAtCursorStartIndex && spanEnd == mWordAtCursorEndIndex) { - // If the span does not start and stop here, we ignore it. It probably extends + // If the span does not start and stop here, ignore it. It probably extends // past the start or end of the word, as happens in missing space correction // or EasyEditSpans put by voice input. spans[writeIndex++] = spans[readIndex]; @@ -105,7 +106,7 @@ public final class TextRange { } public TextRange(final CharSequence textAtCursor, final int wordAtCursorStartIndex, - final int wordAtCursorEndIndex, final int cursorIndex) { + final int wordAtCursorEndIndex, final int cursorIndex, final boolean hasUrlSpans) { if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex || cursorIndex > wordAtCursorEndIndex || wordAtCursorEndIndex > textAtCursor.length()) { @@ -115,6 +116,7 @@ public final class TextRange { mWordAtCursorStartIndex = wordAtCursorStartIndex; mWordAtCursorEndIndex = wordAtCursorEndIndex; mCursorIndex = cursorIndex; + mHasUrlSpans = hasUrlSpans; mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex); } }
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java index 47ea1ea75..087a7f255 100644 --- a/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java @@ -22,6 +22,9 @@ import android.graphics.Typeface; import android.util.SparseArray; public final class TypefaceUtils { + private static final char[] KEY_LABEL_REFERENCE_CHAR = { 'M' }; + private static final char[] KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR = { '8' }; + private TypefaceUtils() { // This utility class is not publicly instantiable. } @@ -31,7 +34,7 @@ public final class TypefaceUtils { // Working variable for the following method. private static final Rect sTextHeightBounds = new Rect(); - public static float getCharHeight(final char[] referenceChar, final Paint paint) { + private static float getCharHeight(final char[] referenceChar, final Paint paint) { final int key = getCharGeometryCacheKey(referenceChar[0], paint); synchronized (sTextHeightCache) { final Float cachedValue = sTextHeightCache.get(key); @@ -51,7 +54,7 @@ public final class TypefaceUtils { // Working variable for the following method. private static final Rect sTextWidthBounds = new Rect(); - public static float getCharWidth(final char[] referenceChar, final Paint paint) { + private static float getCharWidth(final char[] referenceChar, final Paint paint) { final int key = getCharGeometryCacheKey(referenceChar[0], paint); synchronized (sTextWidthCache) { final Float cachedValue = sTextWidthCache.get(key); @@ -66,11 +69,6 @@ public final class TypefaceUtils { } } - public static float getStringWidth(final String string, final Paint paint) { - paint.getTextBounds(string, 0, string.length(), sTextWidthBounds); - return sTextWidthBounds.width(); - } - private static int getCharGeometryCacheKey(final char referenceChar, final Paint paint) { final int labelSize = (int)paint.getTextSize(); final Typeface face = paint.getTypeface(); @@ -86,9 +84,25 @@ public final class TypefaceUtils { } } - public static float getLabelWidth(final String label, final Paint paint) { - final Rect textBounds = new Rect(); - paint.getTextBounds(label, 0, label.length(), textBounds); - return textBounds.width(); + public static float getReferenceCharHeight(final Paint paint) { + return getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint); + } + + public static float getReferenceCharWidth(final Paint paint) { + return getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint); + } + + public static float getReferenceDigitWidth(final Paint paint) { + return getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint); + } + + // Working variable for the following method. + private static final Rect sStringWidthBounds = new Rect(); + + public static float getStringWidth(final String string, final Paint paint) { + synchronized (sStringWidthBounds) { + paint.getTextBounds(string, 0, string.length(), sStringWidthBounds); + return sStringWidthBounds.width(); + } } } diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java deleted file mode 100644 index 635afe7cc..000000000 --- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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.utils; - -import android.util.Log; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; -import com.android.inputmethod.latin.makedict.DictDecoder; -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.PendingAttribute; -import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.concurrent.TimeUnit; - -/** - * Reads and writes Binary files for a UserHistoryDictionary. - * - * All the methods in this class are static. - */ -public final class UserHistoryDictIOUtils { - private static final String TAG = UserHistoryDictIOUtils.class.getSimpleName(); - private static final boolean DEBUG = false; - private static final String USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE"; - private static final String USES_FORGETTING_CURVE_VALUE = "1"; - private static final String LAST_UPDATED_TIME_KEY = "date"; - - public interface OnAddWordListener { - /** - * Callback to be notified when a word is added to the dictionary. - * @param word The added word. - * @param shortcutTarget A shortcut target for this word, or null if none. - * @param frequency The frequency for this word. - * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). - * Unspecified if shortcutTarget is null - do not rely on its value. - */ - public void setUnigram(final String word, final String shortcutTarget, final int frequency, - final int shortcutFreq); - public void setBigram(final String word1, final String word2, final int frequency); - } - - @UsedForTesting - public interface BigramDictionaryInterface { - public int getFrequency(final String word1, final String word2); - } - - /** - * Writes dictionary to file. - */ - public static void writeDictionary(final DictEncoder dictEncoder, - final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams, - final FormatOptions formatOptions) { - final FusionDictionary fusionDict = constructFusionDictionary(dict, bigrams); - fusionDict.addOptionAttribute(USES_FORGETTING_CURVE_KEY, USES_FORGETTING_CURVE_VALUE); - fusionDict.addOptionAttribute(LAST_UPDATED_TIME_KEY, - String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); - try { - dictEncoder.writeDictionary(fusionDict, formatOptions); - Log.d(TAG, "end writing"); - } catch (IOException e) { - Log.e(TAG, "IO exception while writing file", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Unsupported format", e); - } - } - - /** - * Constructs a new FusionDictionary from BigramDictionaryInterface. - */ - @UsedForTesting - static FusionDictionary constructFusionDictionary( - final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams) { - final FusionDictionary fusionDict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false, - false)); - int profTotal = 0; - for (final String word1 : bigrams.keySet()) { - final HashMap<String, Byte> word1Bigrams = bigrams.getBigrams(word1); - for (final String word2 : word1Bigrams.keySet()) { - final int freq = dict.getFrequency(word1, word2); - if (freq == -1) { - // don't add this bigram. - continue; - } - if (DEBUG) { - if (word1 == null) { - Log.d(TAG, "add unigram: " + word2 + "," + Integer.toString(freq)); - } else { - Log.d(TAG, "add bigram: " + word1 - + "," + word2 + "," + Integer.toString(freq)); - } - profTotal++; - } - if (word1 == null) { // unigram - fusionDict.add(word2, freq, null, false /* isNotAWord */); - } else { // bigram - if (FusionDictionary.findWordInTree(fusionDict.mRootNodeArray, word1) == null) { - fusionDict.add(word1, 2, null, false /* isNotAWord */); - } - fusionDict.setBigram(word1, word2, freq); - } - bigrams.updateBigram(word1, word2, (byte)freq); - } - } - if (DEBUG) { - Log.d(TAG, "add " + profTotal + "words"); - } - return fusionDict; - } - - /** - * Reads dictionary from file. - */ - public static void readDictionaryBinary(final DictDecoder dictDecoder, - final OnAddWordListener dict) { - final TreeMap<Integer, String> unigrams = CollectionUtils.newTreeMap(); - final TreeMap<Integer, Integer> frequencies = CollectionUtils.newTreeMap(); - final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap(); - try { - dictDecoder.readUnigramsAndBigramsBinary(unigrams, frequencies, bigrams); - } catch (IOException e) { - Log.e(TAG, "IO exception while reading file", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Unsupported format", e); - } catch (ArrayIndexOutOfBoundsException e) { - Log.e(TAG, "ArrayIndexOutOfBoundsException while reading file", e); - } - addWordsFromWordMap(unigrams, frequencies, bigrams, dict); - } - - /** - * Adds all unigrams and bigrams in maps to OnAddWordListener. - */ - @UsedForTesting - static void addWordsFromWordMap(final TreeMap<Integer, String> unigrams, - final TreeMap<Integer, Integer> frequencies, - final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams, - final OnAddWordListener to) { - for (Entry<Integer, String> entry : unigrams.entrySet()) { - final String word1 = entry.getValue(); - final int unigramFrequency = frequencies.get(entry.getKey()); - to.setUnigram(word1, null /* shortcutTarget */, unigramFrequency, 0 /* shortcutFreq */); - final ArrayList<PendingAttribute> attrList = bigrams.get(entry.getKey()); - if (attrList != null) { - for (final PendingAttribute attr : attrList) { - final String word2 = unigrams.get(attr.mAddress); - if (word1 == null || word2 == null) { - Log.e(TAG, "Invalid bigram pair detected: " + word1 + ", " + word2); - continue; - } - to.setBigram(word1, word2, - BinaryDictIOUtils.reconstructBigramFrequency(unigramFrequency, - attr.mFrequency)); - } - } - } - - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java deleted file mode 100644 index 1992b2f5d..000000000 --- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.utils; - -import android.util.Log; - -import java.util.concurrent.TimeUnit; - -public final class UserHistoryForgettingCurveUtils { - private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName(); - private static final boolean DEBUG = false; - private static final int DEFAULT_FC_FREQ = 127; - private static final int BOOSTED_FC_FREQ = 200; - private static int FC_FREQ_MAX = DEFAULT_FC_FREQ; - /* package */ static final int COUNT_MAX = 3; - private static final int FC_LEVEL_MAX = 3; - /* package */ static final int ELAPSED_TIME_MAX = 15; - private static final int ELAPSED_TIME_INTERVAL_HOURS = 6; - private static final long ELAPSED_TIME_INTERVAL_MILLIS = - TimeUnit.HOURS.toMillis(ELAPSED_TIME_INTERVAL_HOURS); - private static final int HALF_LIFE_HOURS = 48; - private static final int MAX_PUSH_ELAPSED = (FC_LEVEL_MAX + 1) * (ELAPSED_TIME_MAX + 1); - - public static void boostMaxFreqForDebug() { - FC_FREQ_MAX = BOOSTED_FC_FREQ; - } - - public static void resetMaxFreqForDebug() { - FC_FREQ_MAX = DEFAULT_FC_FREQ; - } - - private UserHistoryForgettingCurveUtils() { - // This utility class is not publicly instantiable. - } - - public static final class ForgettingCurveParams { - private byte mFc; - long mLastTouchedTime = 0; - private final boolean mIsValid; - - private void updateLastTouchedTime() { - mLastTouchedTime = System.currentTimeMillis(); - } - - public ForgettingCurveParams(boolean isValid) { - this(System.currentTimeMillis(), isValid); - } - - private ForgettingCurveParams(long now, boolean isValid) { - this(pushCount((byte)0, isValid), now, now, isValid); - } - - /** This constructor is called when the user history bigram dictionary is being restored. */ - public ForgettingCurveParams(int fc, long now, long last) { - // All words with level >= 1 had been saved. - // Invalid words with level == 0 had been saved. - // Valid words words with level == 0 had *not* been saved. - this(fc, now, last, fcToLevel((byte)fc) > 0); - } - - private ForgettingCurveParams(int fc, long now, long last, boolean isValid) { - mIsValid = isValid; - mFc = (byte)fc; - mLastTouchedTime = last; - updateElapsedTime(now); - } - - public boolean isValid() { - return mIsValid; - } - - public byte getFc() { - updateElapsedTime(System.currentTimeMillis()); - return mFc; - } - - public int getFrequency() { - updateElapsedTime(System.currentTimeMillis()); - return UserHistoryForgettingCurveUtils.fcToFreq(mFc); - } - - public int notifyTypedAgainAndGetFrequency() { - updateLastTouchedTime(); - // TODO: Check whether this word is valid or not - mFc = pushCount(mFc, false); - return UserHistoryForgettingCurveUtils.fcToFreq(mFc); - } - - private void updateElapsedTime(long now) { - final int elapsedTimeCount = - (int)((now - mLastTouchedTime) / ELAPSED_TIME_INTERVAL_MILLIS); - if (elapsedTimeCount <= 0) { - return; - } - if (elapsedTimeCount >= MAX_PUSH_ELAPSED) { - mLastTouchedTime = now; - mFc = 0; - return; - } - for (int i = 0; i < elapsedTimeCount; ++i) { - mLastTouchedTime += ELAPSED_TIME_INTERVAL_MILLIS; - mFc = pushElapsedTime(mFc); - } - } - } - - /* package */ static int fcToElapsedTime(byte fc) { - return fc & 0x0F; - } - - /* package */ static int fcToCount(byte fc) { - return (fc >> 4) & 0x03; - } - - /* package */ static int fcToLevel(byte fc) { - return (fc >> 6) & 0x03; - } - - private static int calcFreq(int elapsedTime, int count, int level) { - if (level <= 0) { - // Reserved words, just return -1 - return -1; - } - if (count == COUNT_MAX) { - // Temporary promote because it's frequently typed recently - ++level; - } - final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); - final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); - return MathUtils.SCORE_TABLE[l - 1][et]; - } - - /* pakcage */ static byte calcFc(int elapsedTime, int count, int level) { - final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); - final int c = Math.min(COUNT_MAX, Math.max(0, count)); - final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); - return (byte)(et | (c << 4) | (l << 6)); - } - - public static int fcToFreq(byte fc) { - final int elapsedTime = fcToElapsedTime(fc); - final int count = fcToCount(fc); - final int level = fcToLevel(fc); - return calcFreq(elapsedTime, count, level); - } - - public static byte pushElapsedTime(byte fc) { - int elapsedTime = fcToElapsedTime(fc); - int count = fcToCount(fc); - int level = fcToLevel(fc); - if (elapsedTime >= ELAPSED_TIME_MAX) { - // Downgrade level - elapsedTime = 0; - count = COUNT_MAX; - --level; - } else { - ++elapsedTime; - } - return calcFc(elapsedTime, count, level); - } - - public static byte pushCount(byte fc, boolean isValid) { - final int elapsedTime = fcToElapsedTime(fc); - int count = fcToCount(fc); - int level = fcToLevel(fc); - if ((elapsedTime == 0 && count >= COUNT_MAX) || (isValid && level == 0)) { - // Upgrade level - ++level; - count = 0; - if (DEBUG) { - Log.d(TAG, "Upgrade level."); - } - } else { - ++count; - } - return calcFc(0, count, level); - } - - // TODO: isValid should be false for a word whose frequency is 0, - // or that is not in the dictionary. - /** - * Check wheather we should save the bigram to the SQL DB or not - */ - public static boolean needsToSave(byte fc, boolean isValid, boolean addLevel0Bigram) { - int level = fcToLevel(fc); - if (level == 0) { - if (isValid || !addLevel0Bigram) { - return false; - } - } - final int elapsedTime = fcToElapsedTime(fc); - return (elapsedTime < ELAPSED_TIME_MAX - 1 || level > 0); - } - - private static final class MathUtils { - public static final int[][] SCORE_TABLE = new int[FC_LEVEL_MAX][ELAPSED_TIME_MAX + 1]; - static { - for (int i = 0; i < FC_LEVEL_MAX; ++i) { - final float initialFreq; - if (i >= 2) { - initialFreq = FC_FREQ_MAX; - } else if (i == 1) { - initialFreq = FC_FREQ_MAX / 2; - } else if (i == 0) { - initialFreq = FC_FREQ_MAX / 4; - } else { - continue; - } - for (int j = 0; j < ELAPSED_TIME_MAX; ++j) { - final float elapsedHours = j * ELAPSED_TIME_INTERVAL_HOURS; - final float freq = initialFreq - * (float)Math.pow(initialFreq, elapsedHours / HALF_LIFE_HOURS); - final int intFreq = Math.min(FC_FREQ_MAX, Math.max(0, (int)freq)); - SCORE_TABLE[i][j] = intFreq; - } - } - } - } -} diff --git a/java/src/com/android/inputmethod/research/JsonUtils.java b/java/src/com/android/inputmethod/research/JsonUtils.java index 2beebdfae..6170b4339 100644 --- a/java/src/com/android/inputmethod/research/JsonUtils.java +++ b/java/src/com/android/inputmethod/research/JsonUtils.java @@ -91,7 +91,7 @@ import java.util.Map; jsonWriter.name("willAutoCorrect") .value(words.mWillAutoCorrect); jsonWriter.name("isPunctuationSuggestions") - .value(words.mIsPunctuationSuggestions); + .value(words.isPunctuationSuggestions()); jsonWriter.name("isObsoleteSuggestions").value(words.mIsObsoleteSuggestions); jsonWriter.name("isPrediction").value(words.mIsPrediction); jsonWriter.name("suggestedWords"); diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java index 6df7c1708..ffdb43c15 100644 --- a/java/src/com/android/inputmethod/research/MainLogBuffer.java +++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java @@ -20,7 +20,7 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest; import com.android.inputmethod.latin.define.ProductionFlag; import java.io.IOException; @@ -75,9 +75,7 @@ public abstract class MainLogBuffer extends FixedLogBuffer { // The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams. public static final int N_GRAM_SIZE = 2; - // TODO: Remove dependence on Suggest, and pass in Dictionary as a parameter to an appropriate - // method. - private final Suggest mSuggest; + private final DictionaryFacilitatorForSuggest mDictionaryFacilitator; @UsedForTesting private Dictionary mDictionaryForTesting; private boolean mIsStopping = false; @@ -89,11 +87,11 @@ public abstract class MainLogBuffer extends FixedLogBuffer { /* package for test */ int mNumWordsUntilSafeToSample; public MainLogBuffer(final int wordsBetweenSamples, final int numInitialWordsToIgnore, - final Suggest suggest) { + final DictionaryFacilitatorForSuggest dictionaryFacilitator) { super(N_GRAM_SIZE + wordsBetweenSamples); mNumWordsBetweenNGrams = wordsBetweenSamples; mNumWordsUntilSafeToSample = DEBUG ? 0 : numInitialWordsToIgnore; - mSuggest = suggest; + mDictionaryFacilitator = dictionaryFacilitator; } @UsedForTesting @@ -101,12 +99,14 @@ public abstract class MainLogBuffer extends FixedLogBuffer { mDictionaryForTesting = dictionary; } - private Dictionary getDictionary() { + private boolean isValidDictWord(final String word) { if (mDictionaryForTesting != null) { - return mDictionaryForTesting; + return mDictionaryForTesting.isValidWord(word); } - if (mSuggest == null || !mSuggest.hasMainDictionary()) return null; - return mSuggest.getMainDictionary(); + if (mDictionaryFacilitator != null) { + return mDictionaryFacilitator.isValidMainDictWord(word); + } + return false; } public void setIsStopping() { @@ -155,8 +155,9 @@ public abstract class MainLogBuffer extends FixedLogBuffer { } // Reload the dictionary in case it has changed (e.g., because the user has changed // languages). - final Dictionary dictionary = getDictionary(); - if (dictionary == null) { + if ((mDictionaryFacilitator == null + || !mDictionaryFacilitator.hasInitializedMainDictionary()) + && mDictionaryForTesting == null) { // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a // word is out-of-vocabulary or not. Therefore, we must judge the entire buffer // contents to potentially pose a privacy risk. @@ -166,7 +167,6 @@ public abstract class MainLogBuffer extends FixedLogBuffer { // Check each word in the buffer. If any word poses a privacy threat, we cannot upload // the complete buffer contents in detail. int numWordsInLogUnitList = 0; - final int length = logUnits.size(); for (final LogUnit logUnit : logUnits) { if (!logUnit.hasOneOrMoreWords()) { // Digits outside words are a privacy threat. @@ -178,11 +178,11 @@ public abstract class MainLogBuffer extends FixedLogBuffer { final String[] words = logUnit.getWordsAsStringArray(); for (final String word : words) { // Words not in the dictionary are a privacy threat. - if (ResearchLogger.hasLetters(word) && !(dictionary.isValidWord(word))) { + if (ResearchLogger.hasLetters(word) && !isValidDictWord(word)) { if (DEBUG) { Log.d(TAG, "\"" + word + "\" NOT SAFE!: hasLetters: " + ResearchLogger.hasLetters(word) - + ", isValid: " + (dictionary.isValidWord(word))); + + ", isValid: " + isValidDictWord(word)); } return PUBLISHABILITY_UNPUBLISHABLE_NOT_IN_DICTIONARY; } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index da9c61103..d907dd1b0 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -52,14 +52,14 @@ import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputConnection; -import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.utils.InputTypeUtils; +import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import com.android.inputmethod.research.MotionEventReader.ReplayData; import com.android.inputmethod.research.ui.SplashScreen; @@ -102,10 +102,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; private static final boolean DEBUG_REPLAY_AFTER_FEEDBACK = false && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; - // Whether the TextView contents are logged at the end of the session. true will disclose - // private info. - private static final boolean LOG_FULL_TEXTVIEW_CONTENTS = false - && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; // Whether the feedback dialog preserves the editable text across invocations. Should be false // for normal research builds so users do not have to delete the same feedback string they // entered earlier. Should be true for builds internal to a development team so when the text @@ -113,7 +109,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // feedback mechanism to generate multiple tests. private static final boolean FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD = false; /* package */ static boolean sIsLogging = false; - private static final int OUTPUT_FORMAT_VERSION = 5; + private static final int OUTPUT_FORMAT_VERSION = 6; // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for // testing. /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false @@ -136,7 +132,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static final String RESEARCH_KEY_OUTPUT_TEXT = ".research."; // constants related to specific log points - private static final String WHITESPACE_SEPARATORS = " \t\n\r"; + private static final int[] WHITESPACE_SEPARATORS = + StringUtils.toSortedCodePointArray(" \t\n\r"); private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1 private static final String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel"; @@ -168,12 +165,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // U+E001 is in the "private-use area" /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001"; protected static final int SUSPEND_DURATION_IN_MINUTES = 1; - // set when LatinIME should ignore an onUpdateSelection() callback that - // arises from operations in this class - private static boolean sLatinIMEExpectingUpdateSelection = false; // used to check whether words are not unique - private Suggest mSuggest; + private DictionaryFacilitatorForSuggest mDictionaryFacilitator; private MainKeyboardView mMainKeyboardView; // TODO: Check whether a superclass can be used instead of LatinIME. /* package for test */ LatinIME mLatinIME; @@ -212,8 +206,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return sInstance; } - public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher, - final Suggest suggest) { + public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher) { assert latinIME != null; mLatinIME = latinIME; mPrefs = PreferenceManager.getDefaultSharedPreferences(latinIME); @@ -249,7 +242,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang System.currentTimeMillis(), System.nanoTime()), mLatinIME); final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1); mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore, - mSuggest) { + mDictionaryFacilitator) { @Override protected void publish(final ArrayList<LogUnit> logUnits, boolean canIncludePrivateData) { @@ -262,10 +255,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang + ", cipd: " + canIncludePrivateData); } for (final String word : logUnit.getWordsAsStringArray()) { - final Dictionary dictionary = getDictionary(); + final boolean isDictionaryWord = mDictionaryFacilitator != null + && mDictionaryFacilitator.isValidMainDictWord(word); mStatistics.recordWordEntered( - dictionary != null && dictionary.isValidWord(word), - logUnit.containsUserDeletions()); + isDictionaryWord, logUnit.containsUserDeletions()); } } publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData); @@ -663,8 +656,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mInFeedbackDialog = false; } - public void initSuggest(final Suggest suggest) { - mSuggest = suggest; + public void initDictionary(final DictionaryFacilitatorForSuggest dictionaryFacilitator) { + mDictionaryFacilitator = dictionaryFacilitator; // MainLogBuffer now has an out-of-date Suggest object. Close down MainLogBuffer and create // a new one. if (mMainLogBuffer != null) { @@ -672,13 +665,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private Dictionary getDictionary() { - if (mSuggest == null) { - return null; - } - return mSuggest.getMainDictionary(); - } - private void setIsPasswordView(boolean isPasswordView) { mIsPasswordView = isPasswordView; } @@ -972,11 +958,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private String scrubWord(String word) { - final Dictionary dictionary = getDictionary(); - if (dictionary == null) { - return WORD_REPLACEMENT_STRING; - } - if (dictionary.isValidWord(word)) { + if (mDictionaryFacilitator != null && mDictionaryFacilitator.isValidMainDictWord(word)) { return word; } return WORD_REPLACEMENT_STRING; @@ -1126,12 +1108,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang new Object[] { applicationSpecifiedCompletions }); } - public static boolean getAndClearLatinIMEExpectingUpdateSelection() { - boolean returnValue = sLatinIMEExpectingUpdateSelection; - sLatinIMEExpectingUpdateSelection = false; - return returnValue; - } - /** * The IME is finishing; it is either being destroyed, or is about to be hidden. * @@ -1141,59 +1117,19 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL = new LogStatement("LatinIMEOnFinishInputViewInternal", false, false, "isTextTruncated", "text"); - public static void latinIME_onFinishInputViewInternal(final boolean finishingInput, - final int savedSelectionStart, final int savedSelectionEnd, final InputConnection ic) { + public static void latinIME_onFinishInputViewInternal(final boolean finishingInput) { // The finishingInput flag is set in InputMethodService. It is true if called from // doFinishInput(), which can be called as part of doStartInput(). This can happen at times // when the IME is not closing, such as when powering up. The finishinInput flag is false // if called from finishViews(), which is called from hideWindow() and onDestroy(). These // are the situations in which we want to finish up the researchLog. - if (ic != null && !finishingInput) { - final boolean isTextTruncated; - final String text; - if (LOG_FULL_TEXTVIEW_CONTENTS) { - // Capture the TextView contents. This will trigger onUpdateSelection(), so we - // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called, - // it can tell that it was generated by the logging code, and not by the user, and - // therefore keep user-visible state as is. - ic.beginBatchEdit(); - ic.performContextMenuAction(android.R.id.selectAll); - CharSequence charSequence = ic.getSelectedText(0); - if (savedSelectionStart != -1 && savedSelectionEnd != -1) { - ic.setSelection(savedSelectionStart, savedSelectionEnd); - } - ic.endBatchEdit(); - sLatinIMEExpectingUpdateSelection = true; - if (TextUtils.isEmpty(charSequence)) { - isTextTruncated = false; - text = ""; - } else { - if (charSequence.length() > MAX_INPUTVIEW_LENGTH_TO_CAPTURE) { - int length = MAX_INPUTVIEW_LENGTH_TO_CAPTURE; - // do not cut in the middle of a supplementary character - final char c = charSequence.charAt(length - 1); - if (Character.isHighSurrogate(c)) { - length--; - } - final CharSequence truncatedCharSequence = charSequence.subSequence(0, - length); - isTextTruncated = true; - text = truncatedCharSequence.toString(); - } else { - isTextTruncated = false; - text = charSequence.toString(); - } - } - } else { - isTextTruncated = true; - text = ""; - } + if (!finishingInput) { final ResearchLogger researchLogger = getInstance(); // Assume that OUTPUT_ENTIRE_BUFFER is only true when we don't care about privacy (e.g. // during a live user test), so the normal isPotentiallyPrivate and // isPotentiallyRevealing flags do not apply researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONFINISHINPUTVIEWINTERNAL, - isTextTruncated, text); + true /* isTextTruncated */, "" /* text */); researchLogger.commitCurrentLogUnit(); getInstance().stop(); } @@ -1213,9 +1149,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void latinIME_onUpdateSelection(final int lastSelectionStart, final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd, final int newSelStart, final int newSelEnd, final int composingSpanStart, - final int composingSpanEnd, final boolean expectingUpdateSelection, - final boolean expectingUpdateSelectionFromLogger, - final RichInputConnection connection) { + final int composingSpanEnd, final RichInputConnection connection) { String word = ""; if (connection != null) { TextRange range = connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1); @@ -1227,8 +1161,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final String scrubbedWord = researchLogger.scrubWord(word); researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONUPDATESELECTION, lastSelectionStart, lastSelectionEnd, oldSelStart, oldSelEnd, newSelStart, newSelEnd, - composingSpanStart, composingSpanEnd, expectingUpdateSelection, - expectingUpdateSelectionFromLogger, scrubbedWord); + composingSpanStart, composingSpanEnd, false /* expectingUpdateSelection */, + false /* expectingUpdateSelectionFromLogger */, scrubbedWord); } /** @@ -1411,8 +1345,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final LogStatement LOGSTATEMENT_MAINKEYBOARDVIEW_SETKEYBOARD = new LogStatement("MainKeyboardViewSetKeyboard", false, false, "elementId", "locale", "orientation", "width", "modeName", "action", "navigateNext", - "navigatePrevious", "clobberSettingsKey", "passwordInput", "shortcutKeyEnabled", - "hasShortcutKey", "languageSwitchKeyEnabled", "isMultiLine", "tw", "th", + "navigatePrevious", "clobberSettingsKey", "passwordInput", + "supportsSwitchingToShortcutIme", "hasShortcutKey", "languageSwitchKeyEnabled", + "isMultiLine", "tw", "th", "keys"); public static void mainKeyboardView_setKeyboard(final Keyboard keyboard, final int orientation) { @@ -1425,9 +1360,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang kid.mLocale + ":" + kid.mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), orientation, kid.mWidth, KeyboardId.modeName(kid.mMode), kid.imeAction(), kid.navigateNext(), kid.navigatePrevious(), kid.mClobberSettingsKey, - isPasswordView, kid.mShortcutKeyEnabled, kid.mHasShortcutKey, + isPasswordView, kid.mSupportsSwitchingToShortcutIme, kid.mHasShortcutKey, kid.mLanguageSwitchKeyEnabled, kid.isMultiLine(), keyboard.mOccupiedWidth, - keyboard.mOccupiedHeight, keyboard.getKeys()); + keyboard.mOccupiedHeight, keyboard.getSortedKeys()); } /** diff --git a/native/jni/Android.mk b/native/jni/Android.mk index ca6a77997..47b5c3344 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -28,77 +28,13 @@ LATIN_IME_SRC_DIR := src LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) LOCAL_CFLAGS += -Werror -Wall -Wextra -Weffc++ -Wformat=2 -Wcast-qual -Wcast-align \ - -Wwrite-strings -Wfloat-equal -Wpointer-arith -Winit-self -Wredundant-decls -Wno-system-headers - -ifeq ($(TARGET_ARCH), arm) -ifeq ($(TARGET_GCC_VERSION), 4.6) -LOCAL_CFLAGS += -Winline -endif # TARGET_GCC_VERSION -endif # TARGET_ARCH + -Wwrite-strings -Wfloat-equal -Wpointer-arith -Winit-self -Wredundant-decls \ + -Woverloaded-virtual -Wsign-promo -Wno-system-headers # 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 \ - com_android_inputmethod_latin_DicTraverseSession.cpp \ - com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \ - jni_common.cpp - -LATIN_IME_CORE_SRC_FILES := \ - suggest/core/suggest.cpp \ - $(addprefix suggest/core/dicnode/, \ - dic_node.cpp \ - dic_node_utils.cpp \ - dic_nodes_cache.cpp) \ - $(addprefix suggest/core/dictionary/, \ - bigram_dictionary.cpp \ - bloom_filter.cpp \ - dictionary.cpp \ - digraph_utils.cpp \ - multi_bigram_map.cpp) \ - $(addprefix suggest/core/layout/, \ - additional_proximity_chars.cpp \ - proximity_info.cpp \ - proximity_info_params.cpp \ - proximity_info_state.cpp \ - proximity_info_state_utils.cpp) \ - suggest/core/policy/weighting.cpp \ - suggest/core/session/dic_traverse_session.cpp \ - $(addprefix suggest/policyimpl/dictionary/, \ - bigram/bigram_list_read_write_utils.cpp \ - bigram/dynamic_bigram_list_policy.cpp \ - header/header_policy.cpp \ - header/header_read_write_utils.cpp \ - shortcut/shortcut_list_reading_utils.cpp \ - dictionary_structure_with_buffer_policy_factory.cpp \ - dynamic_patricia_trie_gc_event_listeners.cpp \ - dynamic_patricia_trie_node_reader.cpp \ - dynamic_patricia_trie_policy.cpp \ - dynamic_patricia_trie_reading_helper.cpp \ - dynamic_patricia_trie_reading_utils.cpp \ - dynamic_patricia_trie_writing_helper.cpp \ - dynamic_patricia_trie_writing_utils.cpp \ - patricia_trie_policy.cpp \ - patricia_trie_reading_utils.cpp) \ - $(addprefix suggest/policyimpl/dictionary/utils/, \ - buffer_with_extendable_buffer.cpp \ - byte_array_utils.cpp \ - dict_file_writing_utils.cpp \ - forgetting_curve_utils.cpp \ - format_utils.cpp) \ - suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ - $(addprefix suggest/policyimpl/typing/, \ - scoring_params.cpp \ - typing_scoring.cpp \ - typing_suggest_policy.cpp \ - typing_traversal.cpp \ - typing_weighting.cpp) \ - $(addprefix utils/, \ - autocorrection_threshold_utils.cpp \ - char_utils.cpp \ - log_utils.cpp) +include $(LOCAL_PATH)/NativeFileList.mk LOCAL_SRC_FILES := \ $(LATIN_IME_JNI_SRC_FILES) \ @@ -121,8 +57,9 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime_common_static LOCAL_MODULE_TAGS := optional +LOCAL_CLANG := true LOCAL_SDK_VERSION := 14 -LOCAL_NDK_STL_VARIANT := stlport_static +LOCAL_NDK_STL_VARIANT := c++_static include $(BUILD_STATIC_LIBRARY) ###################################### @@ -144,13 +81,14 @@ endif # FLAG_DO_PROFILE LOCAL_MODULE := libjni_latinime LOCAL_MODULE_TAGS := optional +LOCAL_CLANG := true LOCAL_SDK_VERSION := 14 -LOCAL_NDK_STL_VARIANT := stlport_static -LOCAL_LDFLAGS += -ldl +LOCAL_NDK_STL_VARIANT := c++_static +LOCAL_LDFLAGS += -ldl -fuse-ld=mcld include $(BUILD_SHARED_LIBRARY) - #################### Clean up the tmp vars -LATIN_IME_CORE_SRC_FILES := -LATIN_IME_JNI_SRC_FILES := -LATIN_IME_SRC_DIR := +include $(LOCAL_PATH)/CleanupNativeFileList.mk + +#################### Unit test on host environment +include $(LOCAL_PATH)/HostUnitTests.mk diff --git a/native/jni/CleanupNativeFileList.mk b/native/jni/CleanupNativeFileList.mk new file mode 100644 index 000000000..1738f8c58 --- /dev/null +++ b/native/jni/CleanupNativeFileList.mk @@ -0,0 +1,18 @@ +# Copyright (C) 2013 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. + +LATIN_IME_CORE_SRC_FILES := +LATIN_IME_CORE_TEST_FILES := +LATIN_IME_JNI_SRC_FILES := +LATIN_IME_SRC_DIR := diff --git a/native/jni/HostUnitTests.mk b/native/jni/HostUnitTests.mk new file mode 100644 index 000000000..572d36564 --- /dev/null +++ b/native/jni/HostUnitTests.mk @@ -0,0 +1,56 @@ +# Copyright (C) 2014 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. + +# HACK: Temporarily disable host tool build on Mac until the build system is ready for C++11. +LATINIME_HOST_OSNAME := $(shell uname -s) +ifneq ($(LATINIME_HOST_OSNAME), Darwin) # TODO: Remove this + +LOCAL_PATH := $(call my-dir) + +###################################### +include $(CLEAR_VARS) + +include $(LOCAL_PATH)/NativeFileList.mk + +#################### Host library for unit test +# TODO: Remove -std=c++11 once it is set by default on host build. +LATIN_IME_SRC_DIR := src +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_host_static_for_unittests +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := $(addprefix $(LATIN_IME_SRC_DIR)/, $(LATIN_IME_CORE_SRC_FILES)) +include $(BUILD_HOST_STATIC_LIBRARY) + +#################### Host native tests +include $(CLEAR_VARS) +LATIN_IME_TEST_SRC_DIR := tests +# TODO: Remove -std=c++11 once it is set by default on host build. +LOCAL_CFLAGS += -std=c++11 -Wno-unused-parameter -Wno-unused-function +LOCAL_CLANG := true +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) +LOCAL_MODULE := liblatinime_host_unittests +LOCAL_MODULE_TAGS := tests +LOCAL_SRC_FILES := $(addprefix $(LATIN_IME_TEST_SRC_DIR)/, $(LATIN_IME_CORE_TEST_FILES)) +LOCAL_STATIC_LIBRARIES += liblatinime_host_static_for_unittests libgtest_host libgtest_main_host +include $(BUILD_HOST_NATIVE_TEST) + +endif # Darwin - TODO: Remove this + +#################### Clean up the tmp vars +LATINIME_HOST_OSNAME := +LATIN_IME_SRC_DIR := +LATIN_IME_TEST_SRC_DIR := +include $(LOCAL_PATH)/CleanupNativeFileList.mk diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk new file mode 100644 index 000000000..34c190718 --- /dev/null +++ b/native/jni/NativeFileList.mk @@ -0,0 +1,106 @@ +# Copyright (C) 2013 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. + +LATIN_IME_JNI_SRC_FILES := \ + com_android_inputmethod_keyboard_ProximityInfo.cpp \ + com_android_inputmethod_latin_BinaryDictionary.cpp \ + com_android_inputmethod_latin_BinaryDictionaryUtils.cpp \ + com_android_inputmethod_latin_DicTraverseSession.cpp \ + jni_common.cpp + +LATIN_IME_CORE_SRC_FILES := \ + suggest/core/suggest.cpp \ + $(addprefix suggest/core/dicnode/, \ + dic_node.cpp \ + dic_node_utils.cpp \ + dic_nodes_cache.cpp) \ + $(addprefix suggest/core/dictionary/, \ + bigram_dictionary.cpp \ + dictionary.cpp \ + digraph_utils.cpp \ + error_type_utils.cpp \ + multi_bigram_map.cpp \ + property/word_property.cpp) \ + $(addprefix suggest/core/layout/, \ + additional_proximity_chars.cpp \ + proximity_info.cpp \ + proximity_info_params.cpp \ + proximity_info_state.cpp \ + proximity_info_state_utils.cpp) \ + suggest/core/policy/weighting.cpp \ + suggest/core/session/dic_traverse_session.cpp \ + $(addprefix suggest/core/result/, \ + suggestion_results.cpp \ + suggestions_output_utils.cpp) \ + $(addprefix suggest/policyimpl/dictionary/, \ + header/header_policy.cpp \ + header/header_read_write_utils.cpp \ + shortcut/shortcut_list_reading_utils.cpp \ + structure/dictionary_structure_with_buffer_policy_factory.cpp) \ + $(addprefix suggest/policyimpl/dictionary/bigram/, \ + bigram_list_read_write_utils.cpp \ + ver4_bigram_list_policy.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/pt_common/, \ + dynamic_pt_gc_event_listeners.cpp \ + dynamic_pt_reading_helper.cpp \ + dynamic_pt_reading_utils.cpp \ + dynamic_pt_updating_helper.cpp \ + dynamic_pt_writing_utils.cpp \ + patricia_trie_reading_utils.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v2/, \ + patricia_trie_policy.cpp \ + ver2_patricia_trie_node_reader.cpp \ + ver2_pt_node_array_reader.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v4/, \ + ver4_dict_buffers.cpp \ + ver4_dict_constants.cpp \ + ver4_patricia_trie_node_reader.cpp \ + ver4_patricia_trie_node_writer.cpp \ + ver4_patricia_trie_policy.cpp \ + ver4_patricia_trie_reading_utils.cpp \ + ver4_patricia_trie_writing_helper.cpp \ + ver4_pt_node_array_reader.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v4/content/, \ + bigram_dict_content.cpp \ + probability_dict_content.cpp \ + shortcut_dict_content.cpp \ + sparse_table_dict_content.cpp \ + terminal_position_lookup_table.cpp) \ + $(addprefix suggest/policyimpl/dictionary/utils/, \ + buffer_with_extendable_buffer.cpp \ + byte_array_utils.cpp \ + dict_file_writing_utils.cpp \ + file_utils.cpp \ + forgetting_curve_utils.cpp \ + format_utils.cpp \ + mmapped_buffer.cpp \ + sparse_table.cpp) \ + suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ + $(addprefix suggest/policyimpl/typing/, \ + scoring_params.cpp \ + typing_scoring.cpp \ + typing_suggest_policy.cpp \ + typing_traversal.cpp \ + typing_weighting.cpp) \ + $(addprefix utils/, \ + autocorrection_threshold_utils.cpp \ + char_utils.cpp \ + log_utils.cpp \ + time_keeper.cpp) + +LATIN_IME_CORE_TEST_FILES := \ + defines_test.cpp \ + suggest/core/layout/normal_distribution_2d_test.cpp \ + suggest/core/dictionary/bloom_filter_test.cpp \ + utils/autocorrection_threshold_utils_test.cpp diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 8f21c50ec..9016cae69 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -19,61 +19,25 @@ #include "com_android_inputmethod_latin_BinaryDictionary.h" #include <cstring> // for memset() +#include <vector> #include "defines.h" #include "jni.h" #include "jni_common.h" #include "suggest/core/dictionary/dictionary.h" +#include "suggest/core/dictionary/property/unigram_property.h" +#include "suggest/core/dictionary/property/word_property.h" +#include "suggest/core/result/suggestion_results.h" #include "suggest/core/suggest_options.h" -#include "suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h" -#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" -#include "utils/autocorrection_threshold_utils.h" +#include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" +#include "utils/char_utils.h" +#include "utils/jni_data_utils.h" +#include "utils/time_keeper.h" namespace latinime { class ProximityInfo; -// TODO: Move to makedict. -static jboolean latinime_BinaryDictionary_createEmptyDictFile(JNIEnv *env, jclass clazz, - jstring filePath, jlong dictVersion, jobjectArray attributeKeyStringArray, - jobjectArray attributeValueStringArray) { - const jsize filePathUtf8Length = env->GetStringUTFLength(filePath); - char filePathChars[filePathUtf8Length + 1]; - env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars); - filePathChars[filePathUtf8Length] = '\0'; - - const int keyCount = env->GetArrayLength(attributeKeyStringArray); - const int valueCount = env->GetArrayLength(attributeValueStringArray); - if (keyCount != valueCount) { - return false; - } - - HeaderReadWriteUtils::AttributeMap attributeMap; - for (int i = 0; i < keyCount; i++) { - jstring keyString = static_cast<jstring>( - env->GetObjectArrayElement(attributeKeyStringArray, i)); - const jsize keyUtf8Length = env->GetStringUTFLength(keyString); - char keyChars[keyUtf8Length + 1]; - env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars); - keyChars[keyUtf8Length] = '\0'; - HeaderReadWriteUtils::AttributeMap::key_type key; - HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key); - - jstring valueString = static_cast<jstring>( - env->GetObjectArrayElement(attributeValueStringArray, i)); - const jsize valueUtf8Length = env->GetStringUTFLength(valueString); - char valueChars[valueUtf8Length + 1]; - env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars); - valueChars[valueUtf8Length] = '\0'; - HeaderReadWriteUtils::AttributeMap::mapped_type value; - HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); - attributeMap[key] = value; - } - - return DictFileWritingUtils::createEmptyDictFile(filePathChars, static_cast<int>(dictVersion), - &attributeMap); -} - static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring sourceDir, jlong dictOffset, jlong dictSize, jboolean isUpdatable) { PROF_OPEN; @@ -86,20 +50,49 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s char sourceDirChars[sourceDirUtf8Length + 1]; env->GetStringUTFRegion(sourceDir, 0, env->GetStringLength(sourceDir), sourceDirChars); sourceDirChars[sourceDirUtf8Length] = '\0'; - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy = - DictionaryStructureWithBufferPolicyFactory::newDictionaryStructureWithBufferPolicy( + DictionaryStructureWithBufferPolicy::StructurePolicyPtr dictionaryStructureWithBufferPolicy( + DictionaryStructureWithBufferPolicyFactory::newPolicyForExistingDictFile( sourceDirChars, static_cast<int>(dictOffset), static_cast<int>(dictSize), - isUpdatable == JNI_TRUE); + isUpdatable == JNI_TRUE)); if (!dictionaryStructureWithBufferPolicy) { return 0; } - Dictionary *const dictionary = new Dictionary(env, dictionaryStructureWithBufferPolicy); + Dictionary *const dictionary = + new Dictionary(env, std::move(dictionaryStructureWithBufferPolicy)); PROF_END(66); PROF_CLOSE; return reinterpret_cast<jlong>(dictionary); } +static jlong latinime_BinaryDictionary_createOnMemory(JNIEnv *env, jclass clazz, + jlong formatVersion, jstring locale, jobjectArray attributeKeyStringArray, + jobjectArray attributeValueStringArray) { + const jsize localeUtf8Length = env->GetStringUTFLength(locale); + char localeChars[localeUtf8Length + 1]; + env->GetStringUTFRegion(locale, 0, env->GetStringLength(locale), localeChars); + localeChars[localeUtf8Length] = '\0'; + std::vector<int> localeCodePoints; + HeaderReadWriteUtils::insertCharactersIntoVector(localeChars, &localeCodePoints); + const int keyCount = env->GetArrayLength(attributeKeyStringArray); + const int valueCount = env->GetArrayLength(attributeValueStringArray); + if (keyCount != valueCount) { + return false; + } + DictionaryHeaderStructurePolicy::AttributeMap attributeMap = + JniDataUtils::constructAttributeMap(env, attributeKeyStringArray, + attributeValueStringArray); + DictionaryStructureWithBufferPolicy::StructurePolicyPtr dictionaryStructureWithBufferPolicy = + DictionaryStructureWithBufferPolicyFactory::newPolicyForOnMemoryDict( + formatVersion, localeCodePoints, &attributeMap); + if (!dictionaryStructureWithBufferPolicy) { + return 0; + } + Dictionary *const dictionary = + new Dictionary(env, std::move(dictionaryStructureWithBufferPolicy)); + return reinterpret_cast<jlong>(dictionary); +} + static void latinime_BinaryDictionary_flush(JNIEnv *env, jclass clazz, jlong dict, jstring filePath) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); @@ -135,15 +128,64 @@ static void latinime_BinaryDictionary_close(JNIEnv *env, jclass clazz, jlong dic delete dictionary; } -static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict, +static void latinime_BinaryDictionary_getHeaderInfo(JNIEnv *env, jclass clazz, jlong dict, + jintArray outHeaderSize, jintArray outFormatVersion, jobject outAttributeKeys, + jobject outAttributeValues) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) return; + const DictionaryHeaderStructurePolicy *const headerPolicy = + dictionary->getDictionaryStructurePolicy()->getHeaderStructurePolicy(); + const int headerSize = headerPolicy->getSize(); + env->SetIntArrayRegion(outHeaderSize, 0 /* start */, 1 /* len */, &headerSize); + const int formatVersion = headerPolicy->getFormatVersionNumber(); + env->SetIntArrayRegion(outFormatVersion, 0 /* start */, 1 /* len */, &formatVersion); + // Output attribute map + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + jmethodID addMethodId = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap = + headerPolicy->getAttributeMap(); + for (DictionaryHeaderStructurePolicy::AttributeMap::const_iterator it = attributeMap->begin(); + it != attributeMap->end(); ++it) { + // Output key + jintArray keyCodePointArray = env->NewIntArray(it->first.size()); + env->SetIntArrayRegion( + keyCodePointArray, 0 /* start */, it->first.size(), &it->first.at(0)); + env->CallBooleanMethod(outAttributeKeys, addMethodId, keyCodePointArray); + env->DeleteLocalRef(keyCodePointArray); + // Output value + jintArray valueCodePointArray = env->NewIntArray(it->second.size()); + env->SetIntArrayRegion( + valueCodePointArray, 0 /* start */, it->second.size(), &it->second.at(0)); + env->CallBooleanMethod(outAttributeValues, addMethodId, valueCodePointArray); + env->DeleteLocalRef(valueCodePointArray); + } + env->DeleteLocalRef(arrayListClass); + return; +} + +static int latinime_BinaryDictionary_getFormatVersion(JNIEnv *env, jclass clazz, jlong dict) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) return 0; + const DictionaryHeaderStructurePolicy *const headerPolicy = + dictionary->getDictionaryStructurePolicy()->getHeaderStructurePolicy(); + return headerPolicy->getFormatVersionNumber(); +} + +static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict, jlong proximityInfo, jlong dicTraverseSession, jintArray xCoordinatesArray, jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray, - jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions, - jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray, - jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray, - jintArray outputAutoCommitFirstWordConfidenceArray) { + jintArray inputCodePointsArray, jint inputSize, jintArray suggestOptions, + jintArray prevWordCodePointsForBigrams, jintArray outSuggestionCount, + jintArray outCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray, + jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray, + jfloatArray inOutLanguageWeight) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); - if (!dictionary) return 0; + // Assign 0 to outSuggestionCount here in case of returning earlier in this method. + int count = 0; + env->SetIntArrayRegion(outSuggestionCount, 0, 1 /* len */, &count); + if (!dictionary) { + return; + } ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo); DicTraverseSession *traverseSession = reinterpret_cast<DicTraverseSession *>(dicTraverseSession); @@ -158,7 +200,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j const jsize prevWordCodePointsLength = prevWordCodePointsForBigrams ? env->GetArrayLength(prevWordCodePointsForBigrams) : 0; int prevWordCodePointsInternal[prevWordCodePointsLength]; - int *prevWordCodePoints = 0; + int *prevWordCodePoints = nullptr; env->GetIntArrayRegion(xCoordinatesArray, 0, inputSize, xCoordinates); env->GetIntArrayRegion(yCoordinatesArray, 0, inputSize, yCoordinates); env->GetIntArrayRegion(timesArray, 0, inputSize, times); @@ -177,55 +219,44 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j // Output values /* By the way, let's check the output array length here to make sure */ - const jsize outputCodePointsLength = env->GetArrayLength(outputCodePointsArray); + const jsize outputCodePointsLength = env->GetArrayLength(outCodePointsArray); if (outputCodePointsLength != (MAX_WORD_LENGTH * MAX_RESULTS)) { AKLOGE("Invalid outputCodePointsLength: %d", outputCodePointsLength); ASSERT(false); - return 0; + return; } - const jsize scoresLength = env->GetArrayLength(scoresArray); + const jsize scoresLength = env->GetArrayLength(outScoresArray); if (scoresLength != MAX_RESULTS) { AKLOGE("Invalid scoresLength: %d", scoresLength); ASSERT(false); - return 0; + return; } - int outputCodePoints[outputCodePointsLength]; - int scores[scoresLength]; - const jsize spaceIndicesLength = env->GetArrayLength(spaceIndicesArray); - int spaceIndices[spaceIndicesLength]; - const jsize outputTypesLength = env->GetArrayLength(outputTypesArray); - int outputTypes[outputTypesLength]; const jsize outputAutoCommitFirstWordConfidenceLength = - env->GetArrayLength(outputAutoCommitFirstWordConfidenceArray); - // We only use the first result, as obviously we will only ever autocommit the first one + env->GetArrayLength(outAutoCommitFirstWordConfidenceArray); ASSERT(outputAutoCommitFirstWordConfidenceLength == 1); - int outputAutoCommitFirstWordConfidence[outputAutoCommitFirstWordConfidenceLength]; - memset(outputCodePoints, 0, sizeof(outputCodePoints)); - memset(scores, 0, sizeof(scores)); - memset(spaceIndices, 0, sizeof(spaceIndices)); - memset(outputTypes, 0, sizeof(outputTypes)); - memset(outputAutoCommitFirstWordConfidence, 0, sizeof(outputAutoCommitFirstWordConfidence)); - - int count; + if (outputAutoCommitFirstWordConfidenceLength != 1) { + // We only use the first result, as obviously we will only ever autocommit the first one + AKLOGE("Invalid outputAutoCommitFirstWordConfidenceLength: %d", + outputAutoCommitFirstWordConfidenceLength); + ASSERT(false); + return; + } + float languageWeight; + env->GetFloatArrayRegion(inOutLanguageWeight, 0, 1 /* len */, &languageWeight); + SuggestionResults suggestionResults(MAX_RESULTS); if (givenSuggestOptions.isGesture() || inputSize > 0) { - count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates, + // TODO: Use SuggestionResults to return suggestions. + dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates, times, pointerIds, inputCodePoints, inputSize, prevWordCodePoints, - prevWordCodePointsLength, commitPoint, &givenSuggestOptions, outputCodePoints, - scores, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence); + prevWordCodePointsLength, &givenSuggestOptions, languageWeight, + &suggestionResults); } else { - count = dictionary->getBigrams(prevWordCodePoints, prevWordCodePointsLength, - outputCodePoints, scores, outputTypes); + dictionary->getPredictions(prevWordCodePoints, prevWordCodePointsLength, + &suggestionResults); } - - // Copy back the output values - env->SetIntArrayRegion(outputCodePointsArray, 0, outputCodePointsLength, outputCodePoints); - env->SetIntArrayRegion(scoresArray, 0, scoresLength, scores); - env->SetIntArrayRegion(spaceIndicesArray, 0, spaceIndicesLength, spaceIndices); - env->SetIntArrayRegion(outputTypesArray, 0, outputTypesLength, outputTypes); - env->SetIntArrayRegion(outputAutoCommitFirstWordConfidenceArray, 0, - outputAutoCommitFirstWordConfidenceLength, outputAutoCommitFirstWordConfidence); - - return count; + suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray, + outScoresArray, outSpaceIndicesArray, outTypesArray, + outAutoCommitFirstWordConfidenceArray, inOutLanguageWeight); } static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict, @@ -252,44 +283,64 @@ static jint latinime_BinaryDictionary_getBigramProbability(JNIEnv *env, jclass c word1Length); } -static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jclass clazz, - jintArray before, jintArray after, jint score) { - jsize beforeLength = env->GetArrayLength(before); - jsize afterLength = env->GetArrayLength(after); - int beforeCodePoints[beforeLength]; - int afterCodePoints[afterLength]; - env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); - env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); - return AutocorrectionThresholdUtils::calcNormalizedScore(beforeCodePoints, beforeLength, - afterCodePoints, afterLength, score); +// Method to iterate all words in the dictionary for makedict. +// If token is 0, this method newly starts iterating the dictionary. This method returns 0 when +// the dictionary does not have a next word. +static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz, + jlong dict, jint token, jintArray outCodePoints) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) return 0; + const jsize outCodePointsLength = env->GetArrayLength(outCodePoints); + if (outCodePointsLength != MAX_WORD_LENGTH) { + AKLOGE("Invalid outCodePointsLength: %d", outCodePointsLength); + ASSERT(false); + return 0; + } + int wordCodePoints[outCodePointsLength]; + memset(wordCodePoints, 0, sizeof(wordCodePoints)); + const int nextToken = dictionary->getNextWordAndNextToken(token, wordCodePoints); + env->SetIntArrayRegion(outCodePoints, 0, outCodePointsLength, wordCodePoints); + return nextToken; } -static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jclass clazz, jintArray before, - jintArray after) { - jsize beforeLength = env->GetArrayLength(before); - jsize afterLength = env->GetArrayLength(after); - int beforeCodePoints[beforeLength]; - int afterCodePoints[afterLength]; - env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); - env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); - return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength, - afterCodePoints, afterLength); +static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz, + jlong dict, jintArray word, jintArray outCodePoints, jbooleanArray outFlags, + jintArray outProbabilityInfo, jobject outBigramTargets, jobject outBigramProbabilityInfo, + jobject outShortcutTargets, jobject outShortcutProbabilities) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) return; + const jsize wordLength = env->GetArrayLength(word); + int wordCodePoints[wordLength]; + env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints); + const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, wordLength); + wordProperty.outputProperties(env, outCodePoints, outFlags, outProbabilityInfo, + outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, + outShortcutProbabilities); } static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz, jlong dict, - jintArray word, jint probability) { + jintArray word, jint probability, jintArray shortcutTarget, jint shortcutProbability, + jboolean isNotAWord, jboolean isBlacklisted, jint timestamp) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); if (!dictionary) { return; } - jsize wordLength = env->GetArrayLength(word); - int codePoints[wordLength]; - env->GetIntArrayRegion(word, 0, wordLength, codePoints); - dictionary->addUnigramWord(codePoints, wordLength, probability); + jsize codePointCount = env->GetArrayLength(word); + int codePoints[codePointCount]; + env->GetIntArrayRegion(word, 0, codePointCount, codePoints); + std::vector<UnigramProperty::ShortcutProperty> shortcuts; + std::vector<int> shortcutTargetCodePoints; + JniDataUtils::jintarrayToVector(env, shortcutTarget, &shortcutTargetCodePoints); + if (!shortcutTargetCodePoints.empty()) { + shortcuts.emplace_back(&shortcutTargetCodePoints, shortcutProbability); + } + const UnigramProperty unigramProperty(isNotAWord, isBlacklisted, + probability, timestamp, 0 /* level */, 0 /* count */, &shortcuts); + dictionary->addUnigramWord(codePoints, codePointCount, &unigramProperty); } static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, jlong dict, - jintArray word0, jintArray word1, jint probability) { + jintArray word0, jintArray word1, jint probability, jint timestamp) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); if (!dictionary) { return; @@ -301,7 +352,7 @@ static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, int word1CodePoints[word1Length]; env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints); dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints, - word1Length, probability); + word1Length, probability, timestamp); } static void latinime_BinaryDictionary_removeBigramWords(JNIEnv *env, jclass clazz, jlong dict, @@ -320,6 +371,89 @@ static void latinime_BinaryDictionary_removeBigramWords(JNIEnv *env, jclass claz word1Length); } +// Returns how many language model params are processed. +static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, jclass clazz, + jlong dict, jobjectArray languageModelParams, jint startIndex) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) { + return 0; + } + jsize languageModelParamCount = env->GetArrayLength(languageModelParams); + if (languageModelParamCount == 0 || startIndex >= languageModelParamCount) { + return 0; + } + jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, 0); + jclass languageModelParamClass = env->GetObjectClass(languageModelParam); + env->DeleteLocalRef(languageModelParam); + + jfieldID word0FieldId = env->GetFieldID(languageModelParamClass, "mWord0", "[I"); + jfieldID word1FieldId = env->GetFieldID(languageModelParamClass, "mWord1", "[I"); + jfieldID unigramProbabilityFieldId = + env->GetFieldID(languageModelParamClass, "mUnigramProbability", "I"); + jfieldID bigramProbabilityFieldId = + env->GetFieldID(languageModelParamClass, "mBigramProbability", "I"); + jfieldID timestampFieldId = + env->GetFieldID(languageModelParamClass, "mTimestamp", "I"); + jfieldID shortcutTargetFieldId = + env->GetFieldID(languageModelParamClass, "mShortcutTarget", "[I"); + jfieldID shortcutProbabilityFieldId = + env->GetFieldID(languageModelParamClass, "mShortcutProbability", "I"); + jfieldID isNotAWordFieldId = + env->GetFieldID(languageModelParamClass, "mIsNotAWord", "Z"); + jfieldID isBlacklistedFieldId = + env->GetFieldID(languageModelParamClass, "mIsBlacklisted", "Z"); + env->DeleteLocalRef(languageModelParamClass); + + for (int i = startIndex; i < languageModelParamCount; ++i) { + jobject languageModelParam = env->GetObjectArrayElement(languageModelParams, i); + // languageModelParam is a set of params for word1; thus, word1 cannot be null. On the + // other hand, word0 can be null and then it means the set of params doesn't contain bigram + // information. + jintArray word0 = static_cast<jintArray>( + env->GetObjectField(languageModelParam, word0FieldId)); + jsize word0Length = word0 ? env->GetArrayLength(word0) : 0; + int word0CodePoints[word0Length]; + if (word0) { + env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints); + } + jintArray word1 = static_cast<jintArray>( + env->GetObjectField(languageModelParam, word1FieldId)); + jsize word1Length = env->GetArrayLength(word1); + int word1CodePoints[word1Length]; + env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints); + jint unigramProbability = env->GetIntField(languageModelParam, unigramProbabilityFieldId); + jint timestamp = env->GetIntField(languageModelParam, timestampFieldId); + jboolean isNotAWord = env->GetBooleanField(languageModelParam, isNotAWordFieldId); + jboolean isBlacklisted = env->GetBooleanField(languageModelParam, isBlacklistedFieldId); + jintArray shortcutTarget = static_cast<jintArray>( + env->GetObjectField(languageModelParam, shortcutTargetFieldId)); + std::vector<UnigramProperty::ShortcutProperty> shortcuts; + std::vector<int> shortcutTargetCodePoints; + JniDataUtils::jintarrayToVector(env, shortcutTarget, &shortcutTargetCodePoints); + if (!shortcutTargetCodePoints.empty()) { + jint shortcutProbability = + env->GetIntField(languageModelParam, shortcutProbabilityFieldId); + shortcuts.emplace_back(&shortcutTargetCodePoints, shortcutProbability); + } + const UnigramProperty unigramProperty(isNotAWord, isBlacklisted, + unigramProbability, timestamp, 0 /* level */, 0 /* count */, &shortcuts); + dictionary->addUnigramWord(word1CodePoints, word1Length, &unigramProperty); + if (word0) { + jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId); + dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints, word1Length, + bigramProbability, timestamp); + } + if (dictionary->needsToRunGC(true /* mindsBlockByGC */)) { + return i + 1; + } + env->DeleteLocalRef(word0); + env->DeleteLocalRef(word1); + env->DeleteLocalRef(shortcutTarget); + env->DeleteLocalRef(languageModelParam); + } + return languageModelParamCount; +} + static int latinime_BinaryDictionary_calculateProbabilityNative(JNIEnv *env, jclass clazz, jlong dict, jint unigramProbability, jint bigramProbability) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); @@ -343,27 +477,45 @@ static jstring latinime_BinaryDictionary_getProperty(JNIEnv *env, jclass clazz, static const int GET_PROPERTY_RESULT_LENGTH = 100; char resultChars[GET_PROPERTY_RESULT_LENGTH]; resultChars[0] = '\0'; - dictionary->getProperty(queryChars, resultChars, GET_PROPERTY_RESULT_LENGTH); + dictionary->getProperty(queryChars, queryUtf8Length, resultChars, GET_PROPERTY_RESULT_LENGTH); return env->NewStringUTF(resultChars); } +static bool latinime_BinaryDictionary_isCorruptedNative(JNIEnv *env, jclass clazz, jlong dict) { + Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); + if (!dictionary) { + return false; + } + return dictionary->getDictionaryStructurePolicy()->isCorrupted(); +} + static const JNINativeMethod sMethods[] = { { - const_cast<char *>("createEmptyDictFileNative"), - const_cast<char *>("(Ljava/lang/String;J[Ljava/lang/String;[Ljava/lang/String;)Z"), - reinterpret_cast<void *>(latinime_BinaryDictionary_createEmptyDictFile) - }, - { const_cast<char *>("openNative"), const_cast<char *>("(Ljava/lang/String;JJZ)J"), reinterpret_cast<void *>(latinime_BinaryDictionary_open) }, { + const_cast<char *>("createOnMemoryNative"), + const_cast<char *>("(JLjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)J"), + reinterpret_cast<void *>(latinime_BinaryDictionary_createOnMemory) + }, + { const_cast<char *>("closeNative"), const_cast<char *>("(J)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_close) }, { + const_cast<char *>("getFormatVersionNative"), + const_cast<char *>("(J)I"), + reinterpret_cast<void *>(latinime_BinaryDictionary_getFormatVersion) + }, + { + const_cast<char *>("getHeaderInfoNative"), + const_cast<char *>("(J[I[ILjava/util/ArrayList;Ljava/util/ArrayList;)V"), + reinterpret_cast<void *>(latinime_BinaryDictionary_getHeaderInfo) + }, + { const_cast<char *>("flushNative"), const_cast<char *>("(JLjava/lang/String;)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_flush) @@ -380,7 +532,7 @@ static const JNINativeMethod sMethods[] = { }, { const_cast<char *>("getSuggestionsNative"), - const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"), + const_cast<char *>("(JJJ[I[I[I[I[II[I[I[I[I[I[I[I[I[F)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions) }, { @@ -394,23 +546,24 @@ static const JNINativeMethod sMethods[] = { reinterpret_cast<void *>(latinime_BinaryDictionary_getBigramProbability) }, { - const_cast<char *>("calcNormalizedScoreNative"), - const_cast<char *>("([I[II)F"), - reinterpret_cast<void *>(latinime_BinaryDictionary_calcNormalizedScore) + const_cast<char *>("getWordPropertyNative"), + const_cast<char *>("(J[I[I[Z[ILjava/util/ArrayList;Ljava/util/ArrayList;" + "Ljava/util/ArrayList;Ljava/util/ArrayList;)V"), + reinterpret_cast<void *>(latinime_BinaryDictionary_getWordProperty) }, { - const_cast<char *>("editDistanceNative"), - const_cast<char *>("([I[I)I"), - reinterpret_cast<void *>(latinime_BinaryDictionary_editDistance) + const_cast<char *>("getNextWordNative"), + const_cast<char *>("(JI[I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionary_getNextWord) }, { const_cast<char *>("addUnigramWordNative"), - const_cast<char *>("(J[II)V"), + const_cast<char *>("(J[II[IIZZI)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_addUnigramWord) }, { const_cast<char *>("addBigramWordsNative"), - const_cast<char *>("(J[I[II)V"), + const_cast<char *>("(J[I[III)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_addBigramWords) }, { @@ -419,6 +572,12 @@ static const JNINativeMethod sMethods[] = { reinterpret_cast<void *>(latinime_BinaryDictionary_removeBigramWords) }, { + const_cast<char *>("addMultipleDictionaryEntriesNative"), + const_cast<char *>( + "(J[Lcom/android/inputmethod/latin/utils/LanguageModelParam;I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionary_addMultipleDictionaryEntries) + }, + { const_cast<char *>("calculateProbabilityNative"), const_cast<char *>("(JII)I"), reinterpret_cast<void *>(latinime_BinaryDictionary_calculateProbabilityNative) @@ -427,6 +586,11 @@ static const JNINativeMethod sMethods[] = { const_cast<char *>("getPropertyNative"), const_cast<char *>("(JLjava/lang/String;)Ljava/lang/String;"), reinterpret_cast<void *>(latinime_BinaryDictionary_getProperty) + }, + { + const_cast<char *>("isCorruptedNative"), + const_cast<char *>("(J)Z"), + reinterpret_cast<void *>(latinime_BinaryDictionary_isCorruptedNative) } }; diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp new file mode 100644 index 000000000..0a34b783a --- /dev/null +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 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. + */ + +#define LOG_TAG "LatinIME: jni: BinaryDictionaryUtils" + +#include "com_android_inputmethod_latin_BinaryDictionaryUtils.h" + +#include "defines.h" +#include "jni.h" +#include "jni_common.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "utils/autocorrection_threshold_utils.h" +#include "utils/char_utils.h" +#include "utils/jni_data_utils.h" +#include "utils/time_keeper.h" + +namespace latinime { + +static jboolean latinime_BinaryDictionaryUtils_createEmptyDictFile(JNIEnv *env, jclass clazz, + jstring filePath, jlong dictVersion, jstring locale, jobjectArray attributeKeyStringArray, + jobjectArray attributeValueStringArray) { + const jsize filePathUtf8Length = env->GetStringUTFLength(filePath); + char filePathChars[filePathUtf8Length + 1]; + env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars); + filePathChars[filePathUtf8Length] = '\0'; + + const jsize localeUtf8Length = env->GetStringUTFLength(locale); + char localeChars[localeUtf8Length + 1]; + env->GetStringUTFRegion(locale, 0, env->GetStringLength(locale), localeChars); + localeChars[localeUtf8Length] = '\0'; + std::vector<int> localeCodePoints; + HeaderReadWriteUtils::insertCharactersIntoVector(localeChars, &localeCodePoints); + + const int keyCount = env->GetArrayLength(attributeKeyStringArray); + const int valueCount = env->GetArrayLength(attributeValueStringArray); + if (keyCount != valueCount) { + return false; + } + DictionaryHeaderStructurePolicy::AttributeMap attributeMap = + JniDataUtils::constructAttributeMap(env, attributeKeyStringArray, + attributeValueStringArray); + return DictFileWritingUtils::createEmptyDictFile(filePathChars, static_cast<int>(dictVersion), + localeCodePoints, &attributeMap); +} + +static jfloat latinime_BinaryDictionaryUtils_calcNormalizedScore(JNIEnv *env, jclass clazz, + jintArray before, jintArray after, jint score) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + int beforeCodePoints[beforeLength]; + int afterCodePoints[afterLength]; + env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); + env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); + return AutocorrectionThresholdUtils::calcNormalizedScore(beforeCodePoints, beforeLength, + afterCodePoints, afterLength, score); +} + +static jint latinime_BinaryDictionaryUtils_editDistance(JNIEnv *env, jclass clazz, jintArray before, + jintArray after) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + int beforeCodePoints[beforeLength]; + int afterCodePoints[afterLength]; + env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); + env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); + return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength, + afterCodePoints, afterLength); +} + +static int latinime_BinaryDictionaryUtils_setCurrentTimeForTest(JNIEnv *env, jclass clazz, + jint currentTime) { + if (currentTime >= 0) { + TimeKeeper::startTestModeWithForceCurrentTime(currentTime); + } else { + TimeKeeper::stopTestMode(); + } + TimeKeeper::setCurrentTime(); + return TimeKeeper::peekCurrentTime(); +} + +static const JNINativeMethod sMethods[] = { + { + const_cast<char *>("createEmptyDictFileNative"), + const_cast<char *>( + "(Ljava/lang/String;JLjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)Z"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_createEmptyDictFile) + }, + { + const_cast<char *>("calcNormalizedScoreNative"), + const_cast<char *>("([I[II)F"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_calcNormalizedScore) + }, + { + const_cast<char *>("editDistanceNative"), + const_cast<char *>("([I[I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_editDistance) + }, + { + const_cast<char *>("setCurrentTimeForTestNative"), + const_cast<char *>("(I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_setCurrentTimeForTest) + } +}; + +int register_BinaryDictionaryUtils(JNIEnv *env) { + const char *const kClassPathName = "com/android/inputmethod/latin/utils/BinaryDictionaryUtils"; + return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods)); +} +} // namespace latinime diff --git a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.h index 07e80f1d8..38edcd20c 100644 --- a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2014 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,12 +14,12 @@ * limitations under the License. */ -#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H -#define _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H +#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H +#define _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H #include "jni.h" namespace latinime { -int register_Ver3DictDecoder(JNIEnv *env); +int register_BinaryDictionaryUtils(JNIEnv *env); } // namespace latinime -#endif // _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H +#endif // _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H diff --git a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp deleted file mode 100644 index 15088b65a..000000000 --- a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#define LOG_TAG "LatinIME: jni: Ver3DictDecoder" - -#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h" - -#include "defines.h" -#include "jni.h" -#include "jni_common.h" - -namespace latinime { -static int latinime_Ver3DictDecoder_doNothing(JNIEnv *env, jclass clazz) { - // This is a phony method for test - it does nothing. It just returns some value - // unlikely to be in memory by chance for testing purposes. - // TODO: remove this method. - return 2097; -} - -static const JNINativeMethod sMethods[] = { - { - // TODO: remove this entry when we have one useful method in here - const_cast<char *>("doNothing"), - const_cast<char *>("()I"), - reinterpret_cast<void *>(latinime_Ver3DictDecoder_doNothing) - }, -}; - -int register_Ver3DictDecoder(JNIEnv *env) { - const char *const kClassPathName = - "com/android/inputmethod/latin/makedict/Ver3DictDecoder"; - return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods)); -} -} // namespace latinime diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 3a8f4362d..ce5e30c5d 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -18,12 +18,10 @@ #include "jni_common.h" -#ifndef HOST_TOOL #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" +#include "com_android_inputmethod_latin_BinaryDictionaryUtils.h" #include "com_android_inputmethod_latin_DicTraverseSession.h" -#endif -#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h" #include "defines.h" /* @@ -41,11 +39,14 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { AKLOGE("ERROR: JNIEnv is invalid"); return -1; } -#ifndef HOST_TOOL if (!latinime::register_BinaryDictionary(env)) { AKLOGE("ERROR: BinaryDictionary native registration failed"); return -1; } + if (!latinime::register_BinaryDictionaryUtils(env)) { + AKLOGE("ERROR: BinaryDictionaryUtils native registration failed"); + return -1; + } if (!latinime::register_DicTraverseSession(env)) { AKLOGE("ERROR: DicTraverseSession native registration failed"); return -1; @@ -54,11 +55,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { AKLOGE("ERROR: ProximityInfo native registration failed"); return -1; } -#endif - if (!latinime::register_Ver3DictDecoder(env)) { - AKLOGE("ERROR: Ver3DictDecoder native registration failed"); - return -1; - } /* success -- return valid version number */ return JNI_VERSION_1_6; } @@ -71,7 +67,7 @@ int registerNativeMethods(JNIEnv *env, const char *const className, const JNINat AKLOGE("Native registration unable to find class '%s'", className); return JNI_FALSE; } - if (env->RegisterNatives(clazz, methods, numMethods) < 0) { + if (env->RegisterNatives(clazz, methods, numMethods) != 0) { AKLOGE("RegisterNatives failed for '%s'", className); env->DeleteLocalRef(clazz); return JNI_FALSE; diff --git a/native/jni/run-tests.sh b/native/jni/run-tests.sh new file mode 100755 index 000000000..5b60e0d65 --- /dev/null +++ b/native/jni/run-tests.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Copyright 2014, 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. + +if [[ $(type -t mmm) != function ]]; then +echo "Usage:" 1>&2 +echo " source $0" 1>&2 +echo " or" 1>&2 +echo " . $0" 1>&2 +if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi +fi + +pushd $PWD > /dev/null +cd $(gettop) +mmm -j16 packages/inputmethods/LatinIME/native/jni || \ + make -j16 liblatinime_host_unittests +${ANDROID_HOST_OUT}/bin/liblatinime_host_unittests +popd > /dev/null
\ No newline at end of file diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index 742e388e4..cd095c91d 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -35,7 +35,13 @@ // Must be equal to ProximityInfo.MAX_PROXIMITY_CHARS_SIZE in Java #define MAX_PROXIMITY_CHARS_SIZE 16 #define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 -#define NELEMS(x) (sizeof(x) / sizeof((x)[0])) + +// TODO: Use size_t instead of int. +// Disclaimer: You will see a compile error if you use this macro against a variable-length array. +// Sorry for the inconvenience. It isn't supported. +template <typename T, int N> +char (&ArraySizeHelper(T (&array)[N]))[N]; +#define NELEMS(x) (sizeof(ArraySizeHelper(x))) AK_FORCE_INLINE static int intArrayToCharArray(const int *const source, const int sourceSize, char *dest, const int destSize) { @@ -87,14 +93,24 @@ AK_FORCE_INLINE static int intArrayToCharArray(const int *const source, const in } #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) +#if defined(__ANDROID__) #include <android/log.h> +#endif // defined(__ANDROID__) #ifndef LOG_TAG #define LOG_TAG "LatinIME: " #endif // LOG_TAG + +#if defined(HOST_TOOL) +#include <stdio.h> +#define AKLOGE(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#define AKLOGI(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#else // defined(HOST_TOOL) #define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__) #define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__) +#endif // defined(HOST_TOOL) -#define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0) +#define DUMP_SUGGESTION(words, frequencies, index, score) \ + do { dumpWordInfo(words, frequencies, index, score); } while (0) #define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0) #define INTS_TO_CHARS(input, length, output, outlength) do { \ intArrayToCharArray(input, length, output, outlength); } while (0) @@ -108,14 +124,6 @@ static inline void dumpWordInfo(const int *word, const int length, const int ran } } -static inline void dumpResult(const int *outWords, const int *frequencies) { - AKLOGI("--- DUMP RESULT ---------"); - for (int i = 0; i < MAX_RESULTS; ++i) { - dumpWordInfo(&outWords[i * MAX_WORD_LENGTH], MAX_WORD_LENGTH, i, frequencies[i]); - } - AKLOGI("-------------------------"); -} - static AK_FORCE_INLINE void dumpWord(const int *word, const int length) { static char charBuf[50]; const int N = intArrayToCharArray(word, length, charBuf, NELEMS(charBuf)); @@ -156,7 +164,7 @@ static inline void showStackTrace() { #else // defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) #define AKLOGE(fmt, ...) #define AKLOGI(fmt, ...) -#define DUMP_RESULT(words, frequencies) +#define DUMP_SUGGESTION(words, frequencies, index, score) #define DUMP_WORD(word, length) #undef DO_ASSERT_TEST #define ASSERT(success) @@ -285,23 +293,18 @@ static inline void prof_out(void) { #define M_PI_F 3.14159265f #define MAX_PERCENTILE 100 -// Number of base-10 digits in the largest integer + 1 to leave room for a zero terminator. -// As such, this is the maximum number of characters will be needed to represent an int as a -// string, including the terminator; this is used as the size of a string buffer large enough to -// hold any value that is intended to fit in an integer, e.g. in the code that reads the header -// of the binary dictionary where a {key,value} string pair scheme is used. -#define LARGEST_INT_DIGIT_COUNT 11 - #define NOT_A_CODE_POINT (-1) #define NOT_A_DISTANCE (-1) #define NOT_A_COORDINATE (-1) #define NOT_AN_INDEX (-1) #define NOT_A_PROBABILITY (-1) #define NOT_A_DICT_POS (S_INT_MIN) +#define NOT_A_TIMESTAMP (-1) +#define NOT_A_LANGUAGE_WEIGHT (-1.0f) // A special value to mean the first word confidence makes no sense in this case, // e.g. this is not a multi-word suggestion. -#define NOT_A_FIRST_WORD_CONFIDENCE (S_INT_MAX) +#define NOT_A_FIRST_WORD_CONFIDENCE (S_INT_MIN) // How high the confidence needs to be for us to auto-commit. Arbitrary. // This needs to be the same as CONFIDENCE_FOR_AUTO_COMMIT in BinaryDictionary.java #define CONFIDENCE_FOR_AUTO_COMMIT (1000000) @@ -320,9 +323,6 @@ static inline void prof_out(void) { #define MAX_PROBABILITY 255 #define MAX_BIGRAM_ENCODED_PROBABILITY 15 -// Assuming locale strings such as en_US, sr-Latn etc. -#define MAX_LOCALE_STRING_LENGTH 10 - // Max value for length, distance and probability which are used in weighting // TODO: Remove #define MAX_VALUE_FOR_WEIGHTING 10000000 @@ -334,19 +334,21 @@ static inline void prof_out(void) { #define MAX_POINTER_COUNT 1 #define MAX_POINTER_COUNT_G 2 -template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; } -template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; } +#define DISALLOW_DEFAULT_CONSTRUCTOR(TypeName) \ + TypeName() = delete + +#define DISALLOW_COPY_CONSTRUCTOR(TypeName) \ + TypeName(const TypeName&) = delete -// DEBUG -#define INPUTLENGTH_FOR_DEBUG (-1) -#define MIN_OUTPUT_INDEX_FOR_DEBUG (-1) +#define DISALLOW_ASSIGNMENT_OPERATOR(TypeName) \ + void operator=(const TypeName&) = delete #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) + DISALLOW_COPY_CONSTRUCTOR(TypeName); \ + DISALLOW_ASSIGNMENT_OPERATOR(TypeName) #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ + DISALLOW_DEFAULT_CONSTRUCTOR(TypeName); \ DISALLOW_COPY_AND_ASSIGN(TypeName) // Used as a return value for character comparison @@ -392,24 +394,4 @@ typedef enum { // Create new word with space substitution CT_NEW_WORD_SPACE_SUBSTITUTION, } CorrectionType; - -// ErrorType is mainly decided by CorrectionType but it is also depending on if -// the correction has really been performed or not. -typedef enum { - // Substitution, omission and transposition - ET_EDIT_CORRECTION, - // Proximity error - ET_PROXIMITY_CORRECTION, - // Completion - ET_COMPLETION, - // New word - // TODO: Remove. - // A new word error should be an edit correction error or a proximity correction error. - ET_NEW_WORD, - // Treat error as an intentional omission when the CorrectionType is omission and the node can - // be intentional omission. - ET_INTENTIONAL_OMISSION, - // Not treated as an error. Tracked for checking exact match - ET_NOT_AN_ERROR -} ErrorType; #endif // LATINIME_DEFINES_H diff --git a/native/jni/src/suggest/core/dicnode/dic_node.cpp b/native/jni/src/suggest/core/dicnode/dic_node.cpp index de088c7d0..414dc3b1e 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_node.cpp @@ -24,8 +24,7 @@ DicNode::DicNode(const DicNode &dicNode) mProfiler(dicNode.mProfiler), #endif mDicNodeProperties(dicNode.mDicNodeProperties), mDicNodeState(dicNode.mDicNodeState), - mIsCachedForNextSuggestion(dicNode.mIsCachedForNextSuggestion), mIsUsed(dicNode.mIsUsed), - mReleaseListener(0) { + mIsCachedForNextSuggestion(dicNode.mIsCachedForNextSuggestion) { /* empty */ } @@ -36,8 +35,6 @@ DicNode &DicNode::operator=(const DicNode &dicNode) { mDicNodeProperties = dicNode.mDicNodeProperties; mDicNodeState = dicNode.mDicNodeState; mIsCachedForNextSuggestion = dicNode.mIsCachedForNextSuggestion; - mIsUsed = dicNode.mIsUsed; - mReleaseListener = dicNode.mReleaseListener; return *this; } diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h index 49cfdecac..47f5ec0d7 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.h +++ b/native/jni/src/suggest/core/dicnode/dic_node.h @@ -19,29 +19,35 @@ #include "defines.h" #include "suggest/core/dicnode/dic_node_profiler.h" -#include "suggest/core/dicnode/dic_node_release_listener.h" +#include "suggest/core/dicnode/dic_node_utils.h" #include "suggest/core/dicnode/internal/dic_node_state.h" #include "suggest/core/dicnode/internal/dic_node_properties.h" #include "suggest/core/dictionary/digraph_utils.h" +#include "suggest/core/dictionary/error_type_utils.h" +#include "suggest/core/layout/proximity_info_state.h" #include "utils/char_utils.h" #if DEBUG_DICT #define LOGI_SHOW_ADD_COST_PROP \ - do { char charBuf[50]; \ - INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \ - AKLOGI("%20s, \"%c\", size = %03d, total = %03d, index(0) = %02d, dist = %.4f, %s,,", \ - __FUNCTION__, getNodeCodePoint(), inputSize, getTotalInputIndex(), \ - getInputIndex(0), getNormalizedCompoundDistance(), charBuf); } while (0) + do { \ + char charBuf[50]; \ + INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \ + AKLOGI("%20s, \"%c\", size = %03d, total = %03d, index(0) = %02d, dist = %.4f, %s,,", \ + __FUNCTION__, getNodeCodePoint(), inputSize, getTotalInputIndex(), \ + getInputIndex(0), getNormalizedCompoundDistance(), charBuf); \ + } while (0) #define DUMP_WORD_AND_SCORE(header) \ - do { char charBuf[50]; char prevWordCharBuf[50]; \ - INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \ - INTS_TO_CHARS(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, \ - mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), prevWordCharBuf, \ - NELEMS(prevWordCharBuf)); \ - AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %s, %d, %5f,", header, \ - getSpatialDistanceForScoring(), getLanguageDistanceForScoring(), \ - getNormalizedCompoundDistance(), getRawLength(), prevWordCharBuf, charBuf, \ - getInputIndex(0), getNormalizedCompoundDistanceAfterFirstWord()); \ + do { \ + char charBuf[50]; \ + INTS_TO_CHARS(getOutputWordBuf(), \ + getNodeCodePointCount() \ + + mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(), \ + charBuf, NELEMS(charBuf)); \ + AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %d, %5f,", header, \ + getSpatialDistanceForScoring(), \ + mDicNodeState.mDicNodeStateScoring.getLanguageDistance(), \ + getNormalizedCompoundDistance(), getRawLength(), charBuf, \ + getInputIndex(0), getNormalizedCompoundDistanceAfterFirstWord()); \ } while (0) #else #define LOGI_SHOW_ADD_COST_PROP @@ -77,113 +83,69 @@ class DicNode { #if DEBUG_DICT DicNodeProfiler mProfiler; #endif - ////////////////// - // Memory utils // - ////////////////// - AK_FORCE_INLINE static void managedDelete(DicNode *node) { - node->remove(); - } - // end - ///////////////// AK_FORCE_INLINE DicNode() : #if DEBUG_DICT mProfiler(), #endif - mDicNodeProperties(), mDicNodeState(), mIsCachedForNextSuggestion(false), - mIsUsed(false), mReleaseListener(0) {} + mDicNodeProperties(), mDicNodeState(), mIsCachedForNextSuggestion(false) {} DicNode(const DicNode &dicNode); DicNode &operator=(const DicNode &dicNode); - virtual ~DicNode() {} + ~DicNode() {} // Init for copy - void initByCopy(const DicNode *dicNode) { - mIsUsed = true; + void initByCopy(const DicNode *const dicNode) { mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; - mDicNodeProperties.init(&dicNode->mDicNodeProperties); - mDicNodeState.init(&dicNode->mDicNodeState); + mDicNodeProperties.initByCopy(&dicNode->mDicNodeProperties); + mDicNodeState.initByCopy(&dicNode->mDicNodeState); PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); } - // Init for root with prevWordNodePos which is used for bigram - void initAsRoot(const int rootGroupPos, const int prevWordNodePos) { - mIsUsed = true; + // Init for root with prevWordPtNodePos which is used for bigram + void initAsRoot(const int rootPtNodeArrayPos, const int prevWordPtNodePos) { mIsCachedForNextSuggestion = false; - mDicNodeProperties.init( - NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */, - NOT_A_PROBABILITY /* probability */, false /* isTerminal */, - true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */, - 0 /* terminalDepth */); - mDicNodeState.init(prevWordNodePos); + mDicNodeProperties.init(rootPtNodeArrayPos, prevWordPtNodePos); + mDicNodeState.init(); PROF_NODE_RESET(mProfiler); } // Init for root with previous word - void initAsRootWithPreviousWord(DicNode *dicNode, const int rootGroupPos) { - mIsUsed = true; + void initAsRootWithPreviousWord(const DicNode *const dicNode, const int rootPtNodeArrayPos) { mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; - mDicNodeProperties.init( - NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */, - NOT_A_PROBABILITY /* probability */, false /* isTerminal */, - true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */, - 0 /* terminalDepth */); - // TODO: Move to dicNodeState? - mDicNodeState.mDicNodeStateOutput.init(); // reset for next word - mDicNodeState.mDicNodeStateInput.init( - &dicNode->mDicNodeState.mDicNodeStateInput, true /* resetTerminalDiffCost */); - mDicNodeState.mDicNodeStateScoring.init( - &dicNode->mDicNodeState.mDicNodeStateScoring); - mDicNodeState.mDicNodeStatePrevWord.init( - dicNode->mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() + 1, - dicNode->mDicNodeProperties.getProbability(), - dicNode->mDicNodeProperties.getPos(), - dicNode->mDicNodeState.mDicNodeStatePrevWord.mPrevWord, - dicNode->mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), - dicNode->getOutputWordBuf(), - dicNode->mDicNodeProperties.getDepth(), - dicNode->mDicNodeState.mDicNodeStatePrevWord.getSecondWordFirstInputIndex(), - mDicNodeState.mDicNodeStateInput.getInputIndex(0) /* lastInputIndex */); + mDicNodeProperties.init(rootPtNodeArrayPos, dicNode->mDicNodeProperties.getPtNodePos()); + mDicNodeState.initAsRootWithPreviousWord(&dicNode->mDicNodeState, + dicNode->mDicNodeProperties.getDepth()); PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); } - void initAsPassingChild(DicNode *parentNode) { - mIsUsed = true; - mIsCachedForNextSuggestion = parentNode->mIsCachedForNextSuggestion; - const int c = parentNode->getNodeTypedCodePoint(); - mDicNodeProperties.init(&parentNode->mDicNodeProperties, c); - mDicNodeState.init(&parentNode->mDicNodeState); - PROF_NODE_COPY(&parentNode->mProfiler, mProfiler); + void initAsPassingChild(DicNode *parentDicNode) { + mIsCachedForNextSuggestion = parentDicNode->mIsCachedForNextSuggestion; + const int codePoint = + parentDicNode->mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt( + parentDicNode->getNodeCodePointCount()); + mDicNodeProperties.init(&parentDicNode->mDicNodeProperties, codePoint); + mDicNodeState.initByCopy(&parentDicNode->mDicNodeState); + PROF_NODE_COPY(&parentDicNode->mProfiler, mProfiler); } - void initAsChild(const DicNode *const dicNode, const int pos, const int childrenPos, - const int probability, const bool isTerminal, const bool hasChildren, - const bool isBlacklistedOrNotAWord, const uint16_t mergedNodeCodePointCount, - const int *const mergedNodeCodePoints) { - mIsUsed = true; + void initAsChild(const DicNode *const dicNode, const int ptNodePos, + const int childrenPtNodeArrayPos, const int probability, const bool isTerminal, + const bool hasChildren, const bool isBlacklistedOrNotAWord, + const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) { uint16_t newDepth = static_cast<uint16_t>(dicNode->getNodeCodePointCount() + 1); mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion; const uint16_t newLeavingDepth = static_cast<uint16_t>( dicNode->mDicNodeProperties.getLeavingDepth() + mergedNodeCodePointCount); - mDicNodeProperties.init(pos, childrenPos, mergedNodeCodePoints[0], probability, - isTerminal, hasChildren, isBlacklistedOrNotAWord, newDepth, newLeavingDepth); + mDicNodeProperties.init(ptNodePos, childrenPtNodeArrayPos, mergedNodeCodePoints[0], + probability, isTerminal, hasChildren, isBlacklistedOrNotAWord, newDepth, + newLeavingDepth, dicNode->mDicNodeProperties.getPrevWordTerminalPtNodePos()); mDicNodeState.init(&dicNode->mDicNodeState, mergedNodeCodePointCount, mergedNodeCodePoints); PROF_NODE_COPY(&dicNode->mProfiler, mProfiler); } - AK_FORCE_INLINE void remove() { - mIsUsed = false; - if (mReleaseListener) { - mReleaseListener->onReleased(this); - } - } - - bool isUsed() const { - return mIsUsed; - } - bool isRoot() const { return getNodeCodePointCount() == 0; } @@ -209,11 +171,6 @@ class DicNode { mIsCachedForNextSuggestion = true; } - // Used to expand the node in DicNodeUtils - int getNodeTypedCodePoint() const { - return mDicNodeState.mDicNodeStateOutput.getCodePointAt(getNodeCodePointCount()); - } - // Check if the current word and the previous word can be considered as a valid multiple word // suggestion. bool isValidMultipleWordSuggestion() const { @@ -222,21 +179,17 @@ class DicNode { } // Treat suggestion as invalid if the current and the previous word are single character // words. - const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength() - - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1; + const int prevWordLen = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength() + - mDicNodeState.mDicNodeStateOutput.getPrevWordStart() - 1; const int currentWordLen = getNodeCodePointCount(); return (prevWordLen != 1 || currentWordLen != 1); } bool isFirstCharUppercase() const { - const int c = getOutputWordBuf()[0]; + const int c = mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(0); return CharUtils::isAsciiUpper(c); } - bool isFirstWord() const { - return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_DICT_POS; - } - bool isCompletion(const int inputSize) const { return mDicNodeState.mDicNodeStateInput.getInputIndex(0) >= inputSize; } @@ -246,93 +199,72 @@ class DicNode { } // Used to get bigram probability in DicNodeUtils - int getPos() const { - return mDicNodeProperties.getPos(); + int getPtNodePos() const { + return mDicNodeProperties.getPtNodePos(); } // Used to get bigram probability in DicNodeUtils - int getPrevWordPos() const { - return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos(); + int getPrevWordTerminalPtNodePos() const { + return mDicNodeProperties.getPrevWordTerminalPtNodePos(); } // Used in DicNodeUtils - int getChildrenPos() const { - return mDicNodeProperties.getChildrenPos(); + int getChildrenPtNodeArrayPos() const { + return mDicNodeProperties.getChildrenPtNodeArrayPos(); } int getProbability() const { return mDicNodeProperties.getProbability(); } - AK_FORCE_INLINE bool isTerminalWordNode() const { - const bool isTerminalNodes = mDicNodeProperties.isTerminal(); - const int currentNodeDepth = getNodeCodePointCount(); - const int terminalNodeDepth = mDicNodeProperties.getLeavingDepth(); - return isTerminalNodes && currentNodeDepth > 0 && currentNodeDepth == terminalNodeDepth; + AK_FORCE_INLINE bool isTerminalDicNode() const { + const bool isTerminalPtNode = mDicNodeProperties.isTerminal(); + const int currentDicNodeDepth = getNodeCodePointCount(); + const int terminalDicNodeDepth = mDicNodeProperties.getLeavingDepth(); + return isTerminalPtNode && currentDicNodeDepth > 0 + && currentDicNodeDepth == terminalDicNodeDepth; } bool shouldBeFilteredBySafetyNetForBigram() const { const uint16_t currentDepth = getNodeCodePointCount(); - const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength() - - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1; + const int prevWordLen = mDicNodeState.mDicNodeStateOutput.getPrevWordsLength() + - mDicNodeState.mDicNodeStateOutput.getPrevWordStart() - 1; return !(currentDepth > 0 && (currentDepth != 1 || prevWordLen != 1)); } + bool hasMatchedOrProximityCodePoints() const { + // This DicNode does not have matched or proximity code points when all code points have + // been handled as edit corrections or completion so far. + const int editCorrectionCount = mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount(); + const int completionCount = mDicNodeState.mDicNodeStateScoring.getCompletionCount(); + return (editCorrectionCount + completionCount) < getNodeCodePointCount(); + } + bool isTotalInputSizeExceedingLimit() const { - const int prevWordsLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); - const int currentWordDepth = getNodeCodePointCount(); // TODO: 3 can be 2? Needs to be investigated. // TODO: Have a const variable for 3 (or 2) - return prevWordsLen + currentWordDepth > MAX_WORD_LENGTH - 3; - } - - // TODO: This may be defective. Needs to be revised. - bool truncateNode(const DicNode *const topNode, const int inputCommitPoint) { - const int prevWordLenOfTop = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); - int newPrevWordStartIndex = inputCommitPoint; - int charCount = 0; - // Find new word start index - for (int i = 0; i < prevWordLenOfTop; ++i) { - const int c = mDicNodeState.mDicNodeStatePrevWord.getPrevWordCodePointAt(i); - // TODO: Check other separators. - if (c != KEYCODE_SPACE && c != KEYCODE_SINGLE_QUOTE) { - if (charCount == inputCommitPoint) { - newPrevWordStartIndex = i; - break; - } - ++charCount; - } - } - if (!mDicNodeState.mDicNodeStatePrevWord.startsWith( - &topNode->mDicNodeState.mDicNodeStatePrevWord, newPrevWordStartIndex - 1)) { - // Node mismatch. - return false; - } - mDicNodeState.mDicNodeStateInput.truncate(inputCommitPoint); - mDicNodeState.mDicNodeStatePrevWord.truncate(newPrevWordStartIndex); - return true; + return getTotalNodeCodePointCount() > MAX_WORD_LENGTH - 3; } void outputResult(int *dest) const { - const uint16_t prevWordLength = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); - const uint16_t currentDepth = getNodeCodePointCount(); - DicNodeUtils::appendTwoWords(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, - prevWordLength, getOutputWordBuf(), currentDepth, dest); + memmove(dest, getOutputWordBuf(), getTotalNodeCodePointCount() * sizeof(dest[0])); DUMP_WORD_AND_SCORE("OUTPUT"); } // "Total" in this context (and other methods in this class) means the whole suggestion. When // this represents a multi-word suggestion, the referenced PtNode (in mDicNodeState) is only // the one that corresponds to the last word of the suggestion, and all the previous words - // are concatenated together in mPrevWord - which contains a space at the end. + // are concatenated together in mDicNodeStateOutput. int getTotalNodeSpaceCount() const { - if (isFirstWord()) return 0; - return CharUtils::getSpaceCount(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, - mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength()); + if (!hasMultipleWords()) { + return 0; + } + return CharUtils::getSpaceCount(mDicNodeState.mDicNodeStateOutput.getCodePointBuf(), + mDicNodeState.mDicNodeStateOutput.getPrevWordsLength()); } int getSecondWordFirstInputIndex(const ProximityInfoState *const pInfoState) const { - const int inputIndex = mDicNodeState.mDicNodeStatePrevWord.getSecondWordFirstInputIndex(); + const int inputIndex = mDicNodeState.mDicNodeStateOutput.getSecondWordFirstInputIndex(); if (inputIndex == NOT_AN_INDEX) { return NOT_AN_INDEX; } else { @@ -341,7 +273,7 @@ class DicNode { } bool hasMultipleWords() const { - return mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() > 0; + return mDicNodeState.mDicNodeStateOutput.getPrevWordCount() > 0; } int getProximityCorrectionCount() const { @@ -373,13 +305,8 @@ class DicNode { return mDicNodeState.mDicNodeStateScoring.getCompoundDistance(languageWeight); } - // Used to commit input partially - int getPrevWordNodePos() const { - return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos(); - } - AK_FORCE_INLINE const int *getOutputWordBuf() const { - return mDicNodeState.mDicNodeStateOutput.mCodePointsBuf; + return mDicNodeState.mDicNodeStateOutput.getCodePointBuf(); } int getPrevCodePointG(int pointerId) const { @@ -410,7 +337,7 @@ class DicNode { // TODO: Remove once touch path is merged into ProximityInfoState // Note: Returned codepoint may be a digraph codepoint if the node is in a composite glyph. int getNodeCodePoint() const { - const int codePoint = mDicNodeProperties.getNodeCodePoint(); + const int codePoint = mDicNodeProperties.getDicNodeCodePoint(); const DigraphUtils::DigraphCodePointIndex digraphIndex = mDicNodeState.mDicNodeStateScoring.getDigraphIndex(); if (digraphIndex == DigraphUtils::NOT_A_DIGRAPH_INDEX) { @@ -423,8 +350,8 @@ class DicNode { // Utils for cost calculation // //////////////////////////////// AK_FORCE_INLINE bool isSameNodeCodePoint(const DicNode *const dicNode) const { - return mDicNodeProperties.getNodeCodePoint() - == dicNode->mDicNodeProperties.getNodeCodePoint(); + return mDicNodeProperties.getDicNodeCodePoint() + == dicNode->mDicNodeProperties.getDicNodeCodePoint(); } // TODO: remove @@ -440,10 +367,6 @@ class DicNode { return mDicNodeState.mDicNodeStateScoring.getSpatialDistance(); } - float getLanguageDistanceForScoring() const { - return mDicNodeState.mDicNodeStateScoring.getLanguageDistance(); - } - // For space-aware gestures, we store the normalized distance at the char index // that ends the first word of the suggestion. We call this the distance after // first word. @@ -451,22 +374,10 @@ class DicNode { return mDicNodeState.mDicNodeStateScoring.getNormalizedCompoundDistanceAfterFirstWord(); } - float getLanguageDistanceRatePerWordForScoring() const { - const float langDist = getLanguageDistanceForScoring(); - const float totalWordCount = - static_cast<float>(mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() + 1); - return langDist / totalWordCount; - } - float getRawLength() const { return mDicNodeState.mDicNodeStateScoring.getRawLength(); } - bool isLessThanOneErrorForScoring() const { - return mDicNodeState.mDicNodeStateScoring.getEditCorrectionCount() - + mDicNodeState.mDicNodeStateScoring.getProximityCorrectionCount() <= 1; - } - DoubleLetterLevel getDoubleLetterLevel() const { return mDicNodeState.mDicNodeStateScoring.getDoubleLetterLevel(); } @@ -484,8 +395,8 @@ class DicNode { mDicNodeState.mDicNodeStateScoring.advanceDigraphIndex(); } - bool isExactMatch() const { - return mDicNodeState.mDicNodeStateScoring.isExactMatch(); + ErrorTypeUtils::ErrorType getContainedErrorTypes() const { + return mDicNodeState.mDicNodeStateScoring.getContainedErrorTypes(); } bool isBlacklistedOrNotAWord() const { @@ -498,7 +409,7 @@ class DicNode { // Returns code point count including spaces inline uint16_t getTotalNodeCodePointCount() const { - return getNodeCodePointCount() + mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(); + return getNodeCodePointCount() + mDicNodeState.mDicNodeStateOutput.getPrevWordsLength(); } AK_FORCE_INLINE void dump(const char *tag) const { @@ -510,24 +421,10 @@ class DicNode { #endif } - void setReleaseListener(DicNodeReleaseListener *releaseListener) { - mReleaseListener = releaseListener; - } - - AK_FORCE_INLINE bool compare(const DicNode *right) { - if (!isUsed() && !right->isUsed()) { - // Compare pointer values here for stable comparison - return this > right; - } - if (!isUsed()) { - return true; - } - if (!right->isUsed()) { - return false; - } + AK_FORCE_INLINE bool compare(const DicNode *right) const { // Promote exact matches to prevent them from being pruned. - const bool leftExactMatch = isExactMatch(); - const bool rightExactMatch = right->isExactMatch(); + const bool leftExactMatch = ErrorTypeUtils::isExactMatch(getContainedErrorTypes()); + const bool rightExactMatch = ErrorTypeUtils::isExactMatch(right->getContainedErrorTypes()); if (leftExactMatch != rightExactMatch) { return leftExactMatch; } @@ -545,8 +442,9 @@ class DicNode { return depthDiff > 0; } for (int i = 0; i < depth; ++i) { - const int codePoint = mDicNodeState.mDicNodeStateOutput.getCodePointAt(i); - const int rightCodePoint = right->mDicNodeState.mDicNodeStateOutput.getCodePointAt(i); + const int codePoint = mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(i); + const int rightCodePoint = + right->mDicNodeState.mDicNodeStateOutput.getCurrentWordCodePointAt(i); if (codePoint != rightCodePoint) { return rightCodePoint > codePoint; } @@ -560,8 +458,6 @@ class DicNode { DicNodeState mDicNodeState; // TODO: Remove bool mIsCachedForNextSuggestion; - bool mIsUsed; - DicNodeReleaseListener *mReleaseListener; AK_FORCE_INLINE int getTotalInputIndex() const { int index = 0; @@ -574,7 +470,8 @@ class DicNode { // Caveat: Must not be called outside Weighting // This restriction is guaranteed by "friend" AK_FORCE_INLINE void addCost(const float spatialCost, const float languageCost, - const bool doNormalization, const int inputSize, const ErrorType errorType) { + const bool doNormalization, const int inputSize, + const ErrorTypeUtils::ErrorType errorType) { if (DEBUG_GEO_FULL) { LOGI_SHOW_ADD_COST_PROP; } @@ -602,8 +499,8 @@ class DicNode { } AK_FORCE_INLINE void updateInputIndexG(const DicNode_InputStateG *const inputStateG) { - if (mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() == 1 && isFirstLetter()) { - mDicNodeState.mDicNodeStatePrevWord.setSecondWordFirstInputIndex( + if (mDicNodeState.mDicNodeStateOutput.getPrevWordCount() == 1 && isFirstLetter()) { + mDicNodeState.mDicNodeStateOutput.setSecondWordFirstInputIndex( inputStateG->mInputIndex); } mDicNodeState.mDicNodeStateInput.updateInputIndexG(inputStateG->mPointerId, diff --git a/native/jni/src/suggest/core/dicnode/dic_node_pool.h b/native/jni/src/suggest/core/dicnode/dic_node_pool.h new file mode 100644 index 000000000..a660b744f --- /dev/null +++ b/native/jni/src/suggest/core/dicnode/dic_node_pool.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 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_DIC_NODE_POOL_H +#define LATINIME_DIC_NODE_POOL_H + +#include <deque> +#include <unordered_set> +#include <vector> + +#include "defines.h" +#include "suggest/core/dicnode/dic_node.h" + +namespace latinime { + +class DicNodePool { + public: + explicit DicNodePool(const int capacity) : mDicNodes(), mPooledDicNodes() { + reset(capacity); + } + + void reset(const int capacity) { + if (capacity == static_cast<int>(mDicNodes.size()) + && capacity == static_cast<int>(mPooledDicNodes.size())) { + // No need to reset. + return; + } + mDicNodes.resize(capacity); + mDicNodes.shrink_to_fit(); + mPooledDicNodes.clear(); + for (auto &dicNode : mDicNodes) { + mPooledDicNodes.emplace_back(&dicNode); + } + } + + // Get a DicNode instance from the pool. The instance has to be returned by returnInstance(). + DicNode *getInstance() { + if (mPooledDicNodes.empty()) { + return nullptr; + } + DicNode *const dicNode = mPooledDicNodes.back(); + mPooledDicNodes.pop_back(); + return dicNode; + } + + // Return an instance that has been removed from the pool by getInstance() to the pool. The + // instance must not be used after returning without getInstance(). + void placeBackInstance(DicNode *dicNode) { + mPooledDicNodes.emplace_back(dicNode); + } + + void dump() const { + AKLOGI("\n\n\n\n\n==========================="); + std::unordered_set<const DicNode*> usedDicNodes; + for (const auto &dicNode : mDicNodes) { + usedDicNodes.insert(&dicNode); + } + for (const auto &dicNodePtr : mPooledDicNodes) { + usedDicNodes.erase(dicNodePtr); + } + for (const auto &usedDicNodePtr : usedDicNodes) { + usedDicNodePtr->dump("DIC_NODE_POOL: "); + } + AKLOGI("===========================\n\n\n\n\n"); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodePool); + + std::vector<DicNode> mDicNodes; + std::deque<DicNode*> mPooledDicNodes; +}; +} // namespace latinime +#endif // LATINIME_DIC_NODE_POOL_H diff --git a/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h b/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h index 7461f0cc6..7b753f2e4 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h @@ -17,43 +17,36 @@ #ifndef LATINIME_DIC_NODE_PRIORITY_QUEUE_H #define LATINIME_DIC_NODE_PRIORITY_QUEUE_H +#include <algorithm> #include <queue> #include <vector> #include "defines.h" #include "suggest/core/dicnode/dic_node.h" -#include "suggest/core/dicnode/dic_node_release_listener.h" +#include "suggest/core/dicnode/dic_node_pool.h" namespace latinime { -class DicNodePriorityQueue : public DicNodeReleaseListener { +class DicNodePriorityQueue { public: AK_FORCE_INLINE explicit DicNodePriorityQueue(const int capacity) - : mCapacity(capacity), mMaxSize(capacity), mDicNodesBuf(), - mUnusedNodeIndices(), mNextUnusedNodeId(0), mDicNodesQueue() { - mDicNodesBuf.resize(mCapacity + 1); - mUnusedNodeIndices.resize(mCapacity + 1); - clearAndResizeToCapacity(); + : mMaxSize(capacity), mDicNodesQueue(), mDicNodePool(capacity) { + clear(); } // Non virtual inline destructor -- never inherit this class AK_FORCE_INLINE ~DicNodePriorityQueue() {} - int getSize() const { + AK_FORCE_INLINE int getSize() const { return static_cast<int>(mDicNodesQueue.size()); } - int getMaxSize() const { + AK_FORCE_INLINE int getMaxSize() const { return mMaxSize; } AK_FORCE_INLINE void setMaxSize(const int maxSize) { - ASSERT(maxSize <= mCapacity); - mMaxSize = min(maxSize, mCapacity); - } - - AK_FORCE_INLINE void clearAndResizeToCapacity() { - clearAndResize(mCapacity); + mMaxSize = maxSize; } AK_FORCE_INLINE void clear() { @@ -61,25 +54,32 @@ class DicNodePriorityQueue : public DicNodeReleaseListener { } AK_FORCE_INLINE void clearAndResize(const int maxSize) { - ASSERT(maxSize <= mCapacity); + mMaxSize = maxSize; while (!mDicNodesQueue.empty()) { mDicNodesQueue.pop(); } - setMaxSize(maxSize); - for (int i = 0; i < mCapacity + 1; ++i) { - mDicNodesBuf[i].remove(); - mDicNodesBuf[i].setReleaseListener(this); - mUnusedNodeIndices[i] = i == mCapacity ? NOT_A_NODE_ID : static_cast<int>(i) + 1; - } - mNextUnusedNodeId = 0; + mDicNodePool.reset(mMaxSize + 1); } - // Copy - AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode) { - return copyPush(dicNode, mMaxSize); + AK_FORCE_INLINE void copyPush(const DicNode *const dicNode) { + DicNode *const pooledDicNode = newDicNode(dicNode); + if (!pooledDicNode) { + return; + } + if (getSize() < mMaxSize) { + mDicNodesQueue.push(pooledDicNode); + return; + } + if (betterThanWorstDicNode(pooledDicNode)) { + mDicNodePool.placeBackInstance(mDicNodesQueue.top()); + mDicNodesQueue.pop(); + mDicNodesQueue.push(pooledDicNode); + return; + } + mDicNodePool.placeBackInstance(pooledDicNode); } - AK_FORCE_INLINE void copyPop(DicNode *dest) { + AK_FORCE_INLINE void copyPop(DicNode *const dest) { if (mDicNodesQueue.empty()) { ASSERT(false); return; @@ -88,62 +88,34 @@ class DicNodePriorityQueue : public DicNodeReleaseListener { if (dest) { DicNodeUtils::initByCopy(node, dest); } - node->remove(); + mDicNodePool.placeBackInstance(node); mDicNodesQueue.pop(); } - void onReleased(DicNode *dicNode) { - const int index = static_cast<int>(dicNode - &mDicNodesBuf[0]); - if (mUnusedNodeIndices[index] != NOT_A_NODE_ID) { - // it's already released - return; - } - mUnusedNodeIndices[index] = mNextUnusedNodeId; - mNextUnusedNodeId = index; - ASSERT(index >= 0 && index < (mCapacity + 1)); - } - - AK_FORCE_INLINE void dump() const { - AKLOGI("\n\n\n\n\n==========================="); - for (int i = 0; i < mCapacity + 1; ++i) { - if (mDicNodesBuf[i].isUsed()) { - mDicNodesBuf[i].dump("QUEUE: "); - } - } - AKLOGI("===========================\n\n\n\n\n"); + AK_FORCE_INLINE void dump() { + mDicNodePool.dump(); } private: DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodePriorityQueue); - static const int NOT_A_NODE_ID = -1; - AK_FORCE_INLINE static bool compareDicNode(DicNode *left, DicNode *right) { + AK_FORCE_INLINE static bool compareDicNode(const DicNode *const left, + const DicNode *const right) { return left->compare(right); } struct DicNodeComparator { - bool operator ()(DicNode *left, DicNode *right) { + bool operator ()(const DicNode *left, const DicNode *right) const { return compareDicNode(left, right); } }; typedef std::priority_queue<DicNode *, std::vector<DicNode *>, DicNodeComparator> DicNodesQueue; - const int mCapacity; int mMaxSize; - std::vector<DicNode> mDicNodesBuf; // of each element of mDicNodesBuf respectively - std::vector<int> mUnusedNodeIndices; - int mNextUnusedNodeId; DicNodesQueue mDicNodesQueue; + DicNodePool mDicNodePool; - inline bool isFull(const int maxSize) const { - return getSize() >= maxSize; - } - - AK_FORCE_INLINE void pop() { - copyPop(0); - } - - AK_FORCE_INLINE bool betterThanWorstDicNode(DicNode *dicNode) const { + AK_FORCE_INLINE bool betterThanWorstDicNode(const DicNode *const dicNode) const { DicNode *worstNode = mDicNodesQueue.top(); if (!worstNode) { return true; @@ -151,61 +123,13 @@ class DicNodePriorityQueue : public DicNodeReleaseListener { return compareDicNode(dicNode, worstNode); } - AK_FORCE_INLINE DicNode *searchEmptyDicNode() { - if (mCapacity == 0) { - return 0; - } - if (mNextUnusedNodeId == NOT_A_NODE_ID) { - AKLOGI("No unused node found."); - for (int i = 0; i < mCapacity + 1; ++i) { - AKLOGI("Dump node availability, %d, %d, %d", - i, mDicNodesBuf[i].isUsed(), mUnusedNodeIndices[i]); - } - ASSERT(false); - return 0; - } - DicNode *dicNode = &mDicNodesBuf[mNextUnusedNodeId]; - markNodeAsUsed(dicNode); - return dicNode; - } - - AK_FORCE_INLINE void markNodeAsUsed(DicNode *dicNode) { - const int index = static_cast<int>(dicNode - &mDicNodesBuf[0]); - mNextUnusedNodeId = mUnusedNodeIndices[index]; - mUnusedNodeIndices[index] = NOT_A_NODE_ID; - ASSERT(index >= 0 && index < (mCapacity + 1)); - } - - AK_FORCE_INLINE DicNode *pushPoolNodeWithMaxSize(DicNode *dicNode, const int maxSize) { - if (!dicNode) { - return 0; - } - if (!isFull(maxSize)) { - mDicNodesQueue.push(dicNode); - return dicNode; - } - if (betterThanWorstDicNode(dicNode)) { - pop(); - mDicNodesQueue.push(dicNode); - return dicNode; - } - dicNode->remove(); - return 0; - } - - // Copy - AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode, const int maxSize) { - return pushPoolNodeWithMaxSize(newDicNode(dicNode), maxSize); - } - - AK_FORCE_INLINE DicNode *newDicNode(DicNode *dicNode) { - DicNode *newNode = searchEmptyDicNode(); + AK_FORCE_INLINE DicNode *newDicNode(const DicNode *const dicNode) { + DicNode *newNode = mDicNodePool.getInstance(); if (newNode) { DicNodeUtils::initByCopy(dicNode, newNode); } return newNode; } - }; } // namespace latinime #endif // LATINIME_DIC_NODE_PRIORITY_QUEUE_H diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp index ec65114c7..2d02a7d9c 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp @@ -16,13 +16,10 @@ #include "suggest/core/dicnode/dic_node_utils.h" -#include <cstring> - #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_vector.h" #include "suggest/core/dictionary/multi_bigram_map.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" -#include "utils/char_utils.h" namespace latinime { @@ -32,19 +29,20 @@ namespace latinime { /* static */ void DicNodeUtils::initAsRoot( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const int prevWordNodePos, DicNode *const newRootNode) { - newRootNode->initAsRoot(dictionaryStructurePolicy->getRootPosition(), prevWordNodePos); + const int prevWordPtNodePos, DicNode *const newRootDicNode) { + newRootDicNode->initAsRoot(dictionaryStructurePolicy->getRootPosition(), prevWordPtNodePos); } /*static */ void DicNodeUtils::initAsRootWithPreviousWord( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - DicNode *const prevWordLastNode, DicNode *const newRootNode) { - newRootNode->initAsRootWithPreviousWord( - prevWordLastNode, dictionaryStructurePolicy->getRootPosition()); + const DicNode *const prevWordLastDicNode, DicNode *const newRootDicNode) { + newRootDicNode->initAsRootWithPreviousWord( + prevWordLastDicNode, dictionaryStructurePolicy->getRootPosition()); } -/* static */ void DicNodeUtils::initByCopy(DicNode *srcNode, DicNode *destNode) { - destNode->initByCopy(srcNode); +/* static */ void DicNodeUtils::initByCopy(const DicNode *const srcDicNode, + DicNode *const destDicNode) { + destDicNode->initByCopy(srcDicNode); } /////////////////////////////////// @@ -52,14 +50,14 @@ namespace latinime { /////////////////////////////////// /* static */ void DicNodeUtils::getAllChildDicNodes(DicNode *dicNode, const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - DicNodeVector *childDicNodes) { + DicNodeVector *const childDicNodes) { if (dicNode->isTotalInputSizeExceedingLimit()) { return; } if (!dicNode->isLeavingNode()) { childDicNodes->pushPassingChild(dicNode); } else { - dictionaryStructurePolicy->createAndGetAllChildNodes(dicNode, childDicNodes); + dictionaryStructurePolicy->createAndGetAllChildDicNodes(dicNode, childDicNodes); } } @@ -71,11 +69,11 @@ namespace latinime { */ /* static */ float DicNodeUtils::getBigramNodeImprobability( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const DicNode *const node, MultiBigramMap *multiBigramMap) { - if (node->hasMultipleWords() && !node->isValidMultipleWordSuggestion()) { + const DicNode *const dicNode, MultiBigramMap *const multiBigramMap) { + if (dicNode->hasMultipleWords() && !dicNode->isValidMultipleWordSuggestion()) { return static_cast<float>(MAX_VALUE_FOR_WEIGHTING); } - const int probability = getBigramNodeProbability(dictionaryStructurePolicy, node, + const int probability = getBigramNodeProbability(dictionaryStructurePolicy, dicNode, multiBigramMap); // TODO: This equation to calculate the improbability looks unreasonable. Investigate this. const float cost = static_cast<float>(MAX_PROBABILITY - probability) @@ -85,52 +83,22 @@ namespace latinime { /* static */ int DicNodeUtils::getBigramNodeProbability( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const DicNode *const node, MultiBigramMap *multiBigramMap) { - const int unigramProbability = node->getProbability(); - const int wordPos = node->getPos(); - const int prevWordPos = node->getPrevWordPos(); - if (NOT_A_DICT_POS == wordPos || NOT_A_DICT_POS == prevWordPos) { + const DicNode *const dicNode, MultiBigramMap *const multiBigramMap) { + const int unigramProbability = dicNode->getProbability(); + const int ptNodePos = dicNode->getPtNodePos(); + const int prevWordTerminalPtNodePos = dicNode->getPrevWordTerminalPtNodePos(); + if (NOT_A_DICT_POS == ptNodePos || NOT_A_DICT_POS == prevWordTerminalPtNodePos) { // Note: Normally wordPos comes from the dictionary and should never equal // NOT_A_VALID_WORD_POS. return dictionaryStructurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); } if (multiBigramMap) { - return multiBigramMap->getBigramProbability(dictionaryStructurePolicy, prevWordPos, - wordPos, unigramProbability); + return multiBigramMap->getBigramProbability(dictionaryStructurePolicy, + prevWordTerminalPtNodePos, ptNodePos, unigramProbability); } return dictionaryStructurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY); } -//////////////// -// Char utils // -//////////////// - -// TODO: Move to char_utils? -/* static */ int DicNodeUtils::appendTwoWords(const int *const src0, const int16_t length0, - const int *const src1, const int16_t length1, int *dest) { - int actualLength0 = 0; - for (int i = 0; i < length0; ++i) { - if (src0[i] == 0) { - break; - } - actualLength0 = i + 1; - } - actualLength0 = min(actualLength0, MAX_WORD_LENGTH); - memcpy(dest, src0, actualLength0 * sizeof(dest[0])); - if (!src1 || length1 == 0) { - return actualLength0; - } - int actualLength1 = 0; - for (int i = 0; i < length1; ++i) { - if (src1[i] == 0) { - break; - } - actualLength1 = i + 1; - } - actualLength1 = min(actualLength1, MAX_WORD_LENGTH - actualLength0); - memcpy(&dest[actualLength0], src1, actualLength1 * sizeof(dest[0])); - return actualLength0 + actualLength1; -} } // namespace latinime diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.h b/native/jni/src/suggest/core/dicnode/dic_node_utils.h index 3fb351a61..4c0f1f15d 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_utils.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.h @@ -17,8 +17,6 @@ #ifndef LATINIME_DIC_NODE_UTILS_H #define LATINIME_DIC_NODE_UTILS_H -#include <stdint.h> - #include "defines.h" namespace latinime { @@ -30,21 +28,19 @@ class MultiBigramMap; class DicNodeUtils { public: - static int appendTwoWords(const int *src0, const int16_t length0, const int *src1, - const int16_t length1, int *dest); static void initAsRoot( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const int prevWordNodePos, DicNode *newRootNode); + const int prevWordPtNodePos, DicNode *const newRootDicNode); static void initAsRootWithPreviousWord( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - DicNode *prevWordLastNode, DicNode *newRootNode); - static void initByCopy(DicNode *srcNode, DicNode *destNode); + const DicNode *const prevWordLastDicNode, DicNode *const newRootDicNode); + static void initByCopy(const DicNode *const srcDicNode, DicNode *const destDicNode); static void getAllChildDicNodes(DicNode *dicNode, const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, DicNodeVector *childDicNodes); static float getBigramNodeImprobability( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const DicNode *const node, MultiBigramMap *const multiBigramMap); + const DicNode *const dicNode, MultiBigramMap *const multiBigramMap); private: DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodeUtils); @@ -53,7 +49,7 @@ class DicNodeUtils { static int getBigramNodeProbability( const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy, - const DicNode *const node, MultiBigramMap *multiBigramMap); + const DicNode *const dicNode, MultiBigramMap *const multiBigramMap); }; } // namespace latinime #endif // LATINIME_DIC_NODE_UTILS_H diff --git a/native/jni/src/suggest/core/dicnode/dic_node_vector.h b/native/jni/src/suggest/core/dicnode/dic_node_vector.h index 42addae8d..cb28e57d8 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_vector.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_vector.h @@ -32,10 +32,10 @@ class DicNodeVector { #else static const int DEFAULT_NODES_SIZE_FOR_OPTIMIZATION = 60; #endif - AK_FORCE_INLINE DicNodeVector() : mDicNodes(0), mLock(false), mEmptyNode() {} + AK_FORCE_INLINE DicNodeVector() : mDicNodes(), mLock(false) {} // Specify the capacity of the vector - AK_FORCE_INLINE DicNodeVector(const int size) : mDicNodes(0), mLock(false), mEmptyNode() { + AK_FORCE_INLINE DicNodeVector(const int size) : mDicNodes(), mLock(false) { mDicNodes.reserve(size); } @@ -52,24 +52,20 @@ class DicNodeVector { return static_cast<int>(mDicNodes.size()); } - bool exceeds(const size_t limit) const { - return mDicNodes.size() >= limit; - } - void pushPassingChild(DicNode *dicNode) { ASSERT(!mLock); - mDicNodes.push_back(mEmptyNode); + mDicNodes.emplace_back(); mDicNodes.back().initAsPassingChild(dicNode); } - void pushLeavingChild(const DicNode *const dicNode, const int pos, const int childrenPos, - const int probability, const bool isTerminal, const bool hasChildren, - const bool isBlacklistedOrNotAWord, const uint16_t mergedNodeCodePointCount, - const int *const mergedNodeCodePoints) { + void pushLeavingChild(const DicNode *const dicNode, const int ptNodePos, + const int childrenPtNodeArrayPos, const int probability, const bool isTerminal, + const bool hasChildren, const bool isBlacklistedOrNotAWord, + const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) { ASSERT(!mLock); - mDicNodes.push_back(mEmptyNode); - mDicNodes.back().initAsChild(dicNode, pos, childrenPos, probability, isTerminal, - hasChildren, isBlacklistedOrNotAWord, mergedNodeCodePointCount, + mDicNodes.emplace_back(); + mDicNodes.back().initAsChild(dicNode, ptNodePos, childrenPtNodeArrayPos, probability, + isTerminal, hasChildren, isBlacklistedOrNotAWord, mergedNodeCodePointCount, mergedNodeCodePoints); } @@ -80,14 +76,13 @@ class DicNodeVector { DicNode *front() { ASSERT(1 <= static_cast<int>(mDicNodes.size())); - return &mDicNodes[0]; + return &mDicNodes.front(); } private: DISALLOW_COPY_AND_ASSIGN(DicNodeVector); std::vector<DicNode> mDicNodes; bool mLock; - DicNode mEmptyNode; }; } // namespace latinime #endif // LATINIME_DIC_NODE_VECTOR_H diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp index b6be47e90..ef4a6b5d8 100644 --- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp +++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp @@ -28,37 +28,4 @@ const int DicNodesCache::LARGE_PRIORITY_QUEUE_CAPACITY = 310; // Capacity for reducing memory footprint. const int DicNodesCache::SMALL_PRIORITY_QUEUE_CAPACITY = 100; -/** - * Truncates all of the dicNodes so that they start at the given commit point. - * Only called for multi-word typing input. - */ -DicNode *DicNodesCache::setCommitPoint(int commitPoint) { - std::list<DicNode> dicNodesList; - while (mCachedDicNodesForContinuousSuggestion->getSize() > 0) { - DicNode dicNode; - mCachedDicNodesForContinuousSuggestion->copyPop(&dicNode); - dicNodesList.push_front(dicNode); - } - - // Get the starting words of the top scoring dicNode (last dicNode popped from priority queue) - // up to the commit point. These words have already been committed to the text view. - DicNode *topDicNode = &dicNodesList.front(); - DicNode topDicNodeCopy; - DicNodeUtils::initByCopy(topDicNode, &topDicNodeCopy); - - // Keep only those dicNodes that match the same starting words. - std::list<DicNode>::iterator iter; - for (iter = dicNodesList.begin(); iter != dicNodesList.end(); iter++) { - DicNode *dicNode = &*iter; - if (dicNode->truncateNode(&topDicNodeCopy, commitPoint)) { - mCachedDicNodesForContinuousSuggestion->copyPush(dicNode); - } else { - // Top dicNode should be reprocessed. - ASSERT(dicNode != topDicNode); - DicNode::managedDelete(dicNode); - } - } - mInputIndex -= commitPoint; - return topDicNode; -} } // namespace latinime diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h index 8493b6a8b..fb76c731f 100644 --- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h +++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h @@ -17,7 +17,7 @@ #ifndef LATINIME_DIC_NODES_CACHE_H #define LATINIME_DIC_NODES_CACHE_H -#include <stdint.h> +#include <algorithm> #include "defines.h" #include "suggest/core/dicnode/dic_node_priority_queue.h" @@ -48,15 +48,14 @@ class DicNodesCache { AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) { mInputIndex = 0; mLastCachedInputIndex = 0; - // We want to use the max capacity for the current active dic node queue. - mActiveDicNodes->clearAndResizeToCapacity(); - // nextActiveSize is used to limit the next iteration's active dic node size. - const int nextActiveSizeFittingToTheCapacity = min(nextActiveSize, getCacheCapacity()); + // The size of current active DicNode queue doesn't have to be changed. + mActiveDicNodes->clear(); + // nextActiveSize is used to limit the next iteration's active DicNode size. + const int nextActiveSizeFittingToTheCapacity = std::min(nextActiveSize, getCacheCapacity()); mNextActiveDicNodes->clearAndResize(nextActiveSizeFittingToTheCapacity); mTerminalDicNodes->clearAndResize(terminalSize); - // We want to use the max capacity for the cached dic nodes that will be used for the - // continuous suggestion. - mCachedDicNodesForContinuousSuggestion->clearAndResizeToCapacity(); + // The size of cached DicNode queue doesn't have to be changed. + mCachedDicNodesForContinuousSuggestion->clear(); } AK_FORCE_INLINE void continueSearch() { @@ -75,8 +74,6 @@ class DicNodesCache { moveNodesAndReturnReusableEmptyQueue(mNextActiveDicNodes, &mActiveDicNodes); } - DicNode *setCommitPoint(int commitPoint); - int activeSize() const { return mActiveDicNodes->getSize(); } int terminalSize() const { return mTerminalDicNodes->getSize(); } bool isLookAheadCorrectionInputIndex(const int inputIndex) const { @@ -96,19 +93,12 @@ class DicNodesCache { mActiveDicNodes->copyPush(dicNode); } - AK_FORCE_INLINE bool copyPushContinue(DicNode *dicNode) { - return mCachedDicNodesForContinuousSuggestion->copyPush(dicNode); + AK_FORCE_INLINE void copyPushContinue(DicNode *dicNode) { + mCachedDicNodesForContinuousSuggestion->copyPush(dicNode); } AK_FORCE_INLINE void copyPushNextActive(DicNode *dicNode) { - DicNode *pushedDicNode = mNextActiveDicNodes->copyPush(dicNode); - if (!pushedDicNode) { - if (dicNode->isCached()) { - dicNode->remove(); - } - // We simply drop any dic node that was not cached, ignoring the slim chance - // that one of its children represents what the user really wanted. - } + mNextActiveDicNodes->copyPush(dicNode); } void popTerminal(DicNode *dest) { diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h index 9e0f62ceb..11f8c2905 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h @@ -17,80 +17,97 @@ #ifndef LATINIME_DIC_NODE_PROPERTIES_H #define LATINIME_DIC_NODE_PROPERTIES_H -#include <stdint.h> +#include <cstdint> #include "defines.h" namespace latinime { /** - * Node for traversing the lexicon trie. + * PtNode information related to the DicNode from the lexicon trie. */ -// TODO: Introduce a dictionary node class which has attribute members required to understand the -// dictionary structure. class DicNodeProperties { public: AK_FORCE_INLINE DicNodeProperties() - : mPos(0), mChildrenPos(0), mProbability(0), mNodeCodePoint(0), mIsTerminal(false), - mHasChildren(false), mIsBlacklistedOrNotAWord(false), mDepth(0), mLeavingDepth(0) {} + : mPtNodePos(NOT_A_DICT_POS), mChildrenPtNodeArrayPos(NOT_A_DICT_POS), + mProbability(NOT_A_PROBABILITY), mDicNodeCodePoint(NOT_A_CODE_POINT), + mIsTerminal(false), mHasChildrenPtNodes(false), + mIsBlacklistedOrNotAWord(false), mDepth(0), mLeavingDepth(0), + mPrevWordTerminalPtNodePos(NOT_A_DICT_POS) {} - virtual ~DicNodeProperties() {} + ~DicNodeProperties() {} // Should be called only once per DicNode is initialized. void init(const int pos, const int childrenPos, const int nodeCodePoint, const int probability, const bool isTerminal, const bool hasChildren, const bool isBlacklistedOrNotAWord, - const uint16_t depth, const uint16_t leavingDepth) { - mPos = pos; - mChildrenPos = childrenPos; - mNodeCodePoint = nodeCodePoint; + const uint16_t depth, const uint16_t leavingDepth, const int prevWordNodePos) { + mPtNodePos = pos; + mChildrenPtNodeArrayPos = childrenPos; + mDicNodeCodePoint = nodeCodePoint; mProbability = probability; mIsTerminal = isTerminal; - mHasChildren = hasChildren; + mHasChildrenPtNodes = hasChildren; mIsBlacklistedOrNotAWord = isBlacklistedOrNotAWord; mDepth = depth; mLeavingDepth = leavingDepth; + mPrevWordTerminalPtNodePos = prevWordNodePos; } - // Init for copy - void init(const DicNodeProperties *const nodeProp) { - mPos = nodeProp->mPos; - mChildrenPos = nodeProp->mChildrenPos; - mNodeCodePoint = nodeProp->mNodeCodePoint; - mProbability = nodeProp->mProbability; - mIsTerminal = nodeProp->mIsTerminal; - mHasChildren = nodeProp->mHasChildren; - mIsBlacklistedOrNotAWord = nodeProp->mIsBlacklistedOrNotAWord; - mDepth = nodeProp->mDepth; - mLeavingDepth = nodeProp->mLeavingDepth; + // Init for root with prevWordPtNodePos which is used for bigram + void init(const int rootPtNodeArrayPos, const int prevWordNodePos) { + mPtNodePos = NOT_A_DICT_POS; + mChildrenPtNodeArrayPos = rootPtNodeArrayPos; + mDicNodeCodePoint = NOT_A_CODE_POINT; + mProbability = NOT_A_PROBABILITY; + mIsTerminal = false; + mHasChildrenPtNodes = true; + mIsBlacklistedOrNotAWord = false; + mDepth = 0; + mLeavingDepth = 0; + mPrevWordTerminalPtNodePos = prevWordNodePos; + } + + void initByCopy(const DicNodeProperties *const dicNodeProp) { + mPtNodePos = dicNodeProp->mPtNodePos; + mChildrenPtNodeArrayPos = dicNodeProp->mChildrenPtNodeArrayPos; + mDicNodeCodePoint = dicNodeProp->mDicNodeCodePoint; + mProbability = dicNodeProp->mProbability; + mIsTerminal = dicNodeProp->mIsTerminal; + mHasChildrenPtNodes = dicNodeProp->mHasChildrenPtNodes; + mIsBlacklistedOrNotAWord = dicNodeProp->mIsBlacklistedOrNotAWord; + mDepth = dicNodeProp->mDepth; + mLeavingDepth = dicNodeProp->mLeavingDepth; + mPrevWordTerminalPtNodePos = dicNodeProp->mPrevWordTerminalPtNodePos; } // Init as passing child - void init(const DicNodeProperties *const nodeProp, const int codePoint) { - mPos = nodeProp->mPos; - mChildrenPos = nodeProp->mChildrenPos; - mNodeCodePoint = codePoint; // Overwrite the node char of a passing child - mProbability = nodeProp->mProbability; - mIsTerminal = nodeProp->mIsTerminal; - mHasChildren = nodeProp->mHasChildren; - mIsBlacklistedOrNotAWord = nodeProp->mIsBlacklistedOrNotAWord; - mDepth = nodeProp->mDepth + 1; // Increment the depth of a passing child - mLeavingDepth = nodeProp->mLeavingDepth; + void init(const DicNodeProperties *const dicNodeProp, const int codePoint) { + mPtNodePos = dicNodeProp->mPtNodePos; + mChildrenPtNodeArrayPos = dicNodeProp->mChildrenPtNodeArrayPos; + mDicNodeCodePoint = codePoint; // Overwrite the node char of a passing child + mProbability = dicNodeProp->mProbability; + mIsTerminal = dicNodeProp->mIsTerminal; + mHasChildrenPtNodes = dicNodeProp->mHasChildrenPtNodes; + mIsBlacklistedOrNotAWord = dicNodeProp->mIsBlacklistedOrNotAWord; + mDepth = dicNodeProp->mDepth + 1; // Increment the depth of a passing child + mLeavingDepth = dicNodeProp->mLeavingDepth; + mPrevWordTerminalPtNodePos = dicNodeProp->mPrevWordTerminalPtNodePos; } - int getPos() const { - return mPos; + int getPtNodePos() const { + return mPtNodePos; } - int getChildrenPos() const { - return mChildrenPos; + int getChildrenPtNodeArrayPos() const { + return mChildrenPtNodeArrayPos; } int getProbability() const { return mProbability; } - int getNodeCodePoint() const { - return mNodeCodePoint; + int getDicNodeCodePoint() const { + return mDicNodeCodePoint; } uint16_t getDepth() const { @@ -107,26 +124,31 @@ class DicNodeProperties { } bool hasChildren() const { - return mHasChildren || mDepth != mLeavingDepth; + return mHasChildrenPtNodes || mDepth != mLeavingDepth; } bool isBlacklistedOrNotAWord() const { return mIsBlacklistedOrNotAWord; } + int getPrevWordTerminalPtNodePos() const { + return mPrevWordTerminalPtNodePos; + } + private: // Caution!!! // Use a default copy constructor and an assign operator because shallow copies are ok // for this class - int mPos; - int mChildrenPos; + int mPtNodePos; + int mChildrenPtNodeArrayPos; int mProbability; - int mNodeCodePoint; + int mDicNodeCodePoint; bool mIsTerminal; - bool mHasChildren; + bool mHasChildrenPtNodes; bool mIsBlacklistedOrNotAWord; uint16_t mDepth; uint16_t mLeavingDepth; + int mPrevWordTerminalPtNodePos; }; } // namespace latinime #endif // LATINIME_DIC_NODE_PROPERTIES_H diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h index b0fddb724..badb1f5f2 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state.h @@ -20,7 +20,6 @@ #include "defines.h" #include "suggest/core/dicnode/internal/dic_node_state_input.h" #include "suggest/core/dicnode/internal/dic_node_state_output.h" -#include "suggest/core/dicnode/internal/dic_node_state_prevword.h" #include "suggest/core/dicnode/internal/dic_node_state_scoring.h" namespace latinime { @@ -29,44 +28,53 @@ class DicNodeState { public: DicNodeStateInput mDicNodeStateInput; DicNodeStateOutput mDicNodeStateOutput; - DicNodeStatePrevWord mDicNodeStatePrevWord; DicNodeStateScoring mDicNodeStateScoring; AK_FORCE_INLINE DicNodeState() - : mDicNodeStateInput(), mDicNodeStateOutput(), mDicNodeStatePrevWord(), - mDicNodeStateScoring() { + : mDicNodeStateInput(), mDicNodeStateOutput(), mDicNodeStateScoring() {} + + ~DicNodeState() {} + + DicNodeState &operator=(const DicNodeState& src) { + initByCopy(&src); + return *this; } - virtual ~DicNodeState() {} + DicNodeState(const DicNodeState& src) + : mDicNodeStateInput(), mDicNodeStateOutput(), mDicNodeStateScoring() { + initByCopy(&src); + } - // Init with prevWordPos - void init(const int prevWordPos) { + // Init for root + void init() { mDicNodeStateInput.init(); mDicNodeStateOutput.init(); - mDicNodeStatePrevWord.init(prevWordPos); mDicNodeStateScoring.init(); } + // Init with previous word. + void initAsRootWithPreviousWord(const DicNodeState *prevWordDicNodeState, + const int prevWordCodePointCount) { + mDicNodeStateOutput.init(&prevWordDicNodeState->mDicNodeStateOutput); + mDicNodeStateInput.init( + &prevWordDicNodeState->mDicNodeStateInput, true /* resetTerminalDiffCost */); + mDicNodeStateScoring.initByCopy(&prevWordDicNodeState->mDicNodeStateScoring); + } + // Init by copy - AK_FORCE_INLINE void init(const DicNodeState *const src) { - mDicNodeStateInput.init(&src->mDicNodeStateInput); - mDicNodeStateOutput.init(&src->mDicNodeStateOutput); - mDicNodeStatePrevWord.init(&src->mDicNodeStatePrevWord); - mDicNodeStateScoring.init(&src->mDicNodeStateScoring); + AK_FORCE_INLINE void initByCopy(const DicNodeState *const src) { + mDicNodeStateInput.initByCopy(&src->mDicNodeStateInput); + mDicNodeStateOutput.initByCopy(&src->mDicNodeStateOutput); + mDicNodeStateScoring.initByCopy(&src->mDicNodeStateScoring); } // Init by copy and adding merged node code points. void init(const DicNodeState *const src, const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) { - init(src); + initByCopy(src); mDicNodeStateOutput.addMergedNodeCodePoints( mergedNodeCodePointCount, mergedNodeCodePoints); } - - private: - // Caution!!! - // Use a default copy constructor and an assign operator because shallow copies are ok - // for this class }; } // namespace latinime #endif // LATINIME_DIC_NODE_STATE_H diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h index bbd9435b5..50a37ba3e 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_input.h @@ -25,12 +25,7 @@ namespace latinime { class DicNodeStateInput { public: DicNodeStateInput() {} - virtual ~DicNodeStateInput() {} - - // TODO: Merge into DicNodeStatePrevWord::truncate - void truncate(const int commitPoint) { - mInputIndex[0] -= commitPoint; - } + ~DicNodeStateInput() {} void init() { for (int i = 0; i < MAX_POINTER_COUNT_G; i++) { @@ -58,7 +53,7 @@ class DicNodeStateInput { mTerminalDiffCost[pointerId] = terminalDiffCost; } - void init(const DicNodeStateInput *const src) { + void initByCopy(const DicNodeStateInput *const src) { init(src, false); } @@ -89,9 +84,8 @@ class DicNodeStateInput { } private: - // Caution!!! - // Use a default copy constructor and an assign operator because shallow copies are ok - // for this class + DISALLOW_COPY_AND_ASSIGN(DicNodeStateInput); + int mInputIndex[MAX_POINTER_COUNT_G]; int mPrevCodePoint[MAX_POINTER_COUNT_G]; float mTerminalDiffCost[MAX_POINTER_COUNT_G]; diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h index 74eb5dfe7..69a886f55 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h @@ -17,63 +17,135 @@ #ifndef LATINIME_DIC_NODE_STATE_OUTPUT_H #define LATINIME_DIC_NODE_STATE_OUTPUT_H -#include <cstring> // for memcpy() -#include <stdint.h> +#include <algorithm> +#include <cstdint> +#include <cstring> // for memmove() #include "defines.h" namespace latinime { +// Class to have information to be output. This can contain previous words when the suggestion +// is a multi-word suggestion. class DicNodeStateOutput { public: - DicNodeStateOutput() : mOutputtedCodePointCount(0) { - init(); - } + DicNodeStateOutput() + : mOutputtedCodePointCount(0), mCurrentWordStart(0), mPrevWordCount(0), + mPrevWordsLength(0), mPrevWordStart(0), mSecondWordFirstInputIndex(NOT_AN_INDEX) {} - virtual ~DicNodeStateOutput() {} + ~DicNodeStateOutput() {} + // Init for root void init() { mOutputtedCodePointCount = 0; - mCodePointsBuf[0] = 0; + mCurrentWordStart = 0; + mOutputCodePoints[0] = 0; + mPrevWordCount = 0; + mPrevWordsLength = 0; + mPrevWordStart = 0; + mSecondWordFirstInputIndex = NOT_AN_INDEX; } + // Init for next word. void init(const DicNodeStateOutput *const stateOutput) { - memcpy(mCodePointsBuf, stateOutput->mCodePointsBuf, - stateOutput->mOutputtedCodePointCount * sizeof(mCodePointsBuf[0])); + mOutputtedCodePointCount = stateOutput->mOutputtedCodePointCount + 1; + memmove(mOutputCodePoints, stateOutput->mOutputCodePoints, + stateOutput->mOutputtedCodePointCount * sizeof(mOutputCodePoints[0])); + mOutputCodePoints[stateOutput->mOutputtedCodePointCount] = KEYCODE_SPACE; + mCurrentWordStart = stateOutput->mOutputtedCodePointCount + 1; + mPrevWordCount = std::min(static_cast<int16_t>(stateOutput->mPrevWordCount + 1), + static_cast<int16_t>(MAX_RESULTS)); + mPrevWordsLength = stateOutput->mOutputtedCodePointCount + 1; + mPrevWordStart = stateOutput->mCurrentWordStart; + mSecondWordFirstInputIndex = stateOutput->mSecondWordFirstInputIndex; + } + + void initByCopy(const DicNodeStateOutput *const stateOutput) { + memmove(mOutputCodePoints, stateOutput->mOutputCodePoints, + stateOutput->mOutputtedCodePointCount * sizeof(mOutputCodePoints[0])); mOutputtedCodePointCount = stateOutput->mOutputtedCodePointCount; if (mOutputtedCodePointCount < MAX_WORD_LENGTH) { - mCodePointsBuf[mOutputtedCodePointCount] = 0; + mOutputCodePoints[mOutputtedCodePointCount] = 0; } + mCurrentWordStart = stateOutput->mCurrentWordStart; + mPrevWordCount = stateOutput->mPrevWordCount; + mPrevWordsLength = stateOutput->mPrevWordsLength; + mPrevWordStart = stateOutput->mPrevWordStart; + mSecondWordFirstInputIndex = stateOutput->mSecondWordFirstInputIndex; } void addMergedNodeCodePoints(const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) { if (mergedNodeCodePoints) { - const int additionalCodePointCount = min(static_cast<int>(mergedNodeCodePointCount), + const int additionalCodePointCount = std::min( + static_cast<int>(mergedNodeCodePointCount), MAX_WORD_LENGTH - mOutputtedCodePointCount); - memcpy(&mCodePointsBuf[mOutputtedCodePointCount], mergedNodeCodePoints, - additionalCodePointCount * sizeof(mCodePointsBuf[0])); + memmove(&mOutputCodePoints[mOutputtedCodePointCount], mergedNodeCodePoints, + additionalCodePointCount * sizeof(mOutputCodePoints[0])); mOutputtedCodePointCount = static_cast<uint16_t>( - mOutputtedCodePointCount + mergedNodeCodePointCount); + mOutputtedCodePointCount + additionalCodePointCount); if (mOutputtedCodePointCount < MAX_WORD_LENGTH) { - mCodePointsBuf[mOutputtedCodePointCount] = 0; + mOutputCodePoints[mOutputtedCodePointCount] = 0; } } } - // TODO: Remove - int getCodePointAt(const int index) const { - return mCodePointsBuf[index]; + int getCurrentWordCodePointAt(const int index) const { + return mOutputCodePoints[mCurrentWordStart + index]; + } + + const int *getCodePointBuf() const { + return mOutputCodePoints; + } + + void setSecondWordFirstInputIndex(const int inputIndex) { + mSecondWordFirstInputIndex = inputIndex; + } + + int getSecondWordFirstInputIndex() const { + return mSecondWordFirstInputIndex; } - // TODO: Move to private - int mCodePointsBuf[MAX_WORD_LENGTH]; + // TODO: remove + int16_t getPrevWordsLength() const { + return mPrevWordsLength; + } + + int16_t getPrevWordCount() const { + return mPrevWordCount; + } + + int16_t getPrevWordStart() const { + return mPrevWordStart; + } + + int getOutputCodePointAt(const int id) const { + return mOutputCodePoints[id]; + } private: - // Caution!!! - // Use a default copy constructor and an assign operator because shallow copies are ok - // for this class + DISALLOW_COPY_AND_ASSIGN(DicNodeStateOutput); + + // When the DicNode represents "this is a pen": + // mOutputtedCodePointCount is 13, which is total code point count of "this is a pen" including + // spaces. + // mCurrentWordStart indicates the head of "pen", thus it is 10. + // This contains 3 previous words, "this", "is" and "a"; thus, mPrevWordCount is 3. + // mPrevWordsLength is length of "this is a ", which is 10. + // mPrevWordStart is the start index of "a"; thus, it is 8. + // mSecondWordFirstInputIndex is the first input index of "is". + uint16_t mOutputtedCodePointCount; + int mOutputCodePoints[MAX_WORD_LENGTH]; + int16_t mCurrentWordStart; + // Previous word count in mOutputCodePoints. + int16_t mPrevWordCount; + // Total length of previous words in mOutputCodePoints. This is being used by the algorithm + // that may want to look at the previous word information. + int16_t mPrevWordsLength; + // Start index of the previous word in mOutputCodePoints. This is being used for auto commit. + int16_t mPrevWordStart; + int mSecondWordFirstInputIndex; }; } // namespace latinime #endif // LATINIME_DIC_NODE_STATE_OUTPUT_H diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h deleted file mode 100644 index b8986203d..000000000 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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_DIC_NODE_STATE_PREVWORD_H -#define LATINIME_DIC_NODE_STATE_PREVWORD_H - -#include <cstring> // for memset() -#include <stdint.h> - -#include "defines.h" -#include "suggest/core/dicnode/dic_node_utils.h" -#include "suggest/core/layout/proximity_info_state.h" - -namespace latinime { - -class DicNodeStatePrevWord { - public: - AK_FORCE_INLINE DicNodeStatePrevWord() - : mPrevWordCount(0), mPrevWordLength(0), mPrevWordStart(0), mPrevWordProbability(0), - mPrevWordNodePos(NOT_A_DICT_POS), mSecondWordFirstInputIndex(NOT_AN_INDEX) { - memset(mPrevWord, 0, sizeof(mPrevWord)); - } - - virtual ~DicNodeStatePrevWord() {} - - void init() { - mPrevWordLength = 0; - mPrevWordCount = 0; - mPrevWordStart = 0; - mPrevWordProbability = -1; - mPrevWordNodePos = NOT_A_DICT_POS; - mSecondWordFirstInputIndex = NOT_AN_INDEX; - } - - void init(const int prevWordNodePos) { - mPrevWordLength = 0; - mPrevWordCount = 0; - mPrevWordStart = 0; - mPrevWordProbability = -1; - mPrevWordNodePos = prevWordNodePos; - mSecondWordFirstInputIndex = NOT_AN_INDEX; - } - - // Init by copy - AK_FORCE_INLINE void init(const DicNodeStatePrevWord *const prevWord) { - mPrevWordLength = prevWord->mPrevWordLength; - mPrevWordCount = prevWord->mPrevWordCount; - mPrevWordStart = prevWord->mPrevWordStart; - mPrevWordProbability = prevWord->mPrevWordProbability; - mPrevWordNodePos = prevWord->mPrevWordNodePos; - mSecondWordFirstInputIndex = prevWord->mSecondWordFirstInputIndex; - memcpy(mPrevWord, prevWord->mPrevWord, prevWord->mPrevWordLength * sizeof(mPrevWord[0])); - } - - void init(const int16_t prevWordCount, const int16_t prevWordProbability, - const int prevWordNodePos, const int *const src0, const int16_t length0, - const int *const src1, const int16_t length1, - const int prevWordSecondWordFirstInputIndex, const int lastInputIndex) { - mPrevWordCount = min(prevWordCount, static_cast<int16_t>(MAX_RESULTS)); - mPrevWordProbability = prevWordProbability; - mPrevWordNodePos = prevWordNodePos; - int twoWordsLen = - DicNodeUtils::appendTwoWords(src0, length0, src1, length1, mPrevWord); - if (twoWordsLen >= MAX_WORD_LENGTH) { - twoWordsLen = MAX_WORD_LENGTH - 1; - } - mPrevWord[twoWordsLen] = KEYCODE_SPACE; - mPrevWordStart = length0; - mPrevWordLength = static_cast<int16_t>(twoWordsLen + 1); - mSecondWordFirstInputIndex = prevWordSecondWordFirstInputIndex; - } - - void truncate(const int offset) { - // TODO: memmove - if (mPrevWordLength < offset) { - memset(mPrevWord, 0, sizeof(mPrevWord)); - mPrevWordLength = 0; - return; - } - const int newPrevWordLength = mPrevWordLength - offset; - memmove(mPrevWord, &mPrevWord[offset], newPrevWordLength * sizeof(mPrevWord[0])); - mPrevWordLength = newPrevWordLength; - } - - void setSecondWordFirstInputIndex(const int inputIndex) { - mSecondWordFirstInputIndex = inputIndex; - } - - int getSecondWordFirstInputIndex() const { - return mSecondWordFirstInputIndex; - } - - // TODO: remove - int16_t getPrevWordLength() const { - return mPrevWordLength; - } - - int16_t getPrevWordCount() const { - return mPrevWordCount; - } - - int16_t getPrevWordStart() const { - return mPrevWordStart; - } - - int getPrevWordNodePos() const { - return mPrevWordNodePos; - } - - int getPrevWordCodePointAt(const int id) const { - return mPrevWord[id]; - } - - bool startsWith(const DicNodeStatePrevWord *const prefix, const int prefixLen) const { - if (prefixLen > mPrevWordLength) { - return false; - } - for (int i = 0; i < prefixLen; ++i) { - if (mPrevWord[i] != prefix->mPrevWord[i]) { - return false; - } - } - return true; - } - - // TODO: Move to private - int mPrevWord[MAX_WORD_LENGTH]; - - private: - // Caution!!! - // Use a default copy constructor and an assign operator because shallow copies are ok - // for this class - int16_t mPrevWordCount; - int16_t mPrevWordLength; - int16_t mPrevWordStart; - int16_t mPrevWordProbability; - int mPrevWordNodePos; - int mSecondWordFirstInputIndex; -}; -} // namespace latinime -#endif // LATINIME_DIC_NODE_STATE_PREVWORD_H diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h index 3c85d0e9d..c19d48eb9 100644 --- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h +++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_scoring.h @@ -17,10 +17,12 @@ #ifndef LATINIME_DIC_NODE_STATE_SCORING_H #define LATINIME_DIC_NODE_STATE_SCORING_H -#include <stdint.h> +#include <algorithm> +#include <cstdint> #include "defines.h" #include "suggest/core/dictionary/digraph_utils.h" +#include "suggest/core/dictionary/error_type_utils.h" namespace latinime { @@ -29,17 +31,18 @@ class DicNodeStateScoring { AK_FORCE_INLINE DicNodeStateScoring() : mDoubleLetterLevel(NOT_A_DOUBLE_LETTER), mDigraphIndex(DigraphUtils::NOT_A_DIGRAPH_INDEX), - mEditCorrectionCount(0), mProximityCorrectionCount(0), + mEditCorrectionCount(0), mProximityCorrectionCount(0), mCompletionCount(0), mNormalizedCompoundDistance(0.0f), mSpatialDistance(0.0f), mLanguageDistance(0.0f), - mRawLength(0.0f), mExactMatch(true), + mRawLength(0.0f), mContainedErrorTypes(ErrorTypeUtils::NOT_AN_ERROR), mNormalizedCompoundDistanceAfterFirstWord(MAX_VALUE_FOR_WEIGHTING) { } - virtual ~DicNodeStateScoring() {} + ~DicNodeStateScoring() {} void init() { mEditCorrectionCount = 0; mProximityCorrectionCount = 0; + mCompletionCount = 0; mNormalizedCompoundDistance = 0.0f; mSpatialDistance = 0.0f; mLanguageDistance = 0.0f; @@ -47,46 +50,37 @@ class DicNodeStateScoring { mDoubleLetterLevel = NOT_A_DOUBLE_LETTER; mDigraphIndex = DigraphUtils::NOT_A_DIGRAPH_INDEX; mNormalizedCompoundDistanceAfterFirstWord = MAX_VALUE_FOR_WEIGHTING; - mExactMatch = true; + mContainedErrorTypes = ErrorTypeUtils::NOT_AN_ERROR; } - AK_FORCE_INLINE void init(const DicNodeStateScoring *const scoring) { + AK_FORCE_INLINE void initByCopy(const DicNodeStateScoring *const scoring) { mEditCorrectionCount = scoring->mEditCorrectionCount; mProximityCorrectionCount = scoring->mProximityCorrectionCount; + mCompletionCount = scoring->mCompletionCount; mNormalizedCompoundDistance = scoring->mNormalizedCompoundDistance; mSpatialDistance = scoring->mSpatialDistance; mLanguageDistance = scoring->mLanguageDistance; mRawLength = scoring->mRawLength; mDoubleLetterLevel = scoring->mDoubleLetterLevel; mDigraphIndex = scoring->mDigraphIndex; - mExactMatch = scoring->mExactMatch; + mContainedErrorTypes = scoring->mContainedErrorTypes; mNormalizedCompoundDistanceAfterFirstWord = scoring->mNormalizedCompoundDistanceAfterFirstWord; } void addCost(const float spatialCost, const float languageCost, const bool doNormalization, - const int inputSize, const int totalInputIndex, const ErrorType errorType) { + const int inputSize, const int totalInputIndex, + const ErrorTypeUtils::ErrorType errorType) { addDistance(spatialCost, languageCost, doNormalization, inputSize, totalInputIndex); - switch (errorType) { - case ET_EDIT_CORRECTION: - ++mEditCorrectionCount; - mExactMatch = false; - break; - case ET_PROXIMITY_CORRECTION: - ++mProximityCorrectionCount; - mExactMatch = false; - break; - case ET_COMPLETION: - mExactMatch = false; - break; - case ET_NEW_WORD: - mExactMatch = false; - break; - case ET_INTENTIONAL_OMISSION: - mExactMatch = false; - break; - case ET_NOT_AN_ERROR: - break; + mContainedErrorTypes = mContainedErrorTypes | errorType; + if (ErrorTypeUtils::isEditCorrectionError(errorType)) { + ++mEditCorrectionCount; + } + if (ErrorTypeUtils::isProximityCorrectionError(errorType)) { + ++mProximityCorrectionCount; + } + if (ErrorTypeUtils::isCompletion(errorType)) { + ++mCompletionCount; } } @@ -140,6 +134,10 @@ class DicNodeStateScoring { return mProximityCorrectionCount; } + int16_t getCompletionCount() const { + return mCompletionCount; + } + float getRawLength() const { return mRawLength; } @@ -181,25 +179,26 @@ class DicNodeStateScoring { } } - bool isExactMatch() const { - return mExactMatch; + ErrorTypeUtils::ErrorType getContainedErrorTypes() const { + return mContainedErrorTypes; } private: - // Caution!!! - // Use a default copy constructor and an assign operator because shallow copies are ok - // for this class + DISALLOW_COPY_AND_ASSIGN(DicNodeStateScoring); + DoubleLetterLevel mDoubleLetterLevel; DigraphUtils::DigraphCodePointIndex mDigraphIndex; int16_t mEditCorrectionCount; int16_t mProximityCorrectionCount; + int16_t mCompletionCount; float mNormalizedCompoundDistance; float mSpatialDistance; float mLanguageDistance; float mRawLength; - bool mExactMatch; + // All accumulated error types so far + ErrorTypeUtils::ErrorType mContainedErrorTypes; float mNormalizedCompoundDistanceAfterFirstWord; AK_FORCE_INLINE void addDistance(float spatialDistance, float languageDistance, @@ -210,7 +209,7 @@ class DicNodeStateScoring { mNormalizedCompoundDistance = mSpatialDistance + mLanguageDistance; } else { mNormalizedCompoundDistance = (mSpatialDistance + mLanguageDistance) - / static_cast<float>(max(1, totalInputIndex)); + / static_cast<float>(std::max(1, totalInputIndex)); } } }; diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp index 71f4ef6ea..f793363a8 100644 --- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp @@ -14,16 +14,18 @@ * limitations under the License. */ -#include <cstring> - #define LOG_TAG "LatinIME: bigram_dictionary.cpp" #include "bigram_dictionary.h" +#include <algorithm> +#include <cstring> + #include "defines.h" #include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/dictionary/dictionary.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/core/result/suggestion_results.h" #include "utils/char_utils.h" namespace latinime { @@ -39,65 +41,13 @@ BigramDictionary::BigramDictionary( BigramDictionary::~BigramDictionary() { } -void BigramDictionary::addWordBigram(int *word, int length, int probability, int *bigramProbability, - int *bigramCodePoints, int *outputTypes) const { - word[length] = 0; - if (DEBUG_DICT_FULL) { -#ifdef FLAG_DBG - char s[length + 1]; - for (int i = 0; i <= length; i++) s[i] = static_cast<char>(word[i]); - AKLOGI("Bigram: Found word = %s, freq = %d :", s, probability); -#endif - } - - // Find the right insertion point - int insertAt = 0; - while (insertAt < MAX_RESULTS) { - if (probability > bigramProbability[insertAt] || (bigramProbability[insertAt] == probability - && length < CharUtils::getCodePointCount(MAX_WORD_LENGTH, - bigramCodePoints + insertAt * MAX_WORD_LENGTH))) { - break; - } - insertAt++; - } - if (DEBUG_DICT_FULL) { - AKLOGI("Bigram: InsertAt -> %d MAX_RESULTS: %d", insertAt, MAX_RESULTS); - } - if (insertAt >= MAX_RESULTS) { - return; - } - memmove(bigramProbability + (insertAt + 1), - bigramProbability + insertAt, - (MAX_RESULTS - insertAt - 1) * sizeof(bigramProbability[0])); - bigramProbability[insertAt] = probability; - outputTypes[insertAt] = Dictionary::KIND_PREDICTION; - memmove(bigramCodePoints + (insertAt + 1) * MAX_WORD_LENGTH, - bigramCodePoints + insertAt * MAX_WORD_LENGTH, - (MAX_RESULTS - insertAt - 1) * sizeof(bigramCodePoints[0]) * MAX_WORD_LENGTH); - int *dest = bigramCodePoints + insertAt * MAX_WORD_LENGTH; - while (length--) { - *dest++ = *word++; - } - *dest = 0; // NULL terminate - if (DEBUG_DICT_FULL) { - AKLOGI("Bigram: Added word at %d", insertAt); - } -} - /* Parameters : * prevWord: the word before, the one for which we need to look up bigrams. * prevWordLength: its length. - * outBigramCodePoints: an array for output, at the same format as outwords for getSuggestions. - * outBigramProbability: an array to output frequencies. - * outputTypes: an array to output types. - * This method returns the number of bigrams this word has, for backward compatibility. + * outSuggestionResults: SuggestionResults to put the predictions. */ -int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLength, - int *const outBigramCodePoints, int *const outBigramProbability, - int *const outputTypes) const { - // TODO: remove unused arguments, and refrain from storing stuff in members of this class - // TODO: have "in" arguments before "out" ones, and make out args explicit in the name - +void BigramDictionary::getPredictions(const int *prevWord, const int prevWordLength, + SuggestionResults *const outSuggestionResults) const { int pos = getBigramListPositionForWord(prevWord, prevWordLength, false /* forceLowerCaseSearch */); // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams @@ -107,11 +57,10 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng true /* forceLowerCaseSearch */); } // If still no bigrams, we really don't have them! - if (NOT_A_DICT_POS == pos) return 0; + if (NOT_A_DICT_POS == pos) return; - int bigramCount = 0; int unigramProbability = 0; - int bigramBuffer[MAX_WORD_LENGTH]; + int bigramCodePoints[MAX_WORD_LENGTH]; BinaryDictionaryBigramsIterator bigramsIt( mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos); while (bigramsIt.hasNext()) { @@ -121,7 +70,7 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng } const int codePointCount = mDictionaryStructurePolicy-> getCodePointsAndProbabilityAndReturnCodePointCount(bigramsIt.getBigramPos(), - MAX_WORD_LENGTH, bigramBuffer, &unigramProbability); + MAX_WORD_LENGTH, bigramCodePoints, &unigramProbability); if (codePointCount <= 0) { continue; } @@ -132,11 +81,8 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng // here, but it can't get too bad. const int probability = mDictionaryStructurePolicy->getProbability( unigramProbability, bigramsIt.getProbability()); - addWordBigram(bigramBuffer, codePointCount, probability, outBigramProbability, - outBigramCodePoints, outputTypes); - ++bigramCount; + outSuggestionResults->addPrediction(bigramCodePoints, codePointCount, probability); } - return min(bigramCount, MAX_RESULTS); } // Returns a pointer to the start of the bigram list. @@ -144,7 +90,7 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const { if (0 >= prevWordLength) return NOT_A_DICT_POS; - int pos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(prevWord, prevWordLength, + int pos = mDictionaryStructurePolicy->getTerminalPtNodePositionOfWord(prevWord, prevWordLength, forceLowerCaseSearch); if (NOT_A_DICT_POS == pos) return NOT_A_DICT_POS; return mDictionaryStructurePolicy->getBigramsPositionOfPtNode(pos); @@ -155,7 +101,7 @@ int BigramDictionary::getBigramProbability(const int *word0, int length0, const int pos = getBigramListPositionForWord(word0, length0, false /* forceLowerCaseSearch */); // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams if (NOT_A_DICT_POS == pos) return NOT_A_PROBABILITY; - int nextWordPos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(word1, length1, + int nextWordPos = mDictionaryStructurePolicy->getTerminalPtNodePositionOfWord(word1, length1, false /* forceLowerCaseSearch */); if (NOT_A_DICT_POS == nextWordPos) return NOT_A_PROBABILITY; @@ -163,7 +109,8 @@ int BigramDictionary::getBigramProbability(const int *word0, int length0, const mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos); while (bigramsIt.hasNext()) { bigramsIt.next(); - if (bigramsIt.getBigramPos() == nextWordPos) { + if (bigramsIt.getBigramPos() == nextWordPos + && bigramsIt.getProbability() != NOT_A_PROBABILITY) { return mDictionaryStructurePolicy->getProbability( mDictionaryStructurePolicy->getUnigramProbabilityOfPtNode(nextWordPos), bigramsIt.getProbability()); diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h index 8af7ee75d..12aaf20d3 100644 --- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h +++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h @@ -22,21 +22,20 @@ namespace latinime { class DictionaryStructureWithBufferPolicy; +class SuggestionResults; class BigramDictionary { public: BigramDictionary(const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy); - int getPredictions(const int *word, int length, int *outBigramCodePoints, - int *outBigramProbability, int *outputTypes) const; + void getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const; int getBigramProbability(const int *word1, int length1, const int *word2, int length2) const; ~BigramDictionary(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary); - void addWordBigram(int *word, int length, int probability, int *bigramProbability, - int *bigramCodePoints, int *outputTypes) const; int getBigramListPositionForWord(const int *prevWord, const int prevWordLength, const bool forceLowerCaseSearch) const; diff --git a/native/jni/src/suggest/core/dictionary/bloom_filter.h b/native/jni/src/suggest/core/dictionary/bloom_filter.h index 5205456a8..1e60f49ed 100644 --- a/native/jni/src/suggest/core/dictionary/bloom_filter.h +++ b/native/jni/src/suggest/core/dictionary/bloom_filter.h @@ -17,7 +17,7 @@ #ifndef LATINIME_BLOOM_FILTER_H #define LATINIME_BLOOM_FILTER_H -#include <stdint.h> +#include <bitset> #include "defines.h" @@ -33,38 +33,37 @@ namespace latinime { // Total 148603.14 (sum of others 148579.90) class BloomFilter { public: - BloomFilter() { - ASSERT(BIGRAM_FILTER_BYTE_SIZE * 8 >= BIGRAM_FILTER_MODULO); - } + BloomFilter() : mFilter() {} - // TODO: uint32_t position - AK_FORCE_INLINE void setInFilter(const int32_t position) { - const uint32_t bucket = static_cast<uint32_t>(position % BIGRAM_FILTER_MODULO); - mFilter[bucket >> 3] |= static_cast<uint8_t>(1 << (bucket & 0x7)); + AK_FORCE_INLINE void setInFilter(const int position) { + mFilter.set(getIndex(position)); } - // TODO: uint32_t position - AK_FORCE_INLINE bool isInFilter(const int32_t position) const { - const uint32_t bucket = static_cast<uint32_t>(position % BIGRAM_FILTER_MODULO); - return (mFilter[bucket >> 3] & static_cast<uint8_t>(1 << (bucket & 0x7))) != 0; + AK_FORCE_INLINE bool isInFilter(const int position) const { + return mFilter.test(getIndex(position)); } private: - // Size, in bytes, of the bloom filter index for bigrams - // 128 gives us 1024 buckets. The probability of false positive is (1 - e ** (-kn/m))**k, + DISALLOW_ASSIGNMENT_OPERATOR(BloomFilter); + + AK_FORCE_INLINE size_t getIndex(const int position) const { + return static_cast<size_t>(position) % BIGRAM_FILTER_MODULO; + } + + // Size, in bits, of the bloom filter index for bigrams + // The probability of false positive is (1 - e ** (-kn/m))**k, // where k is the number of hash functions, n the number of bigrams, and m the number of // bits we can test. - // At the moment 100 is the maximum number of bigrams for a word with the current + // At the moment 100 is the maximum number of bigrams for a word with the current main // dictionaries, so n = 100. 1024 buckets give us m = 1024. // With 1 hash function, our false positive rate is about 9.3%, which should be enough for // our uses since we are only using this to increase average performance. For the record, // k = 2 gives 3.1% and k = 3 gives 1.6%. With k = 1, making m = 2048 gives 4.8%, // and m = 4096 gives 2.4%. - // This is assigned here because it is used for array size. - static const int BIGRAM_FILTER_BYTE_SIZE = 128; - static const int BIGRAM_FILTER_MODULO; - - uint8_t mFilter[BIGRAM_FILTER_BYTE_SIZE]; + // This is assigned here because it is used for bitset size. + // 1021 is the largest prime under 1024. + static const size_t BIGRAM_FILTER_MODULO = 1021; + std::bitset<BIGRAM_FILTER_MODULO> mFilter; }; } // namespace latinime #endif // LATINIME_BLOOM_FILTER_H diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index 59ead1894..e288413a3 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -18,77 +18,57 @@ #include "suggest/core/dictionary/dictionary.h" -#include <stdint.h> - #include "defines.h" -#include "suggest/core/dictionary/bigram_dictionary.h" #include "suggest/core/policy/dictionary_header_structure_policy.h" -#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/core/result/suggestion_results.h" #include "suggest/core/session/dic_traverse_session.h" #include "suggest/core/suggest.h" #include "suggest/core/suggest_options.h" #include "suggest/policyimpl/gesture/gesture_suggest_policy_factory.h" #include "suggest/policyimpl/typing/typing_suggest_policy_factory.h" #include "utils/log_utils.h" +#include "utils/time_keeper.h" namespace latinime { const int Dictionary::HEADER_ATTRIBUTE_BUFFER_SIZE = 32; -Dictionary::Dictionary(JNIEnv *env, - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy) - : mDictionaryStructureWithBufferPolicy(dictionaryStructureWithBufferPolicy), - mBigramDictionary(new BigramDictionary(mDictionaryStructureWithBufferPolicy)), +Dictionary::Dictionary(JNIEnv *env, DictionaryStructureWithBufferPolicy::StructurePolicyPtr + dictionaryStructureWithBufferPolicy) + : mDictionaryStructureWithBufferPolicy(std::move(dictionaryStructureWithBufferPolicy)), + mBigramDictionary(mDictionaryStructureWithBufferPolicy.get()), mGestureSuggest(new Suggest(GestureSuggestPolicyFactory::getGestureSuggestPolicy())), mTypingSuggest(new Suggest(TypingSuggestPolicyFactory::getTypingSuggestPolicy())) { logDictionaryInfo(env); } -Dictionary::~Dictionary() { - delete mBigramDictionary; - delete mGestureSuggest; - delete mTypingSuggest; - delete mDictionaryStructureWithBufferPolicy; -} - -int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, +void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints, - int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint, - const SuggestOptions *const suggestOptions, int *outWords, int *frequencies, - int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const { - int result = 0; - if (suggestOptions->isGesture()) { - DicTraverseSession::initSessionInstance( - traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions); - result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, - ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords, - frequencies, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence); - if (DEBUG_DICT) { - DUMP_RESULT(outWords, frequencies); - } - return result; - } else { - DicTraverseSession::initSessionInstance( - traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions); - result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, - ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, - outWords, frequencies, spaceIndices, outputTypes, - outputAutoCommitFirstWordConfidence); - if (DEBUG_DICT) { - DUMP_RESULT(outWords, frequencies); - } - return result; + int inputSize, int *prevWordCodePoints, int prevWordLength, + const SuggestOptions *const suggestOptions, const float languageWeight, + SuggestionResults *const outSuggestionResults) const { + TimeKeeper::setCurrentTime(); + DicTraverseSession::initSessionInstance( + traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions); + const auto &suggest = suggestOptions->isGesture() ? mGestureSuggest : mTypingSuggest; + suggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, + ycoordinates, times, pointerIds, inputCodePoints, inputSize, + languageWeight, outSuggestionResults); + if (DEBUG_DICT) { + outSuggestionResults->dumpSuggestions(); } } -int Dictionary::getBigrams(const int *word, int length, int *outWords, int *frequencies, - int *outputTypes) const { - if (length <= 0) return 0; - return mBigramDictionary->getPredictions(word, length, outWords, frequencies, outputTypes); +void Dictionary::getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const { + TimeKeeper::setCurrentTime(); + if (length <= 0) return; + mBigramDictionary.getPredictions(word, length, outSuggestionResults); } int Dictionary::getProbability(const int *word, int length) const { - int pos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(word, length, + TimeKeeper::setCurrentTime(); + int pos = getDictionaryStructurePolicy()->getTerminalPtNodePositionOfWord(word, length, false /* forceLowerCaseSearch */); if (NOT_A_DICT_POS == pos) { return NOT_A_PROBABILITY; @@ -98,39 +78,62 @@ int Dictionary::getProbability(const int *word, int length) const { int Dictionary::getBigramProbability(const int *word0, int length0, const int *word1, int length1) const { - return mBigramDictionary->getBigramProbability(word0, length0, word1, length1); + TimeKeeper::setCurrentTime(); + return mBigramDictionary.getBigramProbability(word0, length0, word1, length1); } -void Dictionary::addUnigramWord(const int *const word, const int length, const int probability) { - mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, probability); +void Dictionary::addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty) { + TimeKeeper::setCurrentTime(); + mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, unigramProperty); } void Dictionary::addBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1, const int probability) { + const int length1, const int probability, const int timestamp) { + TimeKeeper::setCurrentTime(); mDictionaryStructureWithBufferPolicy->addBigramWords(word0, length0, word1, length1, - probability); + probability, timestamp); } void Dictionary::removeBigramWords(const int *const word0, const int length0, const int *const word1, const int length1) { + TimeKeeper::setCurrentTime(); mDictionaryStructureWithBufferPolicy->removeBigramWords(word0, length0, word1, length1); } void Dictionary::flush(const char *const filePath) { + TimeKeeper::setCurrentTime(); mDictionaryStructureWithBufferPolicy->flush(filePath); } void Dictionary::flushWithGC(const char *const filePath) { + TimeKeeper::setCurrentTime(); mDictionaryStructureWithBufferPolicy->flushWithGC(filePath); } bool Dictionary::needsToRunGC(const bool mindsBlockByGC) { + TimeKeeper::setCurrentTime(); return mDictionaryStructureWithBufferPolicy->needsToRunGC(mindsBlockByGC); } -void Dictionary::getProperty(const char *const query, char *const outResult, +void Dictionary::getProperty(const char *const query, const int queryLength, char *const outResult, const int maxResultLength) { - return mDictionaryStructureWithBufferPolicy->getProperty(query, outResult, maxResultLength); + TimeKeeper::setCurrentTime(); + return mDictionaryStructureWithBufferPolicy->getProperty(query, queryLength, outResult, + maxResultLength); +} + +const WordProperty Dictionary::getWordProperty(const int *const codePoints, + const int codePointCount) { + TimeKeeper::setCurrentTime(); + return mDictionaryStructureWithBufferPolicy->getWordProperty( + codePoints, codePointCount); +} + +int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints) { + TimeKeeper::setCurrentTime(); + return mDictionaryStructureWithBufferPolicy->getNextWordAndNextToken( + token, outCodePoints); } void Dictionary::logDictionaryInfo(JNIEnv *const env) const { diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h index 0195d5bf0..b6149b338 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.h +++ b/native/jni/src/suggest/core/dictionary/dictionary.h @@ -17,18 +17,22 @@ #ifndef LATINIME_DICTIONARY_H #define LATINIME_DICTIONARY_H -#include <stdint.h> +#include <memory> #include "defines.h" #include "jni.h" +#include "suggest/core/dictionary/bigram_dictionary.h" +#include "suggest/core/dictionary/property/word_property.h" +#include "suggest/core/policy/dictionary_header_structure_policy.h" +#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/core/suggest_interface.h" namespace latinime { -class BigramDictionary; class DictionaryStructureWithBufferPolicy; class DicTraverseSession; class ProximityInfo; -class SuggestInterface; +class SuggestionResults; class SuggestOptions; class Dictionary { @@ -53,26 +57,27 @@ class Dictionary { static const int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000; static const int KIND_FLAG_EXACT_MATCH = 0x40000000; - Dictionary(JNIEnv *env, - DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPoilcy); + Dictionary(JNIEnv *env, DictionaryStructureWithBufferPolicy::StructurePolicyPtr + dictionaryStructureWithBufferPolicy); - int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, + void getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints, - int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint, - const SuggestOptions *const suggestOptions, int *outWords, int *frequencies, - int *spaceIndices, int *outputTypes, int *outputAutoCommitFirstWordConfidence) const; + int inputSize, int *prevWordCodePoints, int prevWordLength, + const SuggestOptions *const suggestOptions, const float languageWeight, + SuggestionResults *const outSuggestionResults) const; - int getBigrams(const int *word, int length, int *outWords, int *frequencies, - int *outputTypes) const; + void getPredictions(const int *word, int length, + SuggestionResults *const outSuggestionResults) const; int getProbability(const int *word, int length) const; int getBigramProbability(const int *word0, int length0, const int *word1, int length1) const; - void addUnigramWord(const int *const word, const int length, const int probability); + void addUnigramWord(const int *const codePoints, const int codePointCount, + const UnigramProperty *const unigramProperty); void addBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1, const int probability); + const int length1, const int probability, const int timestamp); void removeBigramWords(const int *const word0, const int length0, const int *const word1, const int length1); @@ -83,24 +88,32 @@ class Dictionary { bool needsToRunGC(const bool mindsBlockByGC); - void getProperty(const char *const query, char *const outResult, + void getProperty(const char *const query, const int queryLength, char *const outResult, const int maxResultLength); + const WordProperty getWordProperty(const int *const codePoints, const int codePointCount); + + // Method to iterate all words in the dictionary. + // The returned token has to be used to get the next word. If token is 0, this method newly + // starts iterating the dictionary. + int getNextWordAndNextToken(const int token, int *const outCodePoints); + const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const { - return mDictionaryStructureWithBufferPolicy; + return mDictionaryStructureWithBufferPolicy.get(); } - virtual ~Dictionary(); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary); + typedef std::unique_ptr<SuggestInterface> SuggestInterfacePtr; + static const int HEADER_ATTRIBUTE_BUFFER_SIZE; - DictionaryStructureWithBufferPolicy *const mDictionaryStructureWithBufferPolicy; - const BigramDictionary *const mBigramDictionary; - const SuggestInterface *const mGestureSuggest; - const SuggestInterface *const mTypingSuggest; + const DictionaryStructureWithBufferPolicy::StructurePolicyPtr + mDictionaryStructureWithBufferPolicy; + const BigramDictionary mBigramDictionary; + const SuggestInterfacePtr mGestureSuggest; + const SuggestInterfacePtr mTypingSuggest; void logDictionaryInfo(JNIEnv *const env) const; }; diff --git a/native/jni/src/suggest/core/dictionary/digraph_utils.cpp b/native/jni/src/suggest/core/dictionary/digraph_utils.cpp index 3271c1bfb..bb2ce5012 100644 --- a/native/jni/src/suggest/core/dictionary/digraph_utils.cpp +++ b/native/jni/src/suggest/core/dictionary/digraph_utils.cpp @@ -28,11 +28,8 @@ const DigraphUtils::digraph_t DigraphUtils::GERMAN_UMLAUT_DIGRAPHS[] = { { 'a', 'e', 0x00E4 }, // U+00E4 : LATIN SMALL LETTER A WITH DIAERESIS { 'o', 'e', 0x00F6 }, // U+00F6 : LATIN SMALL LETTER O WITH DIAERESIS { 'u', 'e', 0x00FC } }; // U+00FC : LATIN SMALL LETTER U WITH DIAERESIS -const DigraphUtils::digraph_t DigraphUtils::FRENCH_LIGATURES_DIGRAPHS[] = - { { 'a', 'e', 0x00E6 }, // U+00E6 : LATIN SMALL LETTER AE - { 'o', 'e', 0x0153 } }; // U+0153 : LATIN SMALL LIGATURE OE const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] = - { DIGRAPH_TYPE_GERMAN_UMLAUT, DIGRAPH_TYPE_FRENCH_LIGATURES }; + { DIGRAPH_TYPE_GERMAN_UMLAUT }; /* static */ bool DigraphUtils::hasDigraphForCodePoint( const DictionaryHeaderStructurePolicy *const headerPolicy, @@ -50,9 +47,6 @@ const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] = if (headerPolicy->requiresGermanUmlautProcessing()) { return DIGRAPH_TYPE_GERMAN_UMLAUT; } - if (headerPolicy->requiresFrenchLigatureProcessing()) { - return DIGRAPH_TYPE_FRENCH_LIGATURES; - } return DIGRAPH_TYPE_NONE; } @@ -86,15 +80,11 @@ const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] = *digraphs = GERMAN_UMLAUT_DIGRAPHS; return NELEMS(GERMAN_UMLAUT_DIGRAPHS); } - if (digraphType == DIGRAPH_TYPE_FRENCH_LIGATURES) { - *digraphs = FRENCH_LIGATURES_DIGRAPHS; - return NELEMS(FRENCH_LIGATURES_DIGRAPHS); - } return 0; } /** - * Returns the digraph for the input composite glyph codepoint, or 0 if none exists. + * Returns the digraph for the input composite glyph codepoint, or nullptr if none exists. * compositeGlyphCodePoint: the method returns the digraph corresponding to this codepoint. */ /* static */ const DigraphUtils::digraph_t *DigraphUtils::getDigraphForCodePoint( @@ -106,17 +96,17 @@ const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] = return digraph; } } - return 0; + return nullptr; } /** - * Returns the digraph for the input composite glyph codepoint, or 0 if none exists. + * Returns the digraph for the input composite glyph codepoint, or nullptr if none exists. * digraphType: the type of digraphs supported. * compositeGlyphCodePoint: the method returns the digraph corresponding to this codepoint. */ /* static */ const DigraphUtils::digraph_t *DigraphUtils::getDigraphForDigraphTypeAndCodePoint( const DigraphUtils::DigraphType digraphType, const int compositeGlyphCodePoint) { - const DigraphUtils::digraph_t *digraphs = 0; + const DigraphUtils::digraph_t *digraphs = nullptr; const int compositeGlyphLowerCodePoint = CharUtils::toLowerCase(compositeGlyphCodePoint); const int digraphsSize = DigraphUtils::getAllDigraphsForDigraphTypeAndReturnSize(digraphType, &digraphs); @@ -125,7 +115,7 @@ const DigraphUtils::DigraphType DigraphUtils::USED_DIGRAPH_TYPES[] = return &digraphs[i]; } } - return 0; + return nullptr; } } // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/digraph_utils.h b/native/jni/src/suggest/core/dictionary/digraph_utils.h index 6ae16e390..bec2cd6e2 100644 --- a/native/jni/src/suggest/core/dictionary/digraph_utils.h +++ b/native/jni/src/suggest/core/dictionary/digraph_utils.h @@ -34,7 +34,6 @@ class DigraphUtils { typedef enum { DIGRAPH_TYPE_NONE, DIGRAPH_TYPE_GERMAN_UMLAUT, - DIGRAPH_TYPE_FRENCH_LIGATURES } DigraphType; typedef struct { int first; int second; int compositeGlyph; } digraph_t; @@ -55,7 +54,6 @@ class DigraphUtils { const DigraphType digraphType, const int compositeGlyphCodePoint); static const digraph_t GERMAN_UMLAUT_DIGRAPHS[]; - static const digraph_t FRENCH_LIGATURES_DIGRAPHS[]; static const DigraphType USED_DIGRAPH_TYPES[]; }; } // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/error_type_utils.cpp b/native/jni/src/suggest/core/dictionary/error_type_utils.cpp new file mode 100644 index 000000000..0635fef7e --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/error_type_utils.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/core/dictionary/error_type_utils.h" + +namespace latinime { + +const ErrorTypeUtils::ErrorType ErrorTypeUtils::NOT_AN_ERROR = 0x0; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::MATCH_WITH_CASE_ERROR = 0x1; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::MATCH_WITH_ACCENT_ERROR = 0x2; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::MATCH_WITH_DIGRAPH = 0x4; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::INTENTIONAL_OMISSION = 0x8; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::EDIT_CORRECTION = 0x10; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::PROXIMITY_CORRECTION = 0x20; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::COMPLETION = 0x40; +const ErrorTypeUtils::ErrorType ErrorTypeUtils::NEW_WORD = 0x80; + +const ErrorTypeUtils::ErrorType ErrorTypeUtils::ERRORS_TREATED_AS_AN_EXACT_MATCH = + NOT_AN_ERROR | MATCH_WITH_CASE_ERROR | MATCH_WITH_ACCENT_ERROR | MATCH_WITH_DIGRAPH; + +} // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/error_type_utils.h b/native/jni/src/suggest/core/dictionary/error_type_utils.h new file mode 100644 index 000000000..0e8e5b635 --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/error_type_utils.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 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_ERROR_TYPE_UTILS_H +#define LATINIME_ERROR_TYPE_UTILS_H + +#include <cstdint> + +#include "defines.h" + +namespace latinime { + +class ErrorTypeUtils { + public: + // ErrorType is mainly decided by CorrectionType but it is also depending on if + // the correction has really been performed or not. + typedef uint32_t ErrorType; + + static const ErrorType NOT_AN_ERROR; + static const ErrorType MATCH_WITH_CASE_ERROR; + static const ErrorType MATCH_WITH_ACCENT_ERROR; + static const ErrorType MATCH_WITH_DIGRAPH; + // Treat error as an intentional omission when the CorrectionType is omission and the node can + // be intentional omission. + static const ErrorType INTENTIONAL_OMISSION; + // Substitution, omission and transposition + static const ErrorType EDIT_CORRECTION; + // Proximity error + static const ErrorType PROXIMITY_CORRECTION; + // Completion + static const ErrorType COMPLETION; + // New word + // TODO: Remove. + // A new word error should be an edit correction error or a proximity correction error. + static const ErrorType NEW_WORD; + + static bool isExactMatch(const ErrorType containedErrorTypes) { + return (containedErrorTypes & ~ERRORS_TREATED_AS_AN_EXACT_MATCH) == 0; + } + + static bool isEditCorrectionError(const ErrorType errorType) { + return (errorType & EDIT_CORRECTION) != 0; + } + + static bool isProximityCorrectionError(const ErrorType errorType) { + return (errorType & PROXIMITY_CORRECTION) != 0; + } + + static bool isCompletion(const ErrorType errorType) { + return (errorType & COMPLETION) != 0; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorTypeUtils); + + static const ErrorType ERRORS_TREATED_AS_AN_EXACT_MATCH; +}; +} // namespace latinime +#endif // LATINIME_ERROR_TYPE_UTILS_H diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp index b1d2f4b4d..105224126 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp @@ -17,6 +17,7 @@ #include "suggest/core/dictionary/multi_bigram_map.h" #include <cstddef> +#include <unordered_map> namespace latinime { @@ -30,4 +31,75 @@ const size_t MultiBigramMap::MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP = 25; // Most common previous word contexts currently have 100 bigrams const int MultiBigramMap::BigramMap::DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP = 100; +// Look up the bigram probability for the given word pair from the cached bigram maps. +// Also caches the bigrams if there is space remaining and they have not been cached already. +int MultiBigramMap::getBigramProbability( + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int wordPosition, const int nextWordPosition, const int unigramProbability) { + std::unordered_map<int, BigramMap>::const_iterator mapPosition = + mBigramMaps.find(wordPosition); + if (mapPosition != mBigramMaps.end()) { + return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition, + unigramProbability); + } + if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) { + addBigramsForWordPosition(structurePolicy, wordPosition); + return mBigramMaps[wordPosition].getBigramProbability(structurePolicy, + nextWordPosition, unigramProbability); + } + return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition, + nextWordPosition, unigramProbability); +} + +void MultiBigramMap::BigramMap::init( + const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos) { + const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos); + BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), + bigramsListPos); + while (bigramsIt.hasNext()) { + bigramsIt.next(); + if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) { + continue; + } + mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability(); + mBloomFilter.setInFilter(bigramsIt.getBigramPos()); + } +} + +int MultiBigramMap::BigramMap::getBigramProbability( + const DictionaryStructureWithBufferPolicy *const structurePolicy, + const int nextWordPosition, const int unigramProbability) const { + int bigramProbability = NOT_A_PROBABILITY; + if (mBloomFilter.isInFilter(nextWordPosition)) { + const std::unordered_map<int, int>::const_iterator bigramProbabilityIt = + mBigramMap.find(nextWordPosition); + if (bigramProbabilityIt != mBigramMap.end()) { + bigramProbability = bigramProbabilityIt->second; + } + } + return structurePolicy->getProbability(unigramProbability, bigramProbability); +} + +void MultiBigramMap::addBigramsForWordPosition( + const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position) { + mBigramMaps[position].init(structurePolicy, position); +} + +int MultiBigramMap::readBigramProbabilityFromBinaryDictionary( + const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos, + const int nextWordPosition, const int unigramProbability) { + int bigramProbability = NOT_A_PROBABILITY; + const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos); + BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), + bigramsListPos); + while (bigramsIt.hasNext()) { + bigramsIt.next(); + if (bigramsIt.getBigramPos() == nextWordPosition) { + bigramProbability = bigramsIt.getProbability(); + break; + } + } + return structurePolicy->getProbability(unigramProbability, bigramProbability); +} + } // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h index 4633c07b0..195b5e22f 100644 --- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h +++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h @@ -18,12 +18,12 @@ #define LATINIME_MULTI_BIGRAM_MAP_H #include <cstddef> +#include <unordered_map> #include "defines.h" #include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/core/dictionary/bloom_filter.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" -#include "utils/hash_map_compat.h" namespace latinime { @@ -38,21 +38,7 @@ class MultiBigramMap { // Look up the bigram probability for the given word pair from the cached bigram maps. // Also caches the bigrams if there is space remaining and they have not been cached already. int getBigramProbability(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int wordPosition, const int nextWordPosition, const int unigramProbability) { - hash_map_compat<int, BigramMap>::const_iterator mapPosition = - mBigramMaps.find(wordPosition); - if (mapPosition != mBigramMaps.end()) { - return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition, - unigramProbability); - } - if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) { - addBigramsForWordPosition(structurePolicy, wordPosition); - return mBigramMaps[wordPosition].getBigramProbability(structurePolicy, - nextWordPosition, unigramProbability); - } - return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition, - nextWordPosition, unigramProbability); - } + const int wordPosition, const int nextWordPosition, const int unigramProbability); void clear() { mBigramMaps.clear(); @@ -67,66 +53,29 @@ class MultiBigramMap { ~BigramMap() {} void init(const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int nodePos) { - const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos); - BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), - bigramsListPos); - while (bigramsIt.hasNext()) { - bigramsIt.next(); - if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) { - continue; - } - mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability(); - mBloomFilter.setInFilter(bigramsIt.getBigramPos()); - } - } + const int nodePos); - AK_FORCE_INLINE int getBigramProbability( + int getBigramProbability( const DictionaryStructureWithBufferPolicy *const structurePolicy, - const int nextWordPosition, const int unigramProbability) const { - int bigramProbability = NOT_A_PROBABILITY; - if (mBloomFilter.isInFilter(nextWordPosition)) { - const hash_map_compat<int, int>::const_iterator bigramProbabilityIt = - mBigramMap.find(nextWordPosition); - if (bigramProbabilityIt != mBigramMap.end()) { - bigramProbability = bigramProbabilityIt->second; - } - } - return structurePolicy->getProbability(unigramProbability, bigramProbability); - } + const int nextWordPosition, const int unigramProbability) const; private: // NOTE: The BigramMap class doesn't use DISALLOW_COPY_AND_ASSIGN() because its default // copy constructor is needed for use in hash_map. static const int DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP; - hash_map_compat<int, int> mBigramMap; + std::unordered_map<int, int> mBigramMap; BloomFilter mBloomFilter; }; - AK_FORCE_INLINE void addBigramsForWordPosition( - const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position) { - mBigramMaps[position].init(structurePolicy, position); - } + void addBigramsForWordPosition( + const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position); - AK_FORCE_INLINE int readBigramProbabilityFromBinaryDictionary( + int readBigramProbabilityFromBinaryDictionary( const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos, - const int nextWordPosition, const int unigramProbability) { - int bigramProbability = NOT_A_PROBABILITY; - const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos); - BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), - bigramsListPos); - while (bigramsIt.hasNext()) { - bigramsIt.next(); - if (bigramsIt.getBigramPos() == nextWordPosition) { - bigramProbability = bigramsIt.getProbability(); - break; - } - } - return structurePolicy->getProbability(unigramProbability, bigramProbability); - } + const int nextWordPosition, const int unigramProbability); static const size_t MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP; - hash_map_compat<int, BigramMap> mBigramMaps; + std::unordered_map<int, BigramMap> mBigramMaps; }; } // namespace latinime #endif // LATINIME_MULTI_BIGRAM_MAP_H diff --git a/native/jni/src/suggest/core/dictionary/property/bigram_property.h b/native/jni/src/suggest/core/dictionary/property/bigram_property.h new file mode 100644 index 000000000..8d3429b5b --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/property/bigram_property.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 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_BIGRAM_PROPERTY_H +#define LATINIME_BIGRAM_PROPERTY_H + +#include <vector> + +#include "defines.h" + +namespace latinime { + +class BigramProperty { + public: + BigramProperty(const std::vector<int> *const targetCodePoints, + const int probability, const int timestamp, const int level, const int count) + : mTargetCodePoints(*targetCodePoints), mProbability(probability), + mTimestamp(timestamp), mLevel(level), mCount(count) {} + + const std::vector<int> *getTargetCodePoints() const { + return &mTargetCodePoints; + } + + int getProbability() const { + return mProbability; + } + + int getTimestamp() const { + return mTimestamp; + } + + int getLevel() const { + return mLevel; + } + + int getCount() const { + return mCount; + } + + private: + // Default copy constructor and assign operator are used for using in std::vector. + DISALLOW_DEFAULT_CONSTRUCTOR(BigramProperty); + + // TODO: Make members const. + std::vector<int> mTargetCodePoints; + int mProbability; + int mTimestamp; + int mLevel; + int mCount; +}; +} // namespace latinime +#endif // LATINIME_WORD_PROPERTY_H diff --git a/native/jni/src/suggest/core/dictionary/property/unigram_property.h b/native/jni/src/suggest/core/dictionary/property/unigram_property.h new file mode 100644 index 000000000..d2551057b --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/property/unigram_property.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 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_UNIGRAM_PROPERTY_H +#define LATINIME_UNIGRAM_PROPERTY_H + +#include <vector> + +#include "defines.h" + +namespace latinime { + +class UnigramProperty { + public: + class ShortcutProperty { + public: + ShortcutProperty(const std::vector<int> *const targetCodePoints, const int probability) + : mTargetCodePoints(*targetCodePoints), mProbability(probability) {} + + const std::vector<int> *getTargetCodePoints() const { + return &mTargetCodePoints; + } + + int getProbability() const { + return mProbability; + } + + private: + // Default copy constructor and assign operator are used for using in std::vector. + DISALLOW_DEFAULT_CONSTRUCTOR(ShortcutProperty); + + // TODO: Make members const. + std::vector<int> mTargetCodePoints; + int mProbability; + }; + + UnigramProperty() + : mIsNotAWord(false), mIsBlacklisted(false), mProbability(NOT_A_PROBABILITY), + mTimestamp(NOT_A_TIMESTAMP), mLevel(0), mCount(0), mShortcuts() {} + + UnigramProperty(const bool isNotAWord, const bool isBlacklisted, const int probability, + const int timestamp, const int level, const int count, + const std::vector<ShortcutProperty> *const shortcuts) + : mIsNotAWord(isNotAWord), mIsBlacklisted(isBlacklisted), mProbability(probability), + mTimestamp(timestamp), mLevel(level), mCount(count), mShortcuts(*shortcuts) {} + + bool isNotAWord() const { + return mIsNotAWord; + } + + bool isBlacklisted() const { + return mIsBlacklisted; + } + + bool hasShortcuts() const { + return !mShortcuts.empty(); + } + + int getProbability() const { + return mProbability; + } + + int getTimestamp() const { + return mTimestamp; + } + + int getLevel() const { + return mLevel; + } + + int getCount() const { + return mCount; + } + + const std::vector<ShortcutProperty> &getShortcuts() const { + return mShortcuts; + } + + private: + // Default copy constructor is used for using as a return value. + DISALLOW_ASSIGNMENT_OPERATOR(UnigramProperty); + + // TODO: Make members const. + bool mIsNotAWord; + bool mIsBlacklisted; + int mProbability; + // Historical information + int mTimestamp; + int mLevel; + int mCount; + std::vector<ShortcutProperty> mShortcuts; +}; +} // namespace latinime +#endif // LATINIME_UNIGRAM_PROPERTY_H diff --git a/native/jni/src/suggest/core/dictionary/property/word_property.cpp b/native/jni/src/suggest/core/dictionary/property/word_property.cpp new file mode 100644 index 000000000..95608dcf8 --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/property/word_property.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/core/dictionary/property/word_property.h" + +namespace latinime { + +void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, + jbooleanArray outFlags, jintArray outProbabilityInfo, jobject outBigramTargets, + jobject outBigramProbabilities, jobject outShortcutTargets, + jobject outShortcutProbabilities) const { + env->SetIntArrayRegion(outCodePoints, 0 /* start */, mCodePoints.size(), &mCodePoints[0]); + + jboolean flags[] = {mUnigramProperty.isNotAWord(), mUnigramProperty.isBlacklisted(), + !mBigrams.empty(), mUnigramProperty.hasShortcuts()}; + env->SetBooleanArrayRegion(outFlags, 0 /* start */, NELEMS(flags), flags); + int probabilityInfo[] = {mUnigramProperty.getProbability(), mUnigramProperty.getTimestamp(), + mUnigramProperty.getLevel(), mUnigramProperty.getCount()}; + env->SetIntArrayRegion(outProbabilityInfo, 0 /* start */, NELEMS(probabilityInfo), + probabilityInfo); + + jclass integerClass = env->FindClass("java/lang/Integer"); + jmethodID intToIntegerConstructorId = env->GetMethodID(integerClass, "<init>", "(I)V"); + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + jmethodID addMethodId = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + + // Output bigrams. + for (const auto &bigramProperty : mBigrams) { + const std::vector<int> *const word1CodePoints = bigramProperty.getTargetCodePoints(); + jintArray bigramWord1CodePointArray = env->NewIntArray(word1CodePoints->size()); + env->SetIntArrayRegion(bigramWord1CodePointArray, 0 /* start */, + word1CodePoints->size(), word1CodePoints->data()); + env->CallBooleanMethod(outBigramTargets, addMethodId, bigramWord1CodePointArray); + env->DeleteLocalRef(bigramWord1CodePointArray); + + int bigramProbabilityInfo[] = {bigramProperty.getProbability(), + bigramProperty.getTimestamp(), bigramProperty.getLevel(), + bigramProperty.getCount()}; + jintArray bigramProbabilityInfoArray = env->NewIntArray(NELEMS(bigramProbabilityInfo)); + env->SetIntArrayRegion(bigramProbabilityInfoArray, 0 /* start */, + NELEMS(bigramProbabilityInfo), bigramProbabilityInfo); + env->CallBooleanMethod(outBigramProbabilities, addMethodId, bigramProbabilityInfoArray); + env->DeleteLocalRef(bigramProbabilityInfoArray); + } + + // Output shortcuts. + for (const auto &shortcut : mUnigramProperty.getShortcuts()) { + const std::vector<int> *const targetCodePoints = shortcut.getTargetCodePoints(); + jintArray shortcutTargetCodePointArray = env->NewIntArray(targetCodePoints->size()); + env->SetIntArrayRegion(shortcutTargetCodePointArray, 0 /* start */, + targetCodePoints->size(), targetCodePoints->data()); + env->CallBooleanMethod(outShortcutTargets, addMethodId, shortcutTargetCodePointArray); + env->DeleteLocalRef(shortcutTargetCodePointArray); + jobject integerProbability = env->NewObject(integerClass, intToIntegerConstructorId, + shortcut.getProbability()); + env->CallBooleanMethod(outShortcutProbabilities, addMethodId, integerProbability); + env->DeleteLocalRef(integerProbability); + } + env->DeleteLocalRef(integerClass); + env->DeleteLocalRef(arrayListClass); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/core/dictionary/property/word_property.h b/native/jni/src/suggest/core/dictionary/property/word_property.h new file mode 100644 index 000000000..5519a917c --- /dev/null +++ b/native/jni/src/suggest/core/dictionary/property/word_property.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 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_WORD_PROPERTY_H +#define LATINIME_WORD_PROPERTY_H + +#include <vector> + +#include "defines.h" +#include "jni.h" +#include "suggest/core/dictionary/property/bigram_property.h" +#include "suggest/core/dictionary/property/unigram_property.h" + +namespace latinime { + +// This class is used for returning information belonging to a word to java side. +class WordProperty { + public: + // Default constructor is used to create an instance that indicates an invalid word. + WordProperty() + : mCodePoints(), mUnigramProperty(), mBigrams() {} + + WordProperty(const std::vector<int> *const codePoints, + const UnigramProperty *const unigramProperty, + const std::vector<BigramProperty> *const bigrams) + : mCodePoints(*codePoints), mUnigramProperty(*unigramProperty), mBigrams(*bigrams) {} + + void outputProperties(JNIEnv *const env, jintArray outCodePoints, jbooleanArray outFlags, + jintArray outProbabilityInfo, jobject outBigramTargets, jobject outBigramProbabilities, + jobject outShortcutTargets, jobject outShortcutProbabilities) const; + + private: + // Default copy constructor is used for using as a return value. + DISALLOW_ASSIGNMENT_OPERATOR(WordProperty); + + const std::vector<int> mCodePoints; + const UnigramProperty mUnigramProperty; + const std::vector<BigramProperty> mBigrams; +}; +} // namespace latinime +#endif // LATINIME_WORD_PROPERTY_H diff --git a/native/jni/src/suggest/core/dictionary/shortcut_utils.h b/native/jni/src/suggest/core/dictionary/shortcut_utils.h deleted file mode 100644 index 9ccef020f..000000000 --- a/native/jni/src/suggest/core/dictionary/shortcut_utils.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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_SHORTCUT_UTILS -#define LATINIME_SHORTCUT_UTILS - -#include "defines.h" -#include "suggest/core/dicnode/dic_node_utils.h" -#include "suggest/core/dictionary/binary_dictionary_shortcut_iterator.h" - -namespace latinime { - -class ShortcutUtils { - public: - static int outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt, - int outputWordIndex, const int finalScore, int *const outputCodePoints, - int *const frequencies, int *const outputTypes, const bool sameAsTyped) { - int shortcutTarget[MAX_WORD_LENGTH]; - while (shortcutIt->hasNextShortcutTarget() && outputWordIndex < MAX_RESULTS) { - bool isWhilelist; - int shortcutTargetStringLength; - shortcutIt->nextShortcutTarget(MAX_WORD_LENGTH, shortcutTarget, - &shortcutTargetStringLength, &isWhilelist); - int shortcutScore; - int kind; - if (isWhilelist && sameAsTyped) { - shortcutScore = S_INT_MAX; - kind = Dictionary::KIND_WHITELIST; - } else { - // shortcut entry's score == its base entry's score - 1 - shortcutScore = finalScore; - // Protection against int underflow - shortcutScore = max(S_INT_MIN + 1, shortcutScore) - 1; - kind = Dictionary::KIND_SHORTCUT; - } - outputTypes[outputWordIndex] = kind; - frequencies[outputWordIndex] = shortcutScore; - frequencies[outputWordIndex] = max(S_INT_MIN + 1, shortcutScore) - 1; - const int startIndex2 = outputWordIndex * MAX_WORD_LENGTH; - DicNodeUtils::appendTwoWords(0, 0, shortcutTarget, shortcutTargetStringLength, - &outputCodePoints[startIndex2]); - ++outputWordIndex; - } - return outputWordIndex; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutUtils); -}; -} // namespace latinime -#endif // LATINIME_SHORTCUT_UTILS diff --git a/native/jni/src/suggest/core/layout/normal_distribution.h b/native/jni/src/suggest/core/layout/normal_distribution.h new file mode 100644 index 000000000..5f21a59c0 --- /dev/null +++ b/native/jni/src/suggest/core/layout/normal_distribution.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 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_NORMAL_DISTRIBUTION_H +#define LATINIME_NORMAL_DISTRIBUTION_H + +#include <cmath> + +#include "defines.h" + +namespace latinime { + +// Normal distribution N(u, sigma^2). +class NormalDistribution { + public: + NormalDistribution(const float u, const float sigma) + : mU(u), + mPreComputedNonExpPart(1.0f / sqrtf(2.0f * M_PI_F + * GeometryUtils::SQUARE_FLOAT(sigma))), + mPreComputedExponentPart(-1.0f / (2.0f * GeometryUtils::SQUARE_FLOAT(sigma))) {} + + float getProbabilityDensity(const float x) const { + const float shiftedX = x - mU; + return mPreComputedNonExpPart + * expf(mPreComputedExponentPart * GeometryUtils::SQUARE_FLOAT(shiftedX)); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(NormalDistribution); + + const float mU; // mean value + const float mPreComputedNonExpPart; // = 1 / sqrt(2 * PI * sigma^2) + const float mPreComputedExponentPart; // = -1 / (2 * sigma^2) +}; +} // namespace latinime +#endif // LATINIME_NORMAL_DISTRIBUTION_H diff --git a/native/jni/src/suggest/core/layout/normal_distribution_2d.h b/native/jni/src/suggest/core/layout/normal_distribution_2d.h new file mode 100644 index 000000000..3bc0a0153 --- /dev/null +++ b/native/jni/src/suggest/core/layout/normal_distribution_2d.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 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_NORMAL_DISTRIBUTION_2D_H +#define LATINIME_NORMAL_DISTRIBUTION_2D_H + +#include <cmath> + +#include "defines.h" +#include "suggest/core/layout/geometry_utils.h" +#include "suggest/core/layout/normal_distribution.h" + +namespace latinime { + +// Normal distribution on a 2D plane. The covariance is always zero, but the distribution can be +// rotated. +class NormalDistribution2D { + public: + NormalDistribution2D(const float uX, const float sigmaX, const float uY, const float sigmaY, + const float theta) + : mXDistribution(0.0f, sigmaX), mYDistribution(0.0f, sigmaY), mUX(uX), mUY(uY), + mSinTheta(sinf(theta)), mCosTheta(cosf(theta)) {} + + float getProbabilityDensity(const float x, const float y) const { + // Shift + const float shiftedX = x - mUX; + const float shiftedY = y - mUY; + // Rotate + const float rotatedShiftedX = mCosTheta * shiftedX + mSinTheta * shiftedY; + const float rotatedShiftedY = -mSinTheta * shiftedX + mCosTheta * shiftedY; + return mXDistribution.getProbabilityDensity(rotatedShiftedX) + * mYDistribution.getProbabilityDensity(rotatedShiftedY); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(NormalDistribution2D); + + const NormalDistribution mXDistribution; + const NormalDistribution mYDistribution; + const float mUX; + const float mUY; + const float mSinTheta; + const float mCosTheta; +}; +} // namespace latinime +#endif // LATINIME_NORMAL_DISTRIBUTION_2D_H diff --git a/native/jni/src/suggest/core/layout/proximity_info.cpp b/native/jni/src/suggest/core/layout/proximity_info.cpp index e64476d82..c40a2bdca 100644 --- a/native/jni/src/suggest/core/layout/proximity_info.cpp +++ b/native/jni/src/suggest/core/layout/proximity_info.cpp @@ -18,6 +18,7 @@ #include "suggest/core/layout/proximity_info.h" +#include <algorithm> #include <cstring> #include <cmath> @@ -57,13 +58,12 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const jfloatArray sweetSpotCenterYs, const jfloatArray sweetSpotRadii) : GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight), MOST_COMMON_KEY_WIDTH(mostCommonKeyWidth), MOST_COMMON_KEY_WIDTH_SQUARE(mostCommonKeyWidth * mostCommonKeyWidth), - MOST_COMMON_KEY_HEIGHT(mostCommonKeyHeight), NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE(1.0f + GeometryUtils::SQUARE_FLOAT(static_cast<float>(mostCommonKeyHeight) / static_cast<float>(mostCommonKeyWidth))), CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight), - KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), + KEY_COUNT(std::min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight), KEYBOARD_HYPOTENUSE(hypotf(KEYBOARD_WIDTH, KEYBOARD_HEIGHT)), HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates @@ -71,7 +71,7 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, && sweetSpotCenterYs && sweetSpotRadii), mProximityCharsArray(new int[GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE /* proximityCharsLength */]), - mCodeToKeyMap() { + mLowerCodePointToKeyMap() { /* Let's check the input array length here to make sure */ const jsize proximityCharsLength = env->GetArrayLength(proximityChars); if (proximityCharsLength != GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE) { @@ -147,7 +147,14 @@ int ProximityInfo::getCodePointOf(const int keyIndex) const { if (keyIndex < 0 || keyIndex >= KEY_COUNT) { return NOT_A_CODE_POINT; } - return mKeyIndexToCodePointG[keyIndex]; + return mKeyIndexToLowerCodePointG[keyIndex]; +} + +int ProximityInfo::getOriginalCodePointOf(const int keyIndex) const { + if (keyIndex < 0 || keyIndex >= KEY_COUNT) { + return NOT_A_CODE_POINT; + } + return mKeyIndexToOriginalCodePoint[keyIndex]; } void ProximityInfo::initializeG() { @@ -164,8 +171,9 @@ void ProximityInfo::initializeG() { const float gapY = sweetSpotCenterY - mCenterYsG[i]; mSweetSpotCenterYsG[i] = static_cast<int>(mCenterYsG[i] + gapY * verticalScale); } - mCodeToKeyMap[lowerCode] = i; - mKeyIndexToCodePointG[i] = lowerCode; + mLowerCodePointToKeyMap[lowerCode] = i; + mKeyIndexToOriginalCodePoint[i] = code; + mKeyIndexToLowerCodePointG[i] = lowerCode; } for (int i = 0; i < KEY_COUNT; i++) { mKeyKeyDistancesG[i][i] = 0; diff --git a/native/jni/src/suggest/core/layout/proximity_info.h b/native/jni/src/suggest/core/layout/proximity_info.h index f25949001..d4e453736 100644 --- a/native/jni/src/suggest/core/layout/proximity_info.h +++ b/native/jni/src/suggest/core/layout/proximity_info.h @@ -17,10 +17,11 @@ #ifndef LATINIME_PROXIMITY_INFO_H #define LATINIME_PROXIMITY_INFO_H +#include <unordered_map> + #include "defines.h" #include "jni.h" #include "suggest/core/layout/proximity_info_utils.h" -#include "utils/hash_map_compat.h" namespace latinime { @@ -35,10 +36,10 @@ class ProximityInfo { const jfloatArray sweetSpotCenterYs, const jfloatArray sweetSpotRadii); ~ProximityInfo(); bool hasSpaceProximity(const int x, const int y) const; - int getNormalizedSquaredDistance(const int inputIndex, const int proximityIndex) const; float getNormalizedSquaredDistanceFromCenterFloatG( const int keyId, const int x, const int y, const bool isGeometric) const; int getCodePointOf(const int keyIndex) const; + int getOriginalCodePointOf(const int keyIndex) const; bool hasSweetSpotData(const int keyIndex) const { // When there are no calibration data for a key, // the radius of the key is assigned to zero. @@ -47,8 +48,6 @@ class ProximityInfo { float getSweetSpotRadiiAt(int keyIndex) const { return mSweetSpotRadii[keyIndex]; } float getSweetSpotCenterXAt(int keyIndex) const { return mSweetSpotCenterXs[keyIndex]; } float getSweetSpotCenterYAt(int keyIndex) const { return mSweetSpotCenterYs[keyIndex]; } - void calculateNearbyKeyCodes( - const int x, const int y, const int primaryKey, int *inputCodes) const; bool hasTouchPositionCorrectionData() const { return HAS_TOUCH_POSITION_CORRECTION_DATA; } int getMostCommonKeyWidth() const { return MOST_COMMON_KEY_WIDTH; } int getMostCommonKeyWidthSquare() const { return MOST_COMMON_KEY_WIDTH_SQUARE; } @@ -76,11 +75,11 @@ class ProximityInfo { ProximityInfoUtils::initializeProximities(inputCodes, inputXCoordinates, inputYCoordinates, inputSize, mKeyXCoordinates, mKeyYCoordinates, mKeyWidths, mKeyHeights, mProximityCharsArray, CELL_HEIGHT, CELL_WIDTH, GRID_WIDTH, MOST_COMMON_KEY_WIDTH, - KEY_COUNT, mLocaleStr, &mCodeToKeyMap, allInputCodes); + KEY_COUNT, mLocaleStr, &mLowerCodePointToKeyMap, allInputCodes); } AK_FORCE_INLINE int getKeyIndexOf(const int c) const { - return ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, c, &mCodeToKeyMap); + return ProximityInfoUtils::getKeyIndexOf(KEY_COUNT, c, &mLowerCodePointToKeyMap); } AK_FORCE_INLINE bool isCodePointOnKeyboard(const int codePoint) const { @@ -96,7 +95,6 @@ class ProximityInfo { const int GRID_HEIGHT; const int MOST_COMMON_KEY_WIDTH; const int MOST_COMMON_KEY_WIDTH_SQUARE; - const int MOST_COMMON_KEY_HEIGHT; const float NORMALIZED_SQUARED_MOST_COMMON_KEY_HYPOTENUSE; const int CELL_WIDTH; const int CELL_HEIGHT; @@ -105,6 +103,8 @@ class ProximityInfo { const int KEYBOARD_HEIGHT; const float KEYBOARD_HYPOTENUSE; const bool HAS_TOUCH_POSITION_CORRECTION_DATA; + // Assuming locale strings such as en_US, sr-Latn etc. + static const int MAX_LOCALE_STRING_LENGTH = 10; char mLocaleStr[MAX_LOCALE_STRING_LENGTH]; int *mProximityCharsArray; int mKeyXCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD]; @@ -117,13 +117,12 @@ class ProximityInfo { // Sweet spots for geometric input. Note that we have extra sweet spots only for Y coordinates. float mSweetSpotCenterYsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; float mSweetSpotRadii[MAX_KEY_COUNT_IN_A_KEYBOARD]; - hash_map_compat<int, int> mCodeToKeyMap; - - int mKeyIndexToCodePointG[MAX_KEY_COUNT_IN_A_KEYBOARD]; + std::unordered_map<int, int> mLowerCodePointToKeyMap; + int mKeyIndexToOriginalCodePoint[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int mKeyIndexToLowerCodePointG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mCenterXsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mCenterYsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mKeyKeyDistancesG[MAX_KEY_COUNT_IN_A_KEYBOARD][MAX_KEY_COUNT_IN_A_KEYBOARD]; - // TODO: move to correction.h }; } // namespace latinime #endif // LATINIME_PROXIMITY_INFO_H diff --git a/native/jni/src/suggest/core/layout/proximity_info_params.cpp b/native/jni/src/suggest/core/layout/proximity_info_params.cpp index 49df10301..68bb0ae9d 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_params.cpp +++ b/native/jni/src/suggest/core/layout/proximity_info_params.cpp @@ -24,9 +24,6 @@ const float ProximityInfoParams::VERTICAL_SWEET_SPOT_SCALE = 1.0f; const float ProximityInfoParams::VERTICAL_SWEET_SPOT_SCALE_G = 0.5f; /* Per method constants */ -// Used by ProximityInfoStateUtils::initGeometricDistanceInfos() -const float ProximityInfoParams::NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; - // Used by ProximityInfoStateUtils::updateNearKeysDistances() const float ProximityInfoParams::NEAR_KEY_THRESHOLD_FOR_DISTANCE = 2.0f; @@ -50,7 +47,7 @@ const int ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION = 2; const int ProximityInfoParams::LAST_POINT_SKIP_DISTANCE_SCALE = 4; // Used by ProximityInfoStateUtils::updateAlignPointProbabilities() -const float ProximityInfoParams::MIN_PROBABILITY = 0.000001f; +const float ProximityInfoParams::MIN_PROBABILITY = 0.000005f; const float ProximityInfoParams::MAX_SKIP_PROBABILITY = 0.95f; const float ProximityInfoParams::SKIP_FIRST_POINT_PROBABILITY = 0.01f; const float ProximityInfoParams::SKIP_LAST_POINT_PROBABILITY = 0.1f; @@ -76,8 +73,12 @@ const float ProximityInfoParams::MAX_SPEEDxANGLE_RATE_FOR_STANDARD_DEVIATION = 0 const float ProximityInfoParams::SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION = 0.5f; const float ProximityInfoParams::MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION = 0.15f; const float ProximityInfoParams::MIN_STANDARD_DEVIATION = 0.37f; -const float ProximityInfoParams::PREV_DISTANCE_WEIGHT = 0.5f; -const float ProximityInfoParams::NEXT_DISTANCE_WEIGHT = 0.6f; +const float ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_FIRST = 1.25f; +const float ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_FIRST = 0.85f; +const float ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_LAST = 1.4f; +const float ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_LAST = 0.95f; +const float ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT = 1.1f; +const float ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT = 0.95f; // Used by ProximityInfoStateUtils::suppressCharProbabilities() const float ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT = 1.5f; @@ -98,7 +99,4 @@ const int ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE = 50; const int ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS = 150; const int ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600; -// Used by ProximityInfoStateUtils::calculateNormalizedSquaredDistance() -const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 1 << 10; - } // namespace latinime diff --git a/native/jni/src/suggest/core/layout/proximity_info_params.h b/native/jni/src/suggest/core/layout/proximity_info_params.h index ae1f82c22..d9515c837 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_params.h +++ b/native/jni/src/suggest/core/layout/proximity_info_params.h @@ -28,9 +28,6 @@ class ProximityInfoParams { static const float VERTICAL_SWEET_SPOT_SCALE; static const float VERTICAL_SWEET_SPOT_SCALE_G; - // Used by ProximityInfoStateUtils::initGeometricDistanceInfos() - static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD; - // Used by ProximityInfoStateUtils::updateNearKeysDistances() static const float NEAR_KEY_THRESHOLD_FOR_DISTANCE; @@ -78,8 +75,13 @@ class ProximityInfoParams { static const float SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION; static const float MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION; static const float MIN_STANDARD_DEVIATION; - static const float PREV_DISTANCE_WEIGHT; - static const float NEXT_DISTANCE_WEIGHT; + // X means gesture's direction. Y means gesture's orthogonal direction. + static const float STANDARD_DEVIATION_X_WEIGHT_FOR_FIRST; + static const float STANDARD_DEVIATION_Y_WEIGHT_FOR_FIRST; + static const float STANDARD_DEVIATION_X_WEIGHT_FOR_LAST; + static const float STANDARD_DEVIATION_Y_WEIGHT_FOR_LAST; + static const float STANDARD_DEVIATION_X_WEIGHT; + static const float STANDARD_DEVIATION_Y_WEIGHT; // Used by ProximityInfoStateUtils::suppressCharProbabilities() static const float SUPPRESSION_LENGTH_WEIGHT; diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.cpp b/native/jni/src/suggest/core/layout/proximity_info_state.cpp index fbabd92f2..91469e26d 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state.cpp +++ b/native/jni/src/suggest/core/layout/proximity_info_state.cpp @@ -18,8 +18,10 @@ #include "suggest/core/layout/proximity_info_state.h" -#include <cstring> // for memset() and memcpy() +#include <algorithm> +#include <cstring> // for memset() and memmove() #include <sstream> // for debug prints +#include <unordered_map> #include <vector> #include "defines.h" @@ -30,6 +32,12 @@ namespace latinime { +int ProximityInfoState::getPrimaryOriginalCodePointAt(const int index) const { + const int primaryCodePoint = getPrimaryCodePointAt(index); + const int keyIndex = mProximityInfo->getKeyIndexOf(primaryCodePoint); + return mProximityInfo->getOriginalCodePointOf(keyIndex); +} + // TODO: Remove the dependency of "isGeometric" void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength, const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize, @@ -84,7 +92,6 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi mSampledInputIndice.clear(); mSampledLengthCache.clear(); mSampledNormalizedSquaredLengthCache.clear(); - mSampledNearKeySets.clear(); mSampledSearchKeySets.clear(); mSpeedRates.clear(); mBeelineSpeedPercentiles.clear(); @@ -119,18 +126,17 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi if (mSampledInputSize > 0) { ProximityInfoStateUtils::initGeometricDistanceInfos(mProximityInfo, mSampledInputSize, lastSavedInputSize, isGeometric, &mSampledInputXs, &mSampledInputYs, - &mSampledNearKeySets, &mSampledNormalizedSquaredLengthCache); + &mSampledNormalizedSquaredLengthCache); if (isGeometric) { // updates probabilities of skipping or mapping each key for all points. ProximityInfoStateUtils::updateAlignPointProbabilities( mMaxPointToKeyLength, mProximityInfo->getMostCommonKeyWidth(), mProximityInfo->getKeyCount(), lastSavedInputSize, mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSpeedRates, &mSampledLengthCache, - &mSampledNormalizedSquaredLengthCache, &mSampledNearKeySets, - &mCharProbabilities); + &mSampledNormalizedSquaredLengthCache, mProximityInfo, &mCharProbabilities); ProximityInfoStateUtils::updateSampledSearchKeySets(mProximityInfo, mSampledInputSize, lastSavedInputSize, &mSampledLengthCache, - &mSampledNearKeySets, &mSampledSearchKeySets, + &mCharProbabilities, &mSampledSearchKeySets, &mSampledSearchKeyVectors); mMostProbableStringProbability = ProximityInfoStateUtils::getMostProbableString( mProximityInfo, mSampledInputSize, &mCharProbabilities, mMostProbableString); @@ -165,7 +171,7 @@ float ProximityInfoState::getPointToKeyLength( const int keyId = mProximityInfo->getKeyIndexOf(codePoint); if (keyId != NOT_AN_INDEX) { const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; - return min(mSampledNormalizedSquaredLengthCache[index], mMaxPointToKeyLength); + return std::min(mSampledNormalizedSquaredLengthCache[index], mMaxPointToKeyLength); } if (CharUtils::isIntentionalOmissionCodePoint(codePoint)) { return 0.0f; @@ -249,6 +255,14 @@ ProximityType ProximityInfoState::getProximityTypeG(const int index, const int c if (!isUsed()) { return UNRELATED_CHAR; } + const int sampledSearchKeyVectorsSize = static_cast<int>(mSampledSearchKeyVectors.size()); + if (index < 0 || index >= sampledSearchKeyVectorsSize) { + AKLOGE("getProximityTypeG() is called with an invalid index(%d). " + "mSampledSearchKeyVectors.size() = %d, codePoint = %x.", index, + sampledSearchKeyVectorsSize, codePoint); + ASSERT(false); + return UNRELATED_CHAR; + } const int lowerCodePoint = CharUtils::toLowerCase(codePoint); const int baseLowerCodePoint = CharUtils::toBaseCodePoint(lowerCodePoint); for (int i = 0; i < static_cast<int>(mSampledSearchKeyVectors[index].size()); ++i) { @@ -271,7 +285,7 @@ float ProximityInfoState::getDirection(const int index0, const int index1) const } float ProximityInfoState::getMostProbableString(int *const codePointBuf) const { - memcpy(codePointBuf, mMostProbableString, sizeof(mMostProbableString)); + memmove(codePointBuf, mMostProbableString, sizeof(mMostProbableString)); return mMostProbableStringProbability; } @@ -283,7 +297,7 @@ bool ProximityInfoState::hasSpaceProximity(const int index) const { // Returns a probability of mapping index to keyIndex. float ProximityInfoState::getProbability(const int index, const int keyIndex) const { ASSERT(0 <= index && index < mSampledInputSize); - hash_map_compat<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex); + std::unordered_map<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex); if (it != mCharProbabilities[index].end()) { return it->second; } diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.h b/native/jni/src/suggest/core/layout/proximity_info_state.h index c94060fa9..6b1a319aa 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state.h +++ b/native/jni/src/suggest/core/layout/proximity_info_state.h @@ -18,12 +18,12 @@ #define LATINIME_PROXIMITY_INFO_STATE_H #include <cstring> // for memset() +#include <unordered_map> #include <vector> #include "defines.h" #include "suggest/core/layout/proximity_info_params.h" #include "suggest/core/layout/proximity_info_state_utils.h" -#include "utils/hash_map_compat.h" namespace latinime { @@ -43,16 +43,16 @@ class ProximityInfoState { // Defined here // ///////////////////////////////////////// AK_FORCE_INLINE ProximityInfoState() - : mProximityInfo(0), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f), + : mProximityInfo(nullptr), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f), mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0), mIsContinuousSuggestionPossible(false), mHasBeenUpdatedByGeometricInput(false), mSampledInputXs(), mSampledInputYs(), mSampledTimes(), mSampledInputIndice(), mSampledLengthCache(), mBeelineSpeedPercentiles(), mSampledNormalizedSquaredLengthCache(), mSpeedRates(), mDirections(), - mCharProbabilities(), mSampledNearKeySets(), mSampledSearchKeySets(), - mSampledSearchKeyVectors(), mTouchPositionCorrectionEnabled(false), - mSampledInputSize(0), mMostProbableStringProbability(0.0f) { + mCharProbabilities(), mSampledSearchKeySets(), mSampledSearchKeyVectors(), + mTouchPositionCorrectionEnabled(false), mSampledInputSize(0), + mMostProbableStringProbability(0.0f) { memset(mInputProximities, 0, sizeof(mInputProximities)); memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); memset(mMostProbableString, 0, sizeof(mMostProbableString)); @@ -65,6 +65,8 @@ class ProximityInfoState { return getProximityCodePointsAt(index)[0]; } + int getPrimaryOriginalCodePointAt(const int index) const; + inline bool sameAsTyped(const int *word, int length) const { if (length != mSampledInputSize) { return false; @@ -106,10 +108,6 @@ class ProximityInfoState { return false; } - inline const int *getPrimaryInputWord() const { - return mPrimaryInputWord; - } - inline bool touchPositionCorrectionEnabled() const { return mTouchPositionCorrectionEnabled; } @@ -154,10 +152,6 @@ class ProximityInfoState { ProximityType getProximityTypeG(const int index, const int codePoint) const; - const std::vector<int> *getSearchKeyVector(const int index) const { - return &mSampledSearchKeyVectors[index]; - } - float getSpeedRate(const int index) const { return mSpeedRates[index]; } @@ -221,11 +215,7 @@ class ProximityInfoState { std::vector<float> mSpeedRates; std::vector<float> mDirections; // probabilities of skipping or mapping to a key for each point. - std::vector<hash_map_compat<int, float> > mCharProbabilities; - // The vector for the key code set which holds nearby keys for each sampled input point - // 1. Used to calculate the probability of the key - // 2. Used to calculate mSampledSearchKeySets - std::vector<ProximityInfoStateUtils::NearKeycodesSet> mSampledNearKeySets; + std::vector<std::unordered_map<int, float> > mCharProbabilities; // The vector for the key code set which holds nearby keys of some trailing sampled input points // for each sampled input point. These nearby keys contain the next characters which can be in // the dictionary. Specifically, currently we are looking for keys nearby trailing sampled diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp index e1b35340b..ea3b02216 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp +++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp @@ -16,13 +16,16 @@ #include "suggest/core/layout/proximity_info_state_utils.h" +#include <algorithm> #include <cmath> #include <cstring> // for memset() #include <sstream> // for debug prints +#include <unordered_map> #include <vector> #include "defines.h" #include "suggest/core/layout/geometry_utils.h" +#include "suggest/core/layout/normal_distribution_2d.h" #include "suggest/core/layout/proximity_info.h" #include "suggest/core/layout/proximity_info_params.h" @@ -186,13 +189,10 @@ namespace latinime { const int lastSavedInputSize, const bool isGeometric, const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, - std::vector<NearKeycodesSet> *sampledNearKeySets, std::vector<float> *sampledNormalizedSquaredLengthCache) { - sampledNearKeySets->resize(sampledInputSize); const int keyCount = proximityInfo->getKeyCount(); sampledNormalizedSquaredLengthCache->resize(sampledInputSize * keyCount); for (int i = lastSavedInputSize; i < sampledInputSize; ++i) { - (*sampledNearKeySets)[i].reset(); for (int k = 0; k < keyCount; ++k) { const int index = i * keyCount + k; const int x = (*sampledInputXs)[i]; @@ -201,10 +201,6 @@ namespace latinime { proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG( k, x, y, isGeometric); (*sampledNormalizedSquaredLengthCache)[index] = normalizedSquaredDistance; - if (normalizedSquaredDistance - < ProximityInfoParams::NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { - (*sampledNearKeySets)[i][k] = true; - } } } } @@ -240,7 +236,7 @@ namespace latinime { // Calculate velocity by using distances and durations of // ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION points for both forward and // backward. - const int forwardNumPoints = min(inputSize - 1, + const int forwardNumPoints = std::min(inputSize - 1, index + ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION); for (int j = index; j < forwardNumPoints; ++j) { if (i < sampledInputSize - 1 && j >= (*sampledInputIndice)[i + 1]) { @@ -250,7 +246,7 @@ namespace latinime { xCoordinates[j + 1], yCoordinates[j + 1]); duration += times[j + 1] - times[j]; } - const int backwardNumPoints = max(0, + const int backwardNumPoints = std::max(0, index - ProximityInfoParams::NUM_POINTS_FOR_SPEED_CALCULATION); for (int j = index - 1; j >= backwardNumPoints; --j) { if (i > 0 && j < (*sampledInputIndice)[i - 1]) { @@ -272,7 +268,7 @@ namespace latinime { // Direction calculation. sampledDirections->resize(sampledInputSize - 1); - for (int i = max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) { + for (int i = std::max(0, lastSavedInputSize - 1); i < sampledInputSize - 1; ++i) { (*sampledDirections)[i] = getDirection(sampledInputXs, sampledInputYs, i, i + 1); } return averageSpeed; @@ -609,7 +605,7 @@ namespace latinime { const int inputIndex, const int keyId) { if (keyId != NOT_AN_INDEX) { const int index = inputIndex * keyCount + keyId; - return min((*sampledNormalizedSquaredLengthCache)[index], maxPointToKeyLength); + return std::min((*sampledNormalizedSquaredLengthCache)[index], maxPointToKeyLength); } // If the char is not a key on the keyboard then return the max length. return static_cast<float>(MAX_VALUE_FOR_WEIGHTING); @@ -624,8 +620,8 @@ namespace latinime { const std::vector<float> *const sampledSpeedRates, const std::vector<int> *const sampledLengthCache, const std::vector<float> *const sampledNormalizedSquaredLengthCache, - std::vector<NearKeycodesSet> *sampledNearKeySets, - std::vector<hash_map_compat<int, float> > *charProbabilities) { + const ProximityInfo *const proximityInfo, + std::vector<std::unordered_map<int, float> > *charProbabilities) { charProbabilities->resize(sampledInputSize); // Calculates probabilities of using a point as a correlated point with the character // for each point. @@ -640,23 +636,21 @@ namespace latinime { float nearestKeyDistance = static_cast<float>(MAX_VALUE_FOR_WEIGHTING); for (int j = 0; j < keyCount; ++j) { - if ((*sampledNearKeySets)[i].test(j)) { - const float distance = getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j); - if (distance < nearestKeyDistance) { - nearestKeyDistance = distance; - } + const float distance = getPointToKeyByIdLength( + maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j); + if (distance < nearestKeyDistance) { + nearestKeyDistance = distance; } } if (i == 0) { - skipProbability *= min(1.0f, + skipProbability *= std::min(1.0f, nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT + ProximityInfoParams::NEAREST_DISTANCE_BIAS); // Promote the first point skipProbability *= ProximityInfoParams::SKIP_FIRST_POINT_PROBABILITY; } else if (i == sampledInputSize - 1) { - skipProbability *= min(1.0f, + skipProbability *= std::min(1.0f, nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT_FOR_LAST + ProximityInfoParams::NEAREST_DISTANCE_BIAS_FOR_LAST); // Promote the last point @@ -667,17 +661,17 @@ namespace latinime { && speedRate < (*sampledSpeedRates)[i + 1] - ProximityInfoParams::SPEED_MARGIN) { if (currentAngle < ProximityInfoParams::CORNER_ANGLE_THRESHOLD) { - skipProbability *= min(1.0f, speedRate + skipProbability *= std::min(1.0f, speedRate * ProximityInfoParams::SLOW_STRAIGHT_WEIGHT_FOR_SKIP_PROBABILITY); } else { // If the angle is small enough, we promote this point more. (e.g. pit vs put) - skipProbability *= min(1.0f, + skipProbability *= std::min(1.0f, speedRate * ProximityInfoParams::SPEED_WEIGHT_FOR_SKIP_PROBABILITY + ProximityInfoParams::MIN_SPEED_RATE_FOR_SKIP_PROBABILITY); } } - skipProbability *= min(1.0f, + skipProbability *= std::min(1.0f, speedRate * nearestKeyDistance * ProximityInfoParams::NEAREST_DISTANCE_WEIGHT + ProximityInfoParams::NEAREST_DISTANCE_BIAS); @@ -707,93 +701,57 @@ namespace latinime { // (1.0f - skipProbability). const float inputCharProbability = 1.0f - skipProbability; - const float speedxAngleRate = min(speedRate * currentAngle / M_PI_F + const float speedMultipliedByAngleRate = std::min(speedRate * currentAngle / M_PI_F * ProximityInfoParams::SPEEDxANGLE_WEIGHT_FOR_STANDARD_DEVIATION, ProximityInfoParams::MAX_SPEEDxANGLE_RATE_FOR_STANDARD_DEVIATION); - const float speedxNearestKeyDistanceRate = min(speedRate * nearestKeyDistance - * ProximityInfoParams::SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION, - ProximityInfoParams::MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION); - const float sigma = speedxAngleRate + speedxNearestKeyDistanceRate - + ProximityInfoParams::MIN_STANDARD_DEVIATION; - - ProximityInfoUtils::NormalDistribution - distribution(ProximityInfoParams::CENTER_VALUE_OF_NORMALIZED_DISTRIBUTION, sigma); + const float speedMultipliedByNearestKeyDistanceRate = std::min( + speedRate * nearestKeyDistance + * ProximityInfoParams::SPEEDxNEAREST_WEIGHT_FOR_STANDARD_DEVIATION, + ProximityInfoParams::MAX_SPEEDxNEAREST_RATE_FOR_STANDARD_DEVIATION); + const float sigma = (speedMultipliedByAngleRate + speedMultipliedByNearestKeyDistanceRate + + ProximityInfoParams::MIN_STANDARD_DEVIATION) * mostCommonKeyWidth; + float theta = 0.0f; + // TODO: Use different metrics to compute sigmas. + float sigmaX = sigma; + float sigmaY = sigma; + if (i == 0 && i != sampledInputSize - 1) { + // First point + theta = getDirection(sampledInputXs, sampledInputYs, i + 1, i); + sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_FIRST; + sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_FIRST; + } else { + if (i == sampledInputSize - 1) { + // Last point + sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT_FOR_LAST; + sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT_FOR_LAST; + } else { + sigmaX *= ProximityInfoParams::STANDARD_DEVIATION_X_WEIGHT; + sigmaY *= ProximityInfoParams::STANDARD_DEVIATION_Y_WEIGHT; + } + theta = getDirection(sampledInputXs, sampledInputYs, i, i - 1); + } + NormalDistribution2D distribution((*sampledInputXs)[i], sigmaX, (*sampledInputYs)[i], + sigmaY, theta); // Summing up probability densities of all near keys. float sumOfProbabilityDensities = 0.0f; for (int j = 0; j < keyCount; ++j) { - if ((*sampledNearKeySets)[i].test(j)) { - float distance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j)); - if (i == 0 && i != sampledInputSize - 1) { - // For the first point, weighted average of distances from first point and the - // next point to the key is used as a point to key distance. - const float nextDistance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, - i + 1, j)); - if (nextDistance < distance) { - // The distance of the first point tends to bigger than continuing - // points because the first touch by the user can be sloppy. - // So we promote the first point if the distance of that point is larger - // than the distance of the next point. - distance = (distance - + nextDistance * ProximityInfoParams::NEXT_DISTANCE_WEIGHT) - / (1.0f + ProximityInfoParams::NEXT_DISTANCE_WEIGHT); - } - } else if (i != 0 && i == sampledInputSize - 1) { - // For the first point, weighted average of distances from last point and - // the previous point to the key is used as a point to key distance. - const float previousDistance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, - i - 1, j)); - if (previousDistance < distance) { - // The distance of the last point tends to bigger than continuing points - // because the last touch by the user can be sloppy. So we promote the - // last point if the distance of that point is larger than the distance of - // the previous point. - distance = (distance - + previousDistance * ProximityInfoParams::PREV_DISTANCE_WEIGHT) - / (1.0f + ProximityInfoParams::PREV_DISTANCE_WEIGHT); - } - } - // TODO: Promote the first point when the extended line from the next input is near - // from a key. Also, promote the last point as well. - sumOfProbabilityDensities += distribution.getProbabilityDensity(distance); - } + sumOfProbabilityDensities += distribution.getProbabilityDensity( + proximityInfo->getKeyCenterXOfKeyIdG(j, + NOT_A_COORDINATE /* referencePointX */, true /* isGeometric */), + proximityInfo->getKeyCenterYOfKeyIdG(j, + NOT_A_COORDINATE /* referencePointY */, true /* isGeometric */)); } // Split the probability of an input point to keys that are close to the input point. for (int j = 0; j < keyCount; ++j) { - if ((*sampledNearKeySets)[i].test(j)) { - float distance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, i, j)); - if (i == 0 && i != sampledInputSize - 1) { - // For the first point, weighted average of distances from the first point and - // the next point to the key is used as a point to key distance. - const float prevDistance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, - i + 1, j)); - if (prevDistance < distance) { - distance = (distance - + prevDistance * ProximityInfoParams::NEXT_DISTANCE_WEIGHT) - / (1.0f + ProximityInfoParams::NEXT_DISTANCE_WEIGHT); - } - } else if (i != 0 && i == sampledInputSize - 1) { - // For the first point, weighted average of distances from last point and - // the previous point to the key is used as a point to key distance. - const float prevDistance = sqrtf(getPointToKeyByIdLength( - maxPointToKeyLength, sampledNormalizedSquaredLengthCache, keyCount, - i - 1, j)); - if (prevDistance < distance) { - distance = (distance - + prevDistance * ProximityInfoParams::PREV_DISTANCE_WEIGHT) - / (1.0f + ProximityInfoParams::PREV_DISTANCE_WEIGHT); - } - } - const float probabilityDensity = distribution.getProbabilityDensity(distance); - const float probability = inputCharProbability * probabilityDensity - / sumOfProbabilityDensities; - (*charProbabilities)[i][j] = probability; - } + const float probabilityDensity = distribution.getProbabilityDensity( + proximityInfo->getKeyCenterXOfKeyIdG(j, + NOT_A_COORDINATE /* referencePointX */, true /* isGeometric */), + proximityInfo->getKeyCenterYOfKeyIdG(j, + NOT_A_COORDINATE /* referencePointY */, true /* isGeometric */)); + const float probability = inputCharProbability * probabilityDensity + / sumOfProbabilityDensities; + (*charProbabilities)[i][j] = probability; } } @@ -805,7 +763,7 @@ namespace latinime { sstream << "Speed: "<< (*sampledSpeedRates)[i] << ", "; sstream << "Angle: "<< getPointAngle(sampledInputXs, sampledInputYs, i) << ", \n"; - for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].begin(); + for (std::unordered_map<int, float>::iterator it = (*charProbabilities)[i].begin(); it != (*charProbabilities)[i].end(); ++it) { if (it->first == NOT_AN_INDEX) { sstream << it->first @@ -827,7 +785,7 @@ namespace latinime { // Decrease key probabilities of points which don't have the highest probability of that key // among nearby points. Probabilities of the first point and the last point are not suppressed. - for (int i = max(start, 1); i < sampledInputSize; ++i) { + for (int i = std::max(start, 1); i < sampledInputSize; ++i) { for (int j = i + 1; j < sampledInputSize; ++j) { if (!suppressCharProbabilities( mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, @@ -835,7 +793,7 @@ namespace latinime { break; } } - for (int j = i - 1; j >= max(start, 0); --j) { + for (int j = i - 1; j >= std::max(start, 0); --j) { if (!suppressCharProbabilities( mostCommonKeyWidth, sampledInputSize, sampledLengthCache, i, j, charProbabilities)) { @@ -847,12 +805,11 @@ namespace latinime { // Converting from raw probabilities to log probabilities to calculate spatial distance. for (int i = start; i < sampledInputSize; ++i) { for (int j = 0; j < keyCount; ++j) { - hash_map_compat<int, float>::iterator it = (*charProbabilities)[i].find(j); + std::unordered_map<int, float>::iterator it = (*charProbabilities)[i].find(j); if (it == (*charProbabilities)[i].end()){ - (*sampledNearKeySets)[i].reset(j); + continue; } else if(it->second < ProximityInfoParams::MIN_PROBABILITY) { // Erases from near keys vector because it has very low probability. - (*sampledNearKeySets)[i].reset(j); (*charProbabilities)[i].erase(j); } else { it->second = -logf(it->second); @@ -864,9 +821,8 @@ namespace latinime { /* static */ void ProximityInfoStateUtils::updateSampledSearchKeySets( const ProximityInfo *const proximityInfo, const int sampledInputSize, - const int lastSavedInputSize, - const std::vector<int> *const sampledLengthCache, - const std::vector<NearKeycodesSet> *const sampledNearKeySets, + const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache, + const std::vector<std::unordered_map<int, float> > *const charProbabilities, std::vector<NearKeycodesSet> *sampledSearchKeySets, std::vector<std::vector<int> > *sampledSearchKeyVectors) { sampledSearchKeySets->resize(sampledInputSize); @@ -878,12 +834,17 @@ namespace latinime { if (i >= lastSavedInputSize) { (*sampledSearchKeySets)[i].reset(); } - for (int j = max(i, lastSavedInputSize); j < sampledInputSize; ++j) { + for (int j = std::max(i, lastSavedInputSize); j < sampledInputSize; ++j) { // TODO: Investigate if this is required. This may not fail. if ((*sampledLengthCache)[j] - (*sampledLengthCache)[i] >= readForwordLength) { break; } - (*sampledSearchKeySets)[i] |= (*sampledNearKeySets)[j]; + for(const auto& charProbability : charProbabilities->at(j)) { + if (charProbability.first == NOT_AN_INDEX) { + continue; + } + (*sampledSearchKeySets)[i].set(charProbability.first); + } } } const int keyCount = proximityInfo->getKeyCount(); @@ -907,7 +868,7 @@ namespace latinime { /* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth, const int sampledInputSize, const std::vector<int> *const lengthCache, const int index0, const int index1, - std::vector<hash_map_compat<int, float> > *charProbabilities) { + std::vector<std::unordered_map<int, float> > *charProbabilities) { ASSERT(0 <= index0 && index0 < sampledInputSize); ASSERT(0 <= index1 && index1 < sampledInputSize); const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth); @@ -918,9 +879,9 @@ namespace latinime { const float suppressionRate = ProximityInfoParams::MIN_SUPPRESSION_RATE + diff / keyWidthFloat / ProximityInfoParams::SUPPRESSION_LENGTH_WEIGHT * ProximityInfoParams::SUPPRESSION_WEIGHT; - for (hash_map_compat<int, float>::iterator it = (*charProbabilities)[index0].begin(); + for (std::unordered_map<int, float>::iterator it = (*charProbabilities)[index0].begin(); it != (*charProbabilities)[index0].end(); ++it) { - hash_map_compat<int, float>::iterator it2 = (*charProbabilities)[index1].find(it->first); + std::unordered_map<int, float>::iterator it2 = (*charProbabilities)[index1].find(it->first); if (it2 != (*charProbabilities)[index1].end() && it->second < it2->second) { const float newProbability = it->second * suppressionRate; const float suppression = it->second - newProbability; @@ -929,7 +890,7 @@ namespace latinime { (*charProbabilities)[index0][NOT_AN_INDEX] += suppression; // Add the probability of the same key nearby index1 - const float probabilityGain = min(suppression + const float probabilityGain = std::min(suppression * ProximityInfoParams::SUPPRESSION_WEIGHT_FOR_PROBABILITY_GAIN, (*charProbabilities)[index1][NOT_AN_INDEX] * ProximityInfoParams::SKIP_PROBABALITY_WEIGHT_FOR_PROBABILITY_GAIN); @@ -972,7 +933,7 @@ namespace latinime { // returns probability of generating the word. /* static */ float ProximityInfoStateUtils::getMostProbableString( const ProximityInfo *const proximityInfo, const int sampledInputSize, - const std::vector<hash_map_compat<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float> > *const charProbabilities, int *const codePointBuf) { ASSERT(sampledInputSize >= 0); memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH); @@ -982,7 +943,7 @@ namespace latinime { for (int i = 0; i < sampledInputSize && index < MAX_WORD_LENGTH - 1; ++i) { float minLogProbability = static_cast<float>(MAX_VALUE_FOR_WEIGHTING); int character = NOT_AN_INDEX; - for (hash_map_compat<int, float>::const_iterator it = (*charProbabilities)[i].begin(); + for (std::unordered_map<int, float>::const_iterator it = (*charProbabilities)[i].begin(); it != (*charProbabilities)[i].end(); ++it) { const float logProbability = (it->first != NOT_AN_INDEX) ? it->second + ProximityInfoParams::DEMOTION_LOG_PROBABILITY : it->second; @@ -992,7 +953,16 @@ namespace latinime { } } if (character != NOT_AN_INDEX) { - codePointBuf[index] = proximityInfo->getCodePointOf(character); + const int codePoint = proximityInfo->getCodePointOf(character); + if (codePoint == NOT_A_CODE_POINT) { + AKLOGE("Key index(%d) is not found. Cannot construct most probable string", + character); + ASSERT(false); + // Make the length zero, which means most probable string won't be used. + index = 0; + break; + } + codePointBuf[index] = codePoint; index++; } sumLogProbability += minLogProbability; diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h index 6de970033..71e83a80c 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h +++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h @@ -18,10 +18,10 @@ #define LATINIME_PROXIMITY_INFO_STATE_UTILS_H #include <bitset> +#include <unordered_map> #include <vector> #include "defines.h" -#include "utils/hash_map_compat.h" namespace latinime { class ProximityInfo; @@ -29,7 +29,7 @@ class ProximityInfoParams; class ProximityInfoStateUtils { public: - typedef hash_map_compat<int, float> NearKeysDistanceMap; + typedef std::unordered_map<int, float> NearKeysDistanceMap; typedef std::bitset<MAX_KEY_COUNT_IN_A_KEYBOARD> NearKeycodesSet; static int trimLastTwoTouchPoints(std::vector<int> *sampledInputXs, @@ -71,12 +71,12 @@ class ProximityInfoStateUtils { const std::vector<float> *const sampledSpeedRates, const std::vector<int> *const sampledLengthCache, const std::vector<float> *const sampledNormalizedSquaredLengthCache, - std::vector<NearKeycodesSet> *sampledNearKeySets, - std::vector<hash_map_compat<int, float> > *charProbabilities); + const ProximityInfo *const proximityInfo, + std::vector<std::unordered_map<int, float> > *charProbabilities); static void updateSampledSearchKeySets(const ProximityInfo *const proximityInfo, const int sampledInputSize, const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache, - const std::vector<NearKeycodesSet> *const sampledNearKeySets, + const std::vector<std::unordered_map<int, float> > *const charProbabilities, std::vector<NearKeycodesSet> *sampledSearchKeySets, std::vector<std::vector<int> > *sampledSearchKeyVectors); static float getPointToKeyByIdLength(const float maxPointToKeyLength, @@ -86,14 +86,9 @@ class ProximityInfoStateUtils { const int sampledInputSize, const int lastSavedInputSize, const bool isGeometric, const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, - std::vector<NearKeycodesSet> *sampledNearKeySets, std::vector<float> *sampledNormalizedSquaredLengthCache); static void initPrimaryInputWord(const int inputSize, const int *const inputProximities, int *primaryInputWord); - static void initNormalizedSquaredDistances(const ProximityInfo *const proximityInfo, - const int inputSize, const int *inputXCoordinates, const int *inputYCoordinates, - const int *const inputProximities, const std::vector<int> *const sampledInputXs, - const std::vector<int> *const sampledInputYs, int *normalizedSquaredDistances); static void dump(const bool isGeometric, const int inputSize, const int *const inputXCoordinates, const int *const inputYCoordinates, const int sampledInputSize, const std::vector<int> *const sampledInputXs, @@ -110,7 +105,7 @@ class ProximityInfoStateUtils { // TODO: Move to most_probable_string_utils.h static float getMostProbableString(const ProximityInfo *const proximityInfo, const int sampledInputSize, - const std::vector<hash_map_compat<int, float> > *const charProbabilities, + const std::vector<std::unordered_map<int, float> > *const charProbabilities, int *const codePointBuf); private: @@ -152,7 +147,7 @@ class ProximityInfoStateUtils { const int index2); static bool suppressCharProbabilities(const int mostCommonKeyWidth, const int sampledInputSize, const std::vector<int> *const lengthCache, const int index0, - const int index1, std::vector<hash_map_compat<int, float> > *charProbabilities); + const int index1, std::vector<std::unordered_map<int, float> > *charProbabilities); static float calculateSquaredDistanceFromSweetSpotCenter( const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs, const std::vector<int> *const sampledInputYs, const int keyIndex, diff --git a/native/jni/src/suggest/core/layout/proximity_info_utils.h b/native/jni/src/suggest/core/layout/proximity_info_utils.h index 0e28560fc..178aada2d 100644 --- a/native/jni/src/suggest/core/layout/proximity_info_utils.h +++ b/native/jni/src/suggest/core/layout/proximity_info_utils.h @@ -18,18 +18,18 @@ #define LATINIME_PROXIMITY_INFO_UTILS_H #include <cmath> +#include <unordered_map> #include "defines.h" #include "suggest/core/layout/additional_proximity_chars.h" #include "suggest/core/layout/geometry_utils.h" #include "utils/char_utils.h" -#include "utils/hash_map_compat.h" namespace latinime { class ProximityInfoUtils { public: static AK_FORCE_INLINE int getKeyIndexOf(const int keyCount, const int c, - const hash_map_compat<int, int> *const codeToKeyMap) { + const std::unordered_map<int, int> *const codeToKeyMap) { if (keyCount == 0) { // We do not have the coordinate data return NOT_AN_INDEX; @@ -38,7 +38,7 @@ class ProximityInfoUtils { return NOT_AN_INDEX; } const int lowerCode = CharUtils::toLowerCase(c); - hash_map_compat<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode); + std::unordered_map<int, int>::const_iterator mapPos = codeToKeyMap->find(lowerCode); if (mapPos != codeToKeyMap->end()) { return mapPos->second; } @@ -52,7 +52,7 @@ class ProximityInfoUtils { const int *const proximityCharsArray, const int cellHeight, const int cellWidth, const int gridWidth, const int mostCommonKeyWidth, const int keyCount, const char *const localeStr, - const hash_map_compat<int, int> *const codeToKeyMap, int *inputProximities) { + const std::unordered_map<int, int> *const codeToKeyMap, int *inputProximities) { // Initialize // - mInputCodes // - mNormalizedSquaredDistances @@ -100,6 +100,10 @@ class ProximityInfoUtils { const float dotProduct = ray1x * ray2x + ray1y * ray2y; const float lineLengthSqr = GeometryUtils::SQUARE_FLOAT(ray2x) + GeometryUtils::SQUARE_FLOAT(ray2y); + if (lineLengthSqr <= 0.0f) { + // Return point to the point distance. + return getSquaredDistanceFloat(x, y, x1, y1); + } const float projectionLengthSqr = dotProduct / lineLengthSqr; float projectionX; @@ -121,29 +125,6 @@ class ProximityInfoUtils { return type == MATCH_CHAR || type == PROXIMITY_CHAR || type == ADDITIONAL_PROXIMITY_CHAR; } - // Normal distribution N(u, sigma^2). - struct NormalDistribution { - public: - NormalDistribution(const float u, const float sigma) - : mU(u), mSigma(sigma), - mPreComputedNonExpPart(1.0f / sqrtf(2.0f * M_PI_F - * GeometryUtils::SQUARE_FLOAT(sigma))), - mPreComputedExponentPart(-1.0f / (2.0f * GeometryUtils::SQUARE_FLOAT(sigma))) {} - - float getProbabilityDensity(const float x) const { - const float shiftedX = x - mU; - return mPreComputedNonExpPart - * expf(mPreComputedExponentPart * GeometryUtils::SQUARE_FLOAT(shiftedX)); - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(NormalDistribution); - const float mU; // mean value - const float mSigma; // standard deviation - const float mPreComputedNonExpPart; // = 1 / sqrt(2 * PI * sigma^2) - const float mPreComputedExponentPart; // = -1 / (2 * sigma^2) - }; // struct NormalDistribution - private: DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoUtils); @@ -163,10 +144,16 @@ class ProximityInfoUtils { const int *const proximityCharsArray, const int cellHeight, const int cellWidth, const int gridWidth, const int mostCommonKeyWidth, const int keyCount, const int x, const int y, const int primaryKey, const char *const localeStr, - const hash_map_compat<int, int> *const codeToKeyMap, int *proximities) { + const std::unordered_map<int, int> *const codeToKeyMap, int *proximities) { const int mostCommonKeyWidthSquare = mostCommonKeyWidth * mostCommonKeyWidth; int insertPos = 0; proximities[insertPos++] = primaryKey; + if (x == NOT_A_COORDINATE || y == NOT_A_COORDINATE) { + for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { + proximities[i] = NOT_A_CODE_POINT; + } + return; + } const int startIndex = getStartIndexFromCoordinates(x, y, cellHeight, cellWidth, gridWidth); if (startIndex >= 0) { for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { diff --git a/native/jni/src/suggest/core/layout/touch_position_correction_utils.h b/native/jni/src/suggest/core/layout/touch_position_correction_utils.h index 9130e87d3..14074c13d 100644 --- a/native/jni/src/suggest/core/layout/touch_position_correction_utils.h +++ b/native/jni/src/suggest/core/layout/touch_position_correction_utils.h @@ -17,6 +17,8 @@ #ifndef LATINIME_TOUCH_POSITION_CORRECTION_UTILS_H #define LATINIME_TOUCH_POSITION_CORRECTION_UTILS_H +#include <algorithm> + #include "defines.h" #include "suggest/core/layout/proximity_info_params.h" @@ -34,7 +36,7 @@ class TouchPositionCorrectionUtils { static const float R2 = 1.0f; const float x = normalizedSquaredDistance; if (!isTouchPositionCorrectionEnabled) { - return min(C, x); + return std::min(C, x); } // factor is a piecewise linear function like: diff --git a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h index 5492c6070..a8dab9fcd 100644 --- a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h @@ -17,6 +17,9 @@ #ifndef LATINIME_DICTIONARY_HEADER_STRUCTURE_POLICY_H #define LATINIME_DICTIONARY_HEADER_STRUCTURE_POLICY_H +#include <map> +#include <vector> + #include "defines.h" namespace latinime { @@ -27,21 +30,25 @@ namespace latinime { */ class DictionaryHeaderStructurePolicy { public: + typedef std::map<std::vector<int>, std::vector<int> > AttributeMap; + virtual ~DictionaryHeaderStructurePolicy() {} - virtual bool supportsDynamicUpdate() const = 0; + virtual int getFormatVersionNumber() const = 0; - virtual bool requiresGermanUmlautProcessing() const = 0; + virtual int getSize() const = 0; - virtual bool requiresFrenchLigatureProcessing() const = 0; + virtual const AttributeMap *getAttributeMap() const = 0; - virtual float getMultiWordCostMultiplier() const = 0; + virtual bool requiresGermanUmlautProcessing() const = 0; - virtual int getLastDecayedTime() const = 0; + virtual float getMultiWordCostMultiplier() const = 0; virtual void readHeaderValueOrQuestionMark(const char *const key, int *outValue, int outValueSize) const = 0; + virtual bool shouldBoostExactMatches() const = 0; + protected: DictionaryHeaderStructurePolicy() {} diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h index 41f82049f..807f9b8dd 100644 --- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h +++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h @@ -17,7 +17,10 @@ #ifndef LATINIME_DICTIONARY_STRUCTURE_POLICY_H #define LATINIME_DICTIONARY_STRUCTURE_POLICY_H +#include <memory> + #include "defines.h" +#include "suggest/core/dictionary/property/word_property.h" namespace latinime { @@ -26,25 +29,28 @@ class DicNodeVector; class DictionaryBigramsStructurePolicy; class DictionaryHeaderStructurePolicy; class DictionaryShortcutsStructurePolicy; +class UnigramProperty; /* - * This class abstracts structure of dictionaries. + * This class abstracts the structure of dictionaries. * Implement this policy to support additional dictionaries. */ class DictionaryStructureWithBufferPolicy { public: + typedef std::unique_ptr<DictionaryStructureWithBufferPolicy> StructurePolicyPtr; + virtual ~DictionaryStructureWithBufferPolicy() {} virtual int getRootPosition() const = 0; - virtual void createAndGetAllChildNodes(const DicNode *const dicNode, + virtual void createAndGetAllChildDicNodes(const DicNode *const dicNode, DicNodeVector *const childDicNodes) const = 0; virtual int getCodePointsAndProbabilityAndReturnCodePointCount( const int nodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const = 0; - virtual int getTerminalNodePositionOfWord(const int *const inWord, + virtual int getTerminalPtNodePositionOfWord(const int *const inWord, const int length, const bool forceLowerCaseSearch) const = 0; virtual int getProbability(const int unigramProbability, @@ -64,11 +70,11 @@ class DictionaryStructureWithBufferPolicy { // Returns whether the update was success or not. virtual bool addUnigramWord(const int *const word, const int length, - const int probability) = 0; + const UnigramProperty *const unigramProperty) = 0; // Returns whether the update was success or not. virtual bool addBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1, const int probability) = 0; + const int length1, const int probability, const int timestamp) = 0; // Returns whether the update was success or not. virtual bool removeBigramWords(const int *const word0, const int length0, @@ -82,9 +88,20 @@ class DictionaryStructureWithBufferPolicy { // Currently, this method is used only for testing. You may want to consider creating new // dedicated method instead of this if you want to use this in the production. - virtual void getProperty(const char *const query, char *const outResult, + virtual void getProperty(const char *const query, const int queryLength, char *const outResult, const int maxResultLength) = 0; + // Used for testing. + virtual const WordProperty getWordProperty(const int *const codePonts, + const int codePointCount) const = 0; + + // Method to iterate all words in the dictionary. + // The returned token has to be used to get the next word. If token is 0, this method newly + // starts iterating the dictionary. + virtual int getNextWordAndNextToken(const int token, int *const outCodePoints) = 0; + + virtual bool isCorrupted() const = 0; + protected: DictionaryStructureWithBufferPolicy() {} diff --git a/native/jni/src/suggest/core/policy/scoring.h b/native/jni/src/suggest/core/policy/scoring.h index 102e856f5..292194bf2 100644 --- a/native/jni/src/suggest/core/policy/scoring.h +++ b/native/jni/src/suggest/core/policy/scoring.h @@ -23,26 +23,24 @@ namespace latinime { class DicNode; class DicTraverseSession; +class SuggestionResults; // This class basically tweaks suggestions and distances apart from CompoundDistance class Scoring { public: virtual int calculateFinalScore(const float compoundDistance, const int inputSize, - const bool forceCommit) const = 0; - virtual bool getMostProbableString(const DicTraverseSession *const traverseSession, - const int terminalSize, const float languageWeight, int *const outputCodePoints, - int *const type, int *const freq) const = 0; - virtual void safetyNetForMostProbableString(const int terminalSize, - const int maxScore, int *const outputCodePoints, int *const frequencies) const = 0; - // TODO: Make more generic - virtual void searchWordWithDoubleLetter(DicNode *terminals, const int terminalSize, - int *doubleLetterTerminalIndex, DoubleLetterLevel *doubleLetterLevel) const = 0; + const ErrorTypeUtils::ErrorType containedErrorTypes, const bool forceCommit, + const bool boostExactMatches) const = 0; + virtual void getMostProbableString(const DicTraverseSession *const traverseSession, + const float languageWeight, SuggestionResults *const outSuggestionResults) const = 0; virtual float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession, DicNode *const terminals, const int size) const = 0; - virtual float getDoubleLetterDemotionDistanceCost(const int terminalIndex, - const int doubleLetterTerminalIndex, - const DoubleLetterLevel doubleLetterLevel) const = 0; + virtual float getDoubleLetterDemotionDistanceCost( + const DicNode *const terminalDicNode) const = 0; virtual bool doesAutoCorrectValidWord() const = 0; + virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0; + virtual bool sameAsTyped(const DicTraverseSession *const traverseSession, + const DicNode *const dicNode) const = 0; protected: Scoring() {} diff --git a/native/jni/src/suggest/core/policy/traversal.h b/native/jni/src/suggest/core/policy/traversal.h index e935533f2..8ddaa0514 100644 --- a/native/jni/src/suggest/core/policy/traversal.h +++ b/native/jni/src/suggest/core/policy/traversal.h @@ -41,13 +41,11 @@ class Traversal { const DicNode *const dicNode) const = 0; virtual ProximityType getProximityType(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, const DicNode *const childDicNode) const = 0; - virtual bool sameAsTyped(const DicTraverseSession *const traverseSession, - const DicNode *const dicNode) const = 0; virtual bool needsToTraverseAllUserInput() const = 0; virtual float getMaxSpatialDistance() const = 0; - virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0; virtual int getDefaultExpandDicNodeSize() const = 0; virtual int getMaxCacheSize(const int inputSize) const = 0; + virtual int getTerminalCacheSize() const = 0; virtual bool isPossibleOmissionChildNode(const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0; virtual bool isGoodToTraverseNextWord(const DicNode *const dicNode) const = 0; diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp index 0c4016893..c202b81fe 100644 --- a/native/jni/src/suggest/core/policy/weighting.cpp +++ b/native/jni/src/suggest/core/policy/weighting.cpp @@ -20,6 +20,7 @@ #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_profiler.h" #include "suggest/core/dicnode/dic_node_utils.h" +#include "suggest/core/dictionary/error_type_utils.h" #include "suggest/core/session/dic_traverse_session.h" namespace latinime { @@ -82,8 +83,8 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n traverseSession, parentDicNode, dicNode, &inputStateG); const float languageCost = Weighting::getLanguageCost(weighting, correctionType, traverseSession, parentDicNode, dicNode, multiBigramMap); - const ErrorType errorType = weighting->getErrorType(correctionType, traverseSession, - parentDicNode, dicNode); + const ErrorTypeUtils::ErrorType errorType = weighting->getErrorType(correctionType, + traverseSession, parentDicNode, dicNode); profile(correctionType, dicNode); if (inputStateG.mNeedsToUpdateInputStateG) { dicNode->updateInputIndexG(&inputStateG); diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h index 2d49e98a6..bd6b3cf41 100644 --- a/native/jni/src/suggest/core/policy/weighting.h +++ b/native/jni/src/suggest/core/policy/weighting.h @@ -18,6 +18,7 @@ #define LATINIME_WEIGHTING_H #include "defines.h" +#include "suggest/core/dictionary/error_type_utils.h" namespace latinime { @@ -84,7 +85,7 @@ class Weighting { virtual float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const = 0; - virtual ErrorType getErrorType(const CorrectionType correctionType, + virtual ErrorTypeUtils::ErrorType getErrorType(const CorrectionType correctionType, const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0; diff --git a/native/jni/src/suggest/core/result/suggested_word.h b/native/jni/src/suggest/core/result/suggested_word.h new file mode 100644 index 000000000..258a40eeb --- /dev/null +++ b/native/jni/src/suggest/core/result/suggested_word.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 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_SUGGESTED_WORD_H +#define LATINIME_SUGGESTED_WORD_H + +#include <vector> + +#include "defines.h" +#include "suggest/core/dictionary/dictionary.h" + +namespace latinime { + +class SuggestedWord { + public: + class Comparator { + public: + bool operator()(const SuggestedWord &left, const SuggestedWord &right) { + if (left.getScore() != right.getScore()) { + return left.getScore() > right.getScore(); + } + return left.getCodePointCount() < right.getCodePointCount(); + } + + private: + DISALLOW_ASSIGNMENT_OPERATOR(Comparator); + }; + + SuggestedWord(const int *const codePoints, const int codePointCount, + const int score, const int type, const int indexToPartialCommit, + const int autoCommitFirstWordConfidence) + : mCodePoints(codePoints, codePoints + codePointCount), mScore(score), + mType(type), mIndexToPartialCommit(indexToPartialCommit), + mAutoCommitFirstWordConfidence(autoCommitFirstWordConfidence) {} + + const int *getCodePoint() const { + return &mCodePoints.at(0); + } + + int getCodePointCount() const { + return mCodePoints.size(); + } + + int getScore() const { + return mScore; + } + + int getType() const { + return mType; + } + + int getIndexToPartialCommit() const { + return mIndexToPartialCommit; + } + + int getAutoCommitFirstWordConfidence() const { + return mAutoCommitFirstWordConfidence; + } + + private: + DISALLOW_DEFAULT_CONSTRUCTOR(SuggestedWord); + + std::vector<int> mCodePoints; + int mScore; + int mType; + int mIndexToPartialCommit; + int mAutoCommitFirstWordConfidence; +}; +} // namespace latinime +#endif /* LATINIME_SUGGESTED_WORD_H */ diff --git a/native/jni/src/suggest/core/result/suggestion_results.cpp b/native/jni/src/suggest/core/result/suggestion_results.cpp new file mode 100644 index 000000000..088a55f6f --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestion_results.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "suggest/core/result/suggestion_results.h" + +namespace latinime { + +void SuggestionResults::outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, + jintArray outputCodePointsArray, jintArray outScoresArray, jintArray outSpaceIndicesArray, + jintArray outTypesArray, jintArray outAutoCommitFirstWordConfidenceArray, + jfloatArray outLanguageWeight) { + int outputIndex = 0; + while (!mSuggestedWords.empty()) { + const SuggestedWord &suggestedWord = mSuggestedWords.top(); + suggestedWord.getCodePointCount(); + const int start = outputIndex * MAX_WORD_LENGTH; + env->SetIntArrayRegion(outputCodePointsArray, start, suggestedWord.getCodePointCount(), + suggestedWord.getCodePoint()); + if (suggestedWord.getCodePointCount() < MAX_WORD_LENGTH) { + const int terminal = 0; + env->SetIntArrayRegion(outputCodePointsArray, start + suggestedWord.getCodePointCount(), + 1 /* len */, &terminal); + } + const int score = suggestedWord.getScore(); + env->SetIntArrayRegion(outScoresArray, outputIndex, 1 /* len */, &score); + const int indexToPartialCommit = suggestedWord.getIndexToPartialCommit(); + env->SetIntArrayRegion(outSpaceIndicesArray, outputIndex, 1 /* len */, + &indexToPartialCommit); + const int type = suggestedWord.getType(); + env->SetIntArrayRegion(outTypesArray, outputIndex, 1 /* len */, &type); + if (mSuggestedWords.size() == 1) { + const int autoCommitFirstWordConfidence = + suggestedWord.getAutoCommitFirstWordConfidence(); + env->SetIntArrayRegion(outAutoCommitFirstWordConfidenceArray, 0 /* start */, + 1 /* len */, &autoCommitFirstWordConfidence); + } + ++outputIndex; + mSuggestedWords.pop(); + } + env->SetIntArrayRegion(outSuggestionCount, 0 /* start */, 1 /* len */, &outputIndex); + env->SetFloatArrayRegion(outLanguageWeight, 0 /* start */, 1 /* len */, &mLanguageWeight); +} + +void SuggestionResults::addPrediction(const int *const codePoints, const int codePointCount, + const int probability) { + if (probability == NOT_A_PROBABILITY) { + // Invalid word. + return; + } + addSuggestion(codePoints, codePointCount, probability, Dictionary::KIND_PREDICTION, + NOT_AN_INDEX, NOT_A_FIRST_WORD_CONFIDENCE); +} + +void SuggestionResults::addSuggestion(const int *const codePoints, const int codePointCount, + const int score, const int type, const int indexToPartialCommit, + const int autocimmitFirstWordConfindence) { + if (codePointCount <= 0 || codePointCount > MAX_WORD_LENGTH) { + // Invalid word. + AKLOGE("Invalid word is added to the suggestion results. codePointCount: %d", + codePointCount); + return; + } + if (getSuggestionCount() >= mMaxSuggestionCount) { + const SuggestedWord &mWorstSuggestion = mSuggestedWords.top(); + if (score > mWorstSuggestion.getScore() || (score == mWorstSuggestion.getScore() + && codePointCount < mWorstSuggestion.getCodePointCount())) { + mSuggestedWords.pop(); + } else { + return; + } + } + mSuggestedWords.push(SuggestedWord(codePoints, codePointCount, score, type, + indexToPartialCommit, autocimmitFirstWordConfindence)); +} + +void SuggestionResults::getSortedScores(int *const outScores) const { + auto copyOfSuggestedWords = mSuggestedWords; + while (!copyOfSuggestedWords.empty()) { + const SuggestedWord &suggestedWord = copyOfSuggestedWords.top(); + outScores[copyOfSuggestedWords.size() - 1] = suggestedWord.getScore(); + copyOfSuggestedWords.pop(); + } +} + +void SuggestionResults::dumpSuggestions() const { + AKLOGE("language weight: %f", mLanguageWeight); + std::vector<SuggestedWord> suggestedWords; + auto copyOfSuggestedWords = mSuggestedWords; + while (!copyOfSuggestedWords.empty()) { + suggestedWords.push_back(copyOfSuggestedWords.top()); + copyOfSuggestedWords.pop(); + } + int index = 0; + for (auto it = suggestedWords.rbegin(); it != suggestedWords.rend(); ++it) { + DUMP_SUGGESTION(it->getCodePoint(), it->getCodePointCount(), index, it->getScore()); + index++; + } +} + +} // namespace latinime diff --git a/native/jni/src/suggest/core/result/suggestion_results.h b/native/jni/src/suggest/core/result/suggestion_results.h new file mode 100644 index 000000000..8e845e2d3 --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestion_results.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 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_SUGGESTION_RESULTS_H +#define LATINIME_SUGGESTION_RESULTS_H + +#include <queue> +#include <vector> + +#include "defines.h" +#include "jni.h" +#include "suggest/core/result/suggested_word.h" + +namespace latinime { + +class SuggestionResults { + public: + explicit SuggestionResults(const int maxSuggestionCount) + : mMaxSuggestionCount(maxSuggestionCount), mLanguageWeight(NOT_A_LANGUAGE_WEIGHT), + mSuggestedWords() {} + + // Returns suggestion count. + void outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, jintArray outCodePointsArray, + jintArray outScoresArray, jintArray outSpaceIndicesArray, jintArray outTypesArray, + jintArray outAutoCommitFirstWordConfidenceArray, jfloatArray outLanguageWeight); + void addPrediction(const int *const codePoints, const int codePointCount, const int score); + void addSuggestion(const int *const codePoints, const int codePointCount, + const int score, const int type, const int indexToPartialCommit, + const int autocimmitFirstWordConfindence); + void getSortedScores(int *const outScores) const; + void dumpSuggestions() const; + + void setLanguageWeight(const float languageWeight) { + mLanguageWeight = languageWeight; + } + + int getSuggestionCount() const { + return mSuggestedWords.size(); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestionResults); + + const int mMaxSuggestionCount; + float mLanguageWeight; + std::priority_queue< + SuggestedWord, std::vector<SuggestedWord>, SuggestedWord::Comparator> mSuggestedWords; +}; +} // namespace latinime +#endif // LATINIME_SUGGESTION_RESULTS_H diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp new file mode 100644 index 000000000..a307cb45d --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/core/result/suggestions_output_utils.h" + +#include <algorithm> +#include <vector> + +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_utils.h" +#include "suggest/core/dictionary/binary_dictionary_shortcut_iterator.h" +#include "suggest/core/dictionary/error_type_utils.h" +#include "suggest/core/policy/scoring.h" +#include "suggest/core/result/suggestion_results.h" +#include "suggest/core/session/dic_traverse_session.h" + +namespace latinime { + +const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; + +/* static */ void SuggestionsOutputUtils::outputSuggestions( + const Scoring *const scoringPolicy, DicTraverseSession *traverseSession, + const float languageWeight, SuggestionResults *const outSuggestionResults) { +#if DEBUG_EVALUATE_MOST_PROBABLE_STRING + const int terminalSize = 0; +#else + const int terminalSize = traverseSession->getDicTraverseCache()->terminalSize(); +#endif + std::vector<DicNode> terminals(terminalSize); + for (int index = terminalSize - 1; index >= 0; --index) { + traverseSession->getDicTraverseCache()->popTerminal(&terminals[index]); + } + // Compute a language weight when an invalid language weight is passed. + // NOT_A_LANGUAGE_WEIGHT (-1) is assumed as an invalid language weight. + const float languageWeightToOutputSuggestions = (languageWeight < 0.0f) ? + scoringPolicy->getAdjustedLanguageWeight( + traverseSession, terminals.data(), terminalSize) : languageWeight; + outSuggestionResults->setLanguageWeight(languageWeightToOutputSuggestions); + // Force autocorrection for obvious long multi-word suggestions when the top suggestion is + // a long multiple words suggestion. + // TODO: Implement a smarter auto-commit method for handling multi-word suggestions. + const bool forceCommitMultiWords = scoringPolicy->autoCorrectsToMultiWordSuggestionIfTop() + && (traverseSession->getInputSize() >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT + && !terminals.empty() && terminals.front().hasMultipleWords()); + // TODO: have partial commit work even with multiple pointers. + const bool outputSecondWordFirstLetterInputIndex = + traverseSession->isOnlyOnePointerUsed(0 /* pointerId */); + const bool boostExactMatches = traverseSession->getDictionaryStructurePolicy()-> + getHeaderStructurePolicy()->shouldBoostExactMatches(); + + // Output suggestion results here + for (auto &terminalDicNode : terminals) { + outputSuggestionsOfDicNode(scoringPolicy, traverseSession, &terminalDicNode, + languageWeightToOutputSuggestions, boostExactMatches, forceCommitMultiWords, + outputSecondWordFirstLetterInputIndex, outSuggestionResults); + } + scoringPolicy->getMostProbableString(traverseSession, languageWeightToOutputSuggestions, + outSuggestionResults); +} + +/* static */ void SuggestionsOutputUtils::outputSuggestionsOfDicNode( + const Scoring *const scoringPolicy, DicTraverseSession *traverseSession, + const DicNode *const terminalDicNode, const float languageWeight, + const bool boostExactMatches, const bool forceCommitMultiWords, + const bool outputSecondWordFirstLetterInputIndex, + SuggestionResults *const outSuggestionResults) { + if (DEBUG_GEO_FULL) { + terminalDicNode->dump("OUT:"); + } + const float doubleLetterCost = + scoringPolicy->getDoubleLetterDemotionDistanceCost(terminalDicNode); + const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) + + doubleLetterCost; + const bool isPossiblyOffensiveWord = + traverseSession->getDictionaryStructurePolicy()->getProbability( + terminalDicNode->getProbability(), NOT_A_PROBABILITY) <= 0; + const bool isExactMatch = + ErrorTypeUtils::isExactMatch(terminalDicNode->getContainedErrorTypes()); + const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase(); + // Heuristic: We exclude probability=0 first-char-uppercase words from exact match. + // (e.g. "AMD" and "and") + const bool isSafeExactMatch = isExactMatch + && !(isPossiblyOffensiveWord && isFirstCharUppercase); + const int outputTypeFlags = + (isPossiblyOffensiveWord ? Dictionary::KIND_FLAG_POSSIBLY_OFFENSIVE : 0) + | ((isSafeExactMatch && boostExactMatches) ? Dictionary::KIND_FLAG_EXACT_MATCH : 0); + + // Entries that are blacklisted or do not represent a word should not be output. + const bool isValidWord = !terminalDicNode->isBlacklistedOrNotAWord(); + + // Increase output score of top typing suggestion to ensure autocorrection. + // TODO: Better integration with java side autocorrection logic. + const int finalScore = scoringPolicy->calculateFinalScore( + compoundDistance, traverseSession->getInputSize(), + terminalDicNode->getContainedErrorTypes(), + (forceCommitMultiWords && terminalDicNode->hasMultipleWords()) + || (isValidWord && scoringPolicy->doesAutoCorrectValidWord()), + boostExactMatches); + + // Don't output invalid words. However, we still need to submit their shortcuts if any. + if (isValidWord) { + int codePoints[MAX_WORD_LENGTH]; + terminalDicNode->outputResult(codePoints); + const int indexToPartialCommit = outputSecondWordFirstLetterInputIndex ? + terminalDicNode->getSecondWordFirstInputIndex( + traverseSession->getProximityInfoState(0)) : + NOT_AN_INDEX; + outSuggestionResults->addSuggestion(codePoints, + terminalDicNode->getTotalNodeCodePointCount(), + finalScore, Dictionary::KIND_CORRECTION | outputTypeFlags, + indexToPartialCommit, computeFirstWordConfidence(terminalDicNode)); + } + + // Output shortcuts. + // Shortcut is not supported for multiple words suggestions. + // TODO: Check shortcuts during traversal for multiple words suggestions. + if (!terminalDicNode->hasMultipleWords()) { + BinaryDictionaryShortcutIterator shortcutIt( + traverseSession->getDictionaryStructurePolicy()->getShortcutsStructurePolicy(), + traverseSession->getDictionaryStructurePolicy() + ->getShortcutPositionOfPtNode(terminalDicNode->getPtNodePos())); + const bool sameAsTyped = scoringPolicy->sameAsTyped(traverseSession, terminalDicNode); + const int shortcutBaseScore = scoringPolicy->doesAutoCorrectValidWord() ? + scoringPolicy->calculateFinalScore(compoundDistance, + traverseSession->getInputSize(), + terminalDicNode->getContainedErrorTypes(), + true /* forceCommit */, boostExactMatches) : finalScore; + outputShortcuts(&shortcutIt, shortcutBaseScore, sameAsTyped, outSuggestionResults); + } +} + +/* static */ int SuggestionsOutputUtils::computeFirstWordConfidence( + const DicNode *const terminalDicNode) { + // Get the number of spaces in the first suggestion + const int spaceCount = terminalDicNode->getTotalNodeSpaceCount(); + // Get the number of characters in the first suggestion + const int length = terminalDicNode->getTotalNodeCodePointCount(); + // Get the distance for the first word of the suggestion + const float distance = terminalDicNode->getNormalizedCompoundDistanceAfterFirstWord(); + + // Arbitrarily, we give a score whose useful values range from 0 to 1,000,000. + // 1,000,000 will be the cutoff to auto-commit. It's fine if the number is under 0 or + // above 1,000,000 : under 0 just means it's very bad to commit, and above 1,000,000 means + // we are very confident. + // Expected space count is 1 ~ 5 + static const int MIN_EXPECTED_SPACE_COUNT = 1; + static const int MAX_EXPECTED_SPACE_COUNT = 5; + // Expected length is about 4 ~ 30 + static const int MIN_EXPECTED_LENGTH = 4; + static const int MAX_EXPECTED_LENGTH = 30; + // Expected distance is about 0.2 ~ 2.0, but consider 0.0 ~ 2.0 + static const float MIN_EXPECTED_DISTANCE = 0.0; + static const float MAX_EXPECTED_DISTANCE = 2.0; + // This is not strict: it's where most stuff will be falling, but it's still fine if it's + // outside these values. We want to output a value that reflects all of these. Each factor + // contributes a bit. + + // We need at least a space. + if (spaceCount < 1) return NOT_A_FIRST_WORD_CONFIDENCE; + + // The smaller the edit distance, the higher the contribution. MIN_EXPECTED_DISTANCE means 0 + // contribution, while MAX_EXPECTED_DISTANCE means full contribution according to the + // weight of the distance. Clamp to avoid overflows. + const float clampedDistance = distance < MIN_EXPECTED_DISTANCE ? MIN_EXPECTED_DISTANCE + : distance > MAX_EXPECTED_DISTANCE ? MAX_EXPECTED_DISTANCE : distance; + const int distanceContribution = DISTANCE_WEIGHT_FOR_AUTO_COMMIT + * (MAX_EXPECTED_DISTANCE - clampedDistance) + / (MAX_EXPECTED_DISTANCE - MIN_EXPECTED_DISTANCE); + // The larger the suggestion length, the larger the contribution. MIN_EXPECTED_LENGTH is no + // contribution, MAX_EXPECTED_LENGTH is full contribution according to the weight of the + // length. Length is guaranteed to be between 1 and 48, so we don't need to clamp. + const int lengthContribution = LENGTH_WEIGHT_FOR_AUTO_COMMIT + * (length - MIN_EXPECTED_LENGTH) / (MAX_EXPECTED_LENGTH - MIN_EXPECTED_LENGTH); + // The more spaces, the larger the contribution. MIN_EXPECTED_SPACE_COUNT space is no + // contribution, MAX_EXPECTED_SPACE_COUNT spaces is full contribution according to the + // weight of the space count. + const int spaceContribution = SPACE_COUNT_WEIGHT_FOR_AUTO_COMMIT + * (spaceCount - MIN_EXPECTED_SPACE_COUNT) + / (MAX_EXPECTED_SPACE_COUNT - MIN_EXPECTED_SPACE_COUNT); + + return distanceContribution + lengthContribution + spaceContribution; +} + +/* static */ void SuggestionsOutputUtils::outputShortcuts( + BinaryDictionaryShortcutIterator *const shortcutIt, const int finalScore, + const bool sameAsTyped, SuggestionResults *const outSuggestionResults) { + int shortcutTarget[MAX_WORD_LENGTH]; + while (shortcutIt->hasNextShortcutTarget()) { + bool isWhilelist; + int shortcutTargetStringLength; + shortcutIt->nextShortcutTarget(MAX_WORD_LENGTH, shortcutTarget, + &shortcutTargetStringLength, &isWhilelist); + int shortcutScore; + int kind; + if (isWhilelist && sameAsTyped) { + shortcutScore = S_INT_MAX; + kind = Dictionary::KIND_WHITELIST; + } else { + // shortcut entry's score == its base entry's score - 1 + shortcutScore = finalScore; + // Protection against int underflow + shortcutScore = std::max(S_INT_MIN + 1, shortcutScore) - 1; + kind = Dictionary::KIND_SHORTCUT; + } + outSuggestionResults->addSuggestion(shortcutTarget, shortcutTargetStringLength, + std::max(S_INT_MIN + 1, shortcutScore) - 1, kind, NOT_AN_INDEX, + NOT_A_FIRST_WORD_CONFIDENCE); + } +} +} // namespace latinime diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.h b/native/jni/src/suggest/core/result/suggestions_output_utils.h new file mode 100644 index 000000000..b099b4776 --- /dev/null +++ b/native/jni/src/suggest/core/result/suggestions_output_utils.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 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_SUGGESTIONS_OUTPUT_UTILS +#define LATINIME_SUGGESTIONS_OUTPUT_UTILS + +#include "defines.h" + +namespace latinime { + +class BinaryDictionaryShortcutIterator; +class DicNode; +class DicTraverseSession; +class Scoring; +class SuggestionResults; + +class SuggestionsOutputUtils { + public: + /** + * Outputs the final list of suggestions (i.e., terminal nodes). + */ + static void outputSuggestions(const Scoring *const scoringPolicy, + DicTraverseSession *traverseSession, const float languageWeight, + SuggestionResults *const outSuggestionResults); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SuggestionsOutputUtils); + + // Inputs longer than this will autocorrect if the suggestion is multi-word + static const int MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT; + + static void outputSuggestionsOfDicNode(const Scoring *const scoringPolicy, + DicTraverseSession *traverseSession, const DicNode *const terminalDicNode, + const float languageWeight, const bool boostExactMatches, + const bool forceCommitMultiWords, const bool outputSecondWordFirstLetterInputIndex, + SuggestionResults *const outSuggestionResults); + static void outputShortcuts(BinaryDictionaryShortcutIterator *const shortcutIt, + const int finalScore, const bool sameAsTyped, + SuggestionResults *const outSuggestionResults); + static int computeFirstWordConfidence(const DicNode *const terminalDicNode); +}; +} // namespace latinime +#endif // LATINIME_SUGGESTIONS_OUTPUT_UTILS diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp index 50f2bbd8d..77b634e07 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp +++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp @@ -35,16 +35,16 @@ void DicTraverseSession::init(const Dictionary *const dictionary, const int *pre ->getMultiWordCostMultiplier(); mSuggestOptions = suggestOptions; if (!prevWord) { - mPrevWordPos = NOT_A_DICT_POS; + mPrevWordPtNodePos = NOT_A_DICT_POS; return; } // TODO: merge following similar calls to getTerminalPosition into one case-insensitive call. - mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord( + mPrevWordPtNodePos = getDictionaryStructurePolicy()->getTerminalPtNodePositionOfWord( prevWord, prevWordLength, false /* forceLowerCaseSearch */); - if (mPrevWordPos == NOT_A_DICT_POS) { + if (mPrevWordPtNodePos == NOT_A_DICT_POS) { // Check bigrams for lower-cased previous word if original was not found. Useful for // auto-capitalized words like "The [current_word]". - mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord( + mPrevWordPtNodePos = getDictionaryStructurePolicy()->getTerminalPtNodePositionOfWord( prevWord, prevWordLength, true /* forceLowerCaseSearch */); } } @@ -68,7 +68,6 @@ void DicTraverseSession::resetCache(const int thresholdForNextActiveDicNodes, co mDicNodesCache.reset(thresholdForNextActiveDicNodes /* nextActiveSize */, maxWords /* terminalSize */); mMultiBigramMap.clear(); - mPartiallyCommited = false; } void DicTraverseSession::initializeProximityInfoStates(const int *const inputCodePoints, diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h index e0b1c67d9..843ca85a0 100644 --- a/native/jni/src/suggest/core/session/dic_traverse_session.h +++ b/native/jni/src/suggest/core/session/dic_traverse_session.h @@ -17,7 +17,6 @@ #ifndef LATINIME_DIC_TRAVERSE_SESSION_H #define LATINIME_DIC_TRAVERSE_SESSION_H -#include <stdint.h> #include <vector> #include "defines.h" @@ -59,9 +58,9 @@ class DicTraverseSession { } AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache) - : mPrevWordPos(NOT_A_DICT_POS), mProximityInfo(0), - mDictionary(0), mSuggestOptions(0), mDicNodesCache(usesLargeCache), - mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1), + : mPrevWordPtNodePos(NOT_A_DICT_POS), mProximityInfo(nullptr), + mDictionary(nullptr), mSuggestOptions(nullptr), mDicNodesCache(usesLargeCache), + mMultiBigramMap(), mInputSize(0), mMaxPointerCount(1), mMultiWordCostMultiplier(1.0f) { // NOTE: mProximityInfoStates is an array of instances. // No need to initialize it explicitly here. @@ -86,19 +85,15 @@ class DicTraverseSession { //-------------------- const ProximityInfo *getProximityInfo() const { return mProximityInfo; } const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; } - int getPrevWordPos() const { return mPrevWordPos; } + int getPrevWordPtNodePos() const { return mPrevWordPtNodePos; } // TODO: REMOVE - void setPrevWordPos(int pos) { mPrevWordPos = pos; } - // TODO: Use proper parameter when changed - int getDicRootPos() const { return 0; } + void setPrevWordPtNodePos(const int ptNodePos) { mPrevWordPtNodePos = ptNodePos; } DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; } MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; } const ProximityInfoState *getProximityInfoState(int id) const { return &mProximityInfoStates[id]; } int getInputSize() const { return mInputSize; } - void setPartiallyCommited() { mPartiallyCommited = true; } - bool isPartiallyCommited() const { return mPartiallyCommited; } bool isOnlyOnePointerUsed(int *pointerId) const { // Not in the dictionary word @@ -119,26 +114,13 @@ class DicTraverseSession { return true; } - void getSearchKeys(const DicNode *node, std::vector<int> *const outputSearchKeyVector) const { - for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) { - if (!mProximityInfoStates[i].isUsed()) { - continue; - } - const int pointerId = node->getInputIndex(i); - const std::vector<int> *const searchKeyVector = - mProximityInfoStates[i].getSearchKeyVector(pointerId); - outputSearchKeyVector->insert(outputSearchKeyVector->end(), searchKeyVector->begin(), - searchKeyVector->end()); - } - } - - ProximityType getProximityTypeG(const DicNode *const node, const int childCodePoint) const { + ProximityType getProximityTypeG(const DicNode *const dicNode, const int childCodePoint) const { ProximityType proximityType = UNRELATED_CHAR; for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) { if (!mProximityInfoStates[i].isUsed()) { continue; } - const int pointerId = node->getInputIndex(i); + const int pointerId = dicNode->getInputIndex(i); proximityType = mProximityInfoStates[i].getProximityTypeG(pointerId, childCodePoint); ASSERT(proximityType == UNRELATED_CHAR || proximityType == MATCH_CHAR); // TODO: Make this more generic @@ -192,7 +174,7 @@ class DicTraverseSession { const int *const inputYs, const int *const times, const int *const pointerIds, const int inputSize, const float maxSpatialDistance, const int maxPointerCount); - int mPrevWordPos; + int mPrevWordPtNodePos; const ProximityInfo *mProximityInfo; const Dictionary *mDictionary; const SuggestOptions *mSuggestOptions; @@ -203,7 +185,6 @@ class DicTraverseSession { ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G]; int mInputSize; - bool mPartiallyCommited; int mMaxPointerCount; ///////////////////////////////// diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index 73ccebc88..e675e0bb3 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -19,23 +19,19 @@ #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_priority_queue.h" #include "suggest/core/dicnode/dic_node_vector.h" -#include "suggest/core/dictionary/binary_dictionary_shortcut_iterator.h" #include "suggest/core/dictionary/dictionary.h" #include "suggest/core/dictionary/digraph_utils.h" -#include "suggest/core/dictionary/shortcut_utils.h" #include "suggest/core/layout/proximity_info.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" -#include "suggest/core/policy/scoring.h" #include "suggest/core/policy/traversal.h" #include "suggest/core/policy/weighting.h" +#include "suggest/core/result/suggestions_output_utils.h" #include "suggest/core/session/dic_traverse_session.h" namespace latinime { // Initialization of class constants. -const int Suggest::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16; const int Suggest::MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE = 2; -const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f; /** * Returns a set of suggestions for the given input touch points. The commitPoint argument indicates @@ -46,10 +42,10 @@ const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f; * automatically activated for sequential calls that share the same starting input. * TODO: Stop detecting continuous suggestion. Start using traverseSession instead. */ -int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession, +void Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints, - int inputSize, int commitPoint, int *outWords, int *frequencies, int *outputIndices, - int *outputTypes, int *outputAutoCommitFirstWordConfidence) const { + int inputSize, const float languageWeight, + SuggestionResults *const outSuggestionResults) const { PROF_OPEN; PROF_START(0); const float maxSpatialDistance = TRAVERSAL->getMaxSpatialDistance(); @@ -58,7 +54,7 @@ int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession, pointerIds, maxSpatialDistance, TRAVERSAL->getMaxPointerCount()); // TODO: Add the way to evaluate cache - initializeSearch(tSession, commitPoint); + initializeSearch(tSession); PROF_END(0); PROF_START(1); @@ -70,247 +66,38 @@ int Suggest::getSuggestions(ProximityInfo *pInfo, void *traverseSession, } PROF_END(1); PROF_START(2); - const int size = outputSuggestions(tSession, frequencies, outWords, outputIndices, outputTypes, - outputAutoCommitFirstWordConfidence); + SuggestionsOutputUtils::outputSuggestions( + SCORING, tSession, languageWeight, outSuggestionResults); PROF_END(2); PROF_CLOSE; - return size; } /** * Initializes the search at the root of the lexicon trie. Note that when possible the search will * continue suggestion from where it left off during the last call. */ -void Suggest::initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const { +void Suggest::initializeSearch(DicTraverseSession *traverseSession) const { if (!traverseSession->getProximityInfoState(0)->isUsed()) { return; } - // Never auto partial commit for now. - commitPoint = 0; - if (traverseSession->getInputSize() > MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE && traverseSession->isContinuousSuggestionPossible()) { - if (commitPoint == 0) { - // Continue suggestion - traverseSession->getDicTraverseCache()->continueSearch(); - } else { - // Continue suggestion after partial commit. - DicNode *topDicNode = - traverseSession->getDicTraverseCache()->setCommitPoint(commitPoint); - traverseSession->setPrevWordPos(topDicNode->getPrevWordNodePos()); - traverseSession->getDicTraverseCache()->continueSearch(); - traverseSession->setPartiallyCommited(); - } + // Continue suggestion + traverseSession->getDicTraverseCache()->continueSearch(); } else { // Restart recognition at the root. traverseSession->resetCache(TRAVERSAL->getMaxCacheSize(traverseSession->getInputSize()), - MAX_RESULTS); + TRAVERSAL->getTerminalCacheSize()); // Create a new dic node here DicNode rootNode; DicNodeUtils::initAsRoot(traverseSession->getDictionaryStructurePolicy(), - traverseSession->getPrevWordPos(), &rootNode); + traverseSession->getPrevWordPtNodePos(), &rootNode); traverseSession->getDicTraverseCache()->copyPushActive(&rootNode); } } /** - * Outputs the final list of suggestions (i.e., terminal nodes). - */ -int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequencies, - int *outputCodePoints, int *outputIndicesToPartialCommit, int *outputTypes, - int *outputAutoCommitFirstWordConfidence) const { -#if DEBUG_EVALUATE_MOST_PROBABLE_STRING - const int terminalSize = 0; -#else - const int terminalSize = min(MAX_RESULTS, - static_cast<int>(traverseSession->getDicTraverseCache()->terminalSize())); -#endif - DicNode terminals[MAX_RESULTS]; // Avoiding non-POD variable length array - - for (int index = terminalSize - 1; index >= 0; --index) { - traverseSession->getDicTraverseCache()->popTerminal(&terminals[index]); - } - - const float languageWeight = SCORING->getAdjustedLanguageWeight( - traverseSession, terminals, terminalSize); - - int outputWordIndex = 0; - // Insert most probable word at index == 0 as long as there is one terminal at least - const bool hasMostProbableString = - SCORING->getMostProbableString(traverseSession, terminalSize, languageWeight, - &outputCodePoints[0], &outputTypes[0], &frequencies[0]); - if (hasMostProbableString) { - outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX; - ++outputWordIndex; - } - - // Initial value of the loop index for terminal nodes (words) - int doubleLetterTerminalIndex = -1; - DoubleLetterLevel doubleLetterLevel = NOT_A_DOUBLE_LETTER; - SCORING->searchWordWithDoubleLetter(terminals, terminalSize, - &doubleLetterTerminalIndex, &doubleLetterLevel); - - int maxScore = S_INT_MIN; - // Force autocorrection for obvious long multi-word suggestions when the top suggestion is - // a long multiple words suggestion. - // TODO: Implement a smarter auto-commit method for handling multi-word suggestions. - // traverseSession->isPartiallyCommited() always returns false because we never auto partial - // commit for now. - const bool forceCommitMultiWords = (terminalSize > 0) ? - TRAVERSAL->autoCorrectsToMultiWordSuggestionIfTop() - && (traverseSession->isPartiallyCommited() - || (traverseSession->getInputSize() - >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT - && terminals[0].hasMultipleWords())) : false; - // TODO: have partial commit work even with multiple pointers. - const bool outputSecondWordFirstLetterInputIndex = - traverseSession->isOnlyOnePointerUsed(0 /* pointerId */); - if (terminalSize > 0) { - // If we have no suggestions, don't write this - outputAutoCommitFirstWordConfidence[0] = - computeFirstWordConfidence(&terminals[0]); - } - - // Output suggestion results here - for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS; - ++terminalIndex) { - DicNode *terminalDicNode = &terminals[terminalIndex]; - if (DEBUG_GEO_FULL) { - terminalDicNode->dump("OUT:"); - } - const float doubleLetterCost = SCORING->getDoubleLetterDemotionDistanceCost( - terminalIndex, doubleLetterTerminalIndex, doubleLetterLevel); - const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight) - + doubleLetterCost; - const bool isPossiblyOffensiveWord = - traverseSession->getDictionaryStructurePolicy()->getProbability( - terminalDicNode->getProbability(), NOT_A_PROBABILITY) <= 0; - const bool isExactMatch = terminalDicNode->isExactMatch(); - const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase(); - // Heuristic: We exclude freq=0 first-char-uppercase words from exact match. - // (e.g. "AMD" and "and") - const bool isSafeExactMatch = isExactMatch - && !(isPossiblyOffensiveWord && isFirstCharUppercase); - const int outputTypeFlags = - (isPossiblyOffensiveWord ? Dictionary::KIND_FLAG_POSSIBLY_OFFENSIVE : 0) - | (isSafeExactMatch ? Dictionary::KIND_FLAG_EXACT_MATCH : 0); - - // Entries that are blacklisted or do not represent a word should not be output. - const bool isValidWord = !terminalDicNode->isBlacklistedOrNotAWord(); - - // Increase output score of top typing suggestion to ensure autocorrection. - // TODO: Better integration with java side autocorrection logic. - const int finalScore = SCORING->calculateFinalScore( - compoundDistance, traverseSession->getInputSize(), - terminalDicNode->isExactMatch() - || (forceCommitMultiWords && terminalDicNode->hasMultipleWords()) - || (isValidWord && SCORING->doesAutoCorrectValidWord())); - if (maxScore < finalScore && isValidWord) { - maxScore = finalScore; - } - - // Don't output invalid words. However, we still need to submit their shortcuts if any. - if (isValidWord) { - outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags; - frequencies[outputWordIndex] = finalScore; - if (outputSecondWordFirstLetterInputIndex) { - outputIndicesToPartialCommit[outputWordIndex] = - terminalDicNode->getSecondWordFirstInputIndex( - traverseSession->getProximityInfoState(0)); - } else { - outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX; - } - // Populate the outputChars array with the suggested word. - const int startIndex = outputWordIndex * MAX_WORD_LENGTH; - terminalDicNode->outputResult(&outputCodePoints[startIndex]); - ++outputWordIndex; - } - - if (!terminalDicNode->hasMultipleWords()) { - BinaryDictionaryShortcutIterator shortcutIt( - traverseSession->getDictionaryStructurePolicy()->getShortcutsStructurePolicy(), - traverseSession->getDictionaryStructurePolicy() - ->getShortcutPositionOfPtNode(terminalDicNode->getPos())); - // Shortcut is not supported for multiple words suggestions. - // TODO: Check shortcuts during traversal for multiple words suggestions. - const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode); - const int updatedOutputWordIndex = ShortcutUtils::outputShortcuts(&shortcutIt, - outputWordIndex, finalScore, outputCodePoints, frequencies, outputTypes, - sameAsTyped); - const int secondWordFirstInputIndex = terminalDicNode->getSecondWordFirstInputIndex( - traverseSession->getProximityInfoState(0)); - for (int i = outputWordIndex; i < updatedOutputWordIndex; ++i) { - if (outputSecondWordFirstLetterInputIndex) { - outputIndicesToPartialCommit[i] = secondWordFirstInputIndex; - } else { - outputIndicesToPartialCommit[i] = NOT_AN_INDEX; - } - } - outputWordIndex = updatedOutputWordIndex; - } - DicNode::managedDelete(terminalDicNode); - } - - if (hasMostProbableString) { - SCORING->safetyNetForMostProbableString(terminalSize, maxScore, - &outputCodePoints[0], &frequencies[0]); - } - return outputWordIndex; -} - -int Suggest::computeFirstWordConfidence(const DicNode *const terminalDicNode) const { - // Get the number of spaces in the first suggestion - const int spaceCount = terminalDicNode->getTotalNodeSpaceCount(); - // Get the number of characters in the first suggestion - const int length = terminalDicNode->getTotalNodeCodePointCount(); - // Get the distance for the first word of the suggestion - const float distance = terminalDicNode->getNormalizedCompoundDistanceAfterFirstWord(); - - // Arbitrarily, we give a score whose useful values range from 0 to 1,000,000. - // 1,000,000 will be the cutoff to auto-commit. It's fine if the number is under 0 or - // above 1,000,000 : under 0 just means it's very bad to commit, and above 1,000,000 means - // we are very confident. - // Expected space count is 1 ~ 5 - static const int MIN_EXPECTED_SPACE_COUNT = 1; - static const int MAX_EXPECTED_SPACE_COUNT = 5; - // Expected length is about 4 ~ 30 - static const int MIN_EXPECTED_LENGTH = 4; - static const int MAX_EXPECTED_LENGTH = 30; - // Expected distance is about 0.2 ~ 2.0, but consider 0.0 ~ 2.0 - static const float MIN_EXPECTED_DISTANCE = 0.0; - static const float MAX_EXPECTED_DISTANCE = 2.0; - // This is not strict: it's where most stuff will be falling, but it's still fine if it's - // outside these values. We want to output a value that reflects all of these. Each factor - // contributes a bit. - - // We need at least a space. - if (spaceCount < 1) return NOT_A_FIRST_WORD_CONFIDENCE; - - // The smaller the edit distance, the higher the contribution. MIN_EXPECTED_DISTANCE means 0 - // contribution, while MAX_EXPECTED_DISTANCE means full contribution according to the - // weight of the distance. Clamp to avoid overflows. - const float clampedDistance = distance < MIN_EXPECTED_DISTANCE ? MIN_EXPECTED_DISTANCE - : distance > MAX_EXPECTED_DISTANCE ? MAX_EXPECTED_DISTANCE : distance; - const int distanceContribution = DISTANCE_WEIGHT_FOR_AUTO_COMMIT - * (MAX_EXPECTED_DISTANCE - clampedDistance) - / (MAX_EXPECTED_DISTANCE - MIN_EXPECTED_DISTANCE); - // The larger the suggestion length, the larger the contribution. MIN_EXPECTED_LENGTH is no - // contribution, MAX_EXPECTED_LENGTH is full contribution according to the weight of the - // length. Length is guaranteed to be between 1 and 48, so we don't need to clamp. - const int lengthContribution = LENGTH_WEIGHT_FOR_AUTO_COMMIT - * (length - MIN_EXPECTED_LENGTH) / (MAX_EXPECTED_LENGTH - MIN_EXPECTED_LENGTH); - // The more spaces, the larger the contribution. MIN_EXPECTED_SPACE_COUNT space is no - // contribution, MAX_EXPECTED_SPACE_COUNT spaces is full contribution according to the - // weight of the space count. - const int spaceContribution = SPACE_COUNT_WEIGHT_FOR_AUTO_COMMIT - * (spaceCount - MIN_EXPECTED_SPACE_COUNT) - / (MAX_EXPECTED_SPACE_COUNT - MIN_EXPECTED_SPACE_COUNT); - - return distanceContribution + lengthContribution + spaceContribution; -} - -/** * Expands the dicNodes in the current search priority queue by advancing to the possible child * nodes based on the next touch point(s) (or no touch points for lookahead) */ @@ -421,15 +208,15 @@ void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const { } break; case UNRELATED_CHAR: - // Just drop this node and do nothing. + // Just drop this dicNode and do nothing. break; default: - // Just drop this node and do nothing. + // Just drop this dicNode and do nothing. break; } } - // Push the node for look-ahead correction + // Push the dicNode for look-ahead correction if (allowsErrorCorrections && canDoLookAheadCorrection) { traverseSession->getDicTraverseCache()->copyPushNextActive(&dicNode); } @@ -442,15 +229,17 @@ void Suggest::processTerminalDicNode( if (dicNode->getCompoundDistance() >= static_cast<float>(MAX_VALUE_FOR_WEIGHTING)) { return; } - if (!dicNode->isTerminalWordNode()) { + if (!dicNode->isTerminalDicNode()) { return; } if (dicNode->shouldBeFilteredBySafetyNetForBigram()) { return; } + if (!dicNode->hasMatchedOrProximityCodePoints()) { + return; + } // Create a non-cached node here. - DicNode terminalDicNode; - DicNodeUtils::initByCopy(dicNode, &terminalDicNode); + DicNode terminalDicNode(*dicNode); if (TRAVERSAL->needsToTraverseAllUserInput() && dicNode->getInputIndex(0) < traverseSession->getInputSize()) { Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_TERMINAL_INSERTION, traverseSession, 0, @@ -463,7 +252,7 @@ void Suggest::processTerminalDicNode( /** * Adds the expanded dicNode to the next search priority queue. Also creates an additional next word - * (by the space omission error correction) search path if input dicNode is on a terminal node. + * (by the space omission error correction) search path if input dicNode is on a terminal. */ void Suggest::processExpandedDicNode( DicTraverseSession *traverseSession, DicNode *dicNode) const { @@ -478,7 +267,6 @@ void Suggest::processExpandedDicNode( traverseSession->getDicTraverseCache()->copyPushNextActive(dicNode); } } - DicNode::managedDelete(dicNode); } void Suggest::processDicNodeAsMatch(DicTraverseSession *traverseSession, @@ -505,7 +293,7 @@ void Suggest::processDicNodeAsSubstitution(DicTraverseSession *traverseSession, processExpandedDicNode(traverseSession, childDicNode); } -// Process the node codepoint as a digraph. This means that composite glyphs like the German +// Process the DicNode codepoint as a digraph. This means that composite glyphs like the German // u-umlaut is expanded to the transliteration "ue". Note that this happens in parallel with // the normal non-digraph traversal, so both "uber" and "ueber" can be corrected to "[u-umlaut]ber". void Suggest::processDicNodeAsDigraph(DicTraverseSession *traverseSession, @@ -518,7 +306,7 @@ void Suggest::processDicNodeAsDigraph(DicTraverseSession *traverseSession, /** * Handle the dicNode as an omission error (e.g., ths => this). Skip the current letter and consider * matches for all possible next letters. Note that just skipping the current letter without any - * other conditions tends to flood the search dic nodes cache with omission nodes. Instead, check + * other conditions tends to flood the search DicNodes cache with omission DicNodes. Instead, check * the possible *next* letters after the omission to better limit search to plausible omissions. * Note that apostrophes are handled as omissions. */ @@ -572,6 +360,7 @@ void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession, DicNode *dicNode) const { const int16_t pointIndex = dicNode->getInputIndex(0); DicNodeVector childDicNodes1; + DicNodeVector childDicNodes2; DicNodeUtils::getAllChildDicNodes(dicNode, traverseSession->getDictionaryStructurePolicy(), &childDicNodes1); const int childSize1 = childDicNodes1.getSizeAndLock(); @@ -583,7 +372,7 @@ void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession, continue; } if (childDicNodes1[i]->hasChildren()) { - DicNodeVector childDicNodes2; + childDicNodes2.clear(); DicNodeUtils::getAllChildDicNodes(childDicNodes1[i], traverseSession->getDictionaryStructurePolicy(), &childDicNodes2); const int childSize2 = childDicNodes2.getSizeAndLock(); @@ -600,12 +389,11 @@ void Suggest::processDicNodeAsTransposition(DicTraverseSession *traverseSession, processExpandedDicNode(traverseSession, childDicNode2); } } - DicNode::managedDelete(childDicNodes1[i]); } } /** - * Weight child node by aligning it to the key + * Weight child dicNode by aligning it to the key */ void Suggest::weightChildNode(DicTraverseSession *traverseSession, DicNode *dicNode) const { const int inputSize = traverseSession->getInputSize(); diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h index b20343d29..788e0314b 100644 --- a/native/jni/src/suggest/core/suggest.h +++ b/native/jni/src/suggest/core/suggest.h @@ -36,37 +36,30 @@ class DicNode; class DicTraverseSession; class ProximityInfo; class Scoring; +class SuggestionResults; class Traversal; class Weighting; class Suggest : public SuggestInterface { public: AK_FORCE_INLINE Suggest(const SuggestPolicy *const suggestPolicy) - : TRAVERSAL(suggestPolicy ? suggestPolicy->getTraversal() : 0), - SCORING(suggestPolicy ? suggestPolicy->getScoring() : 0), - WEIGHTING(suggestPolicy ? suggestPolicy->getWeighting() : 0) {} + : TRAVERSAL(suggestPolicy ? suggestPolicy->getTraversal() : nullptr), + SCORING(suggestPolicy ? suggestPolicy->getScoring() : nullptr), + WEIGHTING(suggestPolicy ? suggestPolicy->getWeighting() : nullptr) {} AK_FORCE_INLINE virtual ~Suggest() {} - int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, - int *times, int *pointerIds, int *inputCodePoints, int inputSize, int commitPoint, - int *outWords, int *frequencies, int *outputIndices, int *outputTypes, - int *outputAutoCommitFirstWordConfidence) const; + void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, + int *times, int *pointerIds, int *inputCodePoints, int inputSize, + const float languageWeight, SuggestionResults *const outSuggestionResults) const; private: DISALLOW_IMPLICIT_CONSTRUCTORS(Suggest); void createNextWordDicNode(DicTraverseSession *traverseSession, DicNode *dicNode, const bool spaceSubstitution) const; - int outputSuggestions(DicTraverseSession *traverseSession, int *frequencies, - int *outputCodePoints, int *outputIndicesToPartialCommit, int *outputTypes, - int *outputAutoCommitFirstWordConfidence) const; - int computeFirstWordConfidence(const DicNode *const terminalDicNode) const; - void initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const; + void initializeSearch(DicTraverseSession *traverseSession) const; void expandCurrentDicNodes(DicTraverseSession *traverseSession) const; void processTerminalDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; void processExpandedDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; void weightChildNode(DicTraverseSession *traverseSession, DicNode *dicNode) const; - float getAutocorrectScore(DicTraverseSession *traverseSession, DicNode *dicNode) const; - void generateFeatures( - DicTraverseSession *traverseSession, DicNode *dicNode, float *features) const; void processDicNodeAsOmission(DicTraverseSession *traverseSession, DicNode *dicNode) const; void processDicNodeAsDigraph(DicTraverseSession *traverseSession, DicNode *dicNode) const; void processDicNodeAsTransposition(DicTraverseSession *traverseSession, @@ -79,13 +72,8 @@ class Suggest : public SuggestInterface { void processDicNodeAsMatch(DicTraverseSession *traverseSession, DicNode *childDicNode) const; - // Inputs longer than this will autocorrect if the suggestion is multi-word - static const int MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT; static const int MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE; - // Threshold for autocorrection classifier - static const float AUTOCORRECT_CLASSIFICATION_THRESHOLD; - const Traversal *const TRAVERSAL; const Scoring *const SCORING; const Weighting *const WEIGHTING; diff --git a/native/jni/src/suggest/core/suggest_interface.h b/native/jni/src/suggest/core/suggest_interface.h index 4deb4d924..a6e5aefae 100644 --- a/native/jni/src/suggest/core/suggest_interface.h +++ b/native/jni/src/suggest/core/suggest_interface.h @@ -22,13 +22,13 @@ namespace latinime { class ProximityInfo; +class SuggestionResults; class SuggestInterface { public: - virtual int getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, + virtual void getSuggestions(ProximityInfo *pInfo, void *traverseSession, int *inputXs, int *inputYs, int *times, int *pointerIds, int *inputCodePoints, int inputSize, - int commitPoint, int *outWords, int *frequencies, int *outputIndices, - int *outputTypes, int *outputAutoCommitFirstWordConfidence) const = 0; + const float languageWeight, SuggestionResults *const suggestionResults) const = 0; SuggestInterface() {} virtual ~SuggestInterface() {} private: diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h index 6ff95cac4..a898e2afc 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h @@ -17,7 +17,7 @@ #ifndef LATINIME_BIGRAM_LIST_POLICY_H #define LATINIME_BIGRAM_LIST_POLICY_H -#include <stdint.h> +#include <cstdint> #include "defines.h" #include "suggest/core/policy/dictionary_bigrams_structure_policy.h" diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp index 1926b9831..7d0d09631 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp @@ -16,7 +16,6 @@ #include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" #include "suggest/policyimpl/dictionary/utils/byte_array_utils.h" #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" @@ -38,7 +37,6 @@ const BigramListReadWriteUtils::BigramFlags BigramListReadWriteUtils::FLAG_ATTRI // Mask for attribute probability, stored on 4 bits inside the flags byte. const BigramListReadWriteUtils::BigramFlags BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F; -const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4; /* static */ void BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( const uint8_t *const bigramsBuf, BigramFlags *const outBigramFlags, @@ -79,11 +77,6 @@ const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4; offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos); break; } - if (offset == DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID) { - return NOT_A_DICT_POS; - } else if (offset == DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET) { - return origin; - } if (isOffsetNegative(flags)) { return origin - offset; } else { @@ -91,92 +84,4 @@ const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4; } } -/* static */ bool BigramListReadWriteUtils::setHasNextFlag( - BufferWithExtendableBuffer *const buffer, const bool hasNext, const int entryPos) { - const bool usesAdditionalBuffer = buffer->isInAdditionalBuffer(entryPos); - int readingPos = entryPos; - if (usesAdditionalBuffer) { - readingPos -= buffer->getOriginalBufferSize(); - } - BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition( - buffer->getBuffer(usesAdditionalBuffer), &readingPos); - if (hasNext) { - bigramFlags = bigramFlags | FLAG_ATTRIBUTE_HAS_NEXT; - } else { - bigramFlags = bigramFlags & (~FLAG_ATTRIBUTE_HAS_NEXT); - } - int writingPos = entryPos; - return buffer->writeUintAndAdvancePosition(bigramFlags, 1 /* size */, &writingPos); -} - -/* static */ bool BigramListReadWriteUtils::createAndWriteBigramEntry( - BufferWithExtendableBuffer *const buffer, const int targetPos, const int probability, - const bool hasNext, int *const writingPos) { - BigramFlags flags; - if (!createAndGetBigramFlags(*writingPos, targetPos, probability, hasNext, &flags)) { - return false; - } - return writeBigramEntry(buffer, flags, targetPos, writingPos); -} - -/* static */ bool BigramListReadWriteUtils::writeBigramEntry( - BufferWithExtendableBuffer *const bufferToWrite, const BigramFlags flags, - const int targetPtNodePos, int *const writingPos) { - const int offset = getBigramTargetOffset(targetPtNodePos, *writingPos); - const BigramFlags flagsToWrite = (offset < 0) ? - (flags | FLAG_ATTRIBUTE_OFFSET_NEGATIVE) : (flags & ~FLAG_ATTRIBUTE_OFFSET_NEGATIVE); - if (!bufferToWrite->writeUintAndAdvancePosition(flagsToWrite, 1 /* size */, writingPos)) { - return false; - } - const uint32_t absOffest = abs(offset); - const int bigramTargetFieldSize = attributeAddressSize(flags); - return bufferToWrite->writeUintAndAdvancePosition(absOffest, bigramTargetFieldSize, - writingPos); -} - -// Returns true if the bigram entry is valid and put entry flags into out*. -/* static */ bool BigramListReadWriteUtils::createAndGetBigramFlags(const int entryPos, - const int targetPtNodePos, const int probability, const bool hasNext, - BigramFlags *const outBigramFlags) { - BigramFlags flags = probability & MASK_ATTRIBUTE_PROBABILITY; - if (hasNext) { - flags |= FLAG_ATTRIBUTE_HAS_NEXT; - } - const int offset = getBigramTargetOffset(targetPtNodePos, entryPos); - if (offset < 0) { - flags |= FLAG_ATTRIBUTE_OFFSET_NEGATIVE; - } - const uint32_t absOffest = abs(offset); - if ((absOffest >> 24) != 0) { - // Offset is too large. - return false; - } else if ((absOffest >> 16) != 0) { - flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES; - } else if ((absOffest >> 8) != 0) { - flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES; - } else { - flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE; - } - // Currently, all newly written bigram position fields are 3 bytes to simplify dictionary - // writing. - // TODO: Remove following 2 lines and optimize memory space. - flags = (flags & (~MASK_ATTRIBUTE_ADDRESS_TYPE)) | FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES; - *outBigramFlags = flags; - return true; -} - -/* static */ int BigramListReadWriteUtils::getBigramTargetOffset(const int targetPtNodePos, - const int entryPos) { - if (targetPtNodePos == NOT_A_DICT_POS) { - return DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID; - } else { - const int offset = targetPtNodePos - (entryPos + 1 /* bigramFlagsField */); - if (offset == 0) { - return DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET; - } else { - return offset; - } - } -} - } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h index eabe4e099..15f924a6a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h @@ -17,8 +17,8 @@ #ifndef LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H #define LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H +#include <cstdint> #include <cstdlib> -#include <stdint.h> #include "defines.h" @@ -45,34 +45,6 @@ public: // Bigrams reading methods static void skipExistingBigrams(const uint8_t *const bigramsBuf, int *const bigramListPos); - // Returns the size of the bigram position field that is stored in bigram flags. - static AK_FORCE_INLINE int attributeAddressSize(const BigramFlags flags) { - return (flags & MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT; - /* Note: this is a value-dependant optimization of what may probably be - more readably written this way: - switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) { - case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1; - case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2; - case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3; - default: return 0; - } - */ - } - - static bool setHasNextFlag(BufferWithExtendableBuffer *const buffer, - const bool hasNext, const int entryPos); - - static AK_FORCE_INLINE BigramFlags setProbabilityInFlags(const BigramFlags flags, - const int probability) { - return (flags & (~MASK_ATTRIBUTE_PROBABILITY)) | (probability & MASK_ATTRIBUTE_PROBABILITY); - } - - static bool createAndWriteBigramEntry(BufferWithExtendableBuffer *const buffer, - const int targetPos, const int probability, const bool hasNext, int *const writingPos); - - static bool writeBigramEntry(BufferWithExtendableBuffer *const buffer, const BigramFlags flags, - const int targetOffset, int *const writingPos); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadWriteUtils); @@ -83,11 +55,6 @@ private: static const BigramFlags FLAG_ATTRIBUTE_OFFSET_NEGATIVE; static const BigramFlags FLAG_ATTRIBUTE_HAS_NEXT; static const BigramFlags MASK_ATTRIBUTE_PROBABILITY; - static const int ATTRIBUTE_ADDRESS_SHIFT; - - // Returns true if the bigram entry is valid and put entry flags into out*. - static bool createAndGetBigramFlags(const int entryPos, const int targetPos, - const int probability, const bool hasNext, BigramFlags *const outBigramFlags); static AK_FORCE_INLINE bool isOffsetNegative(const BigramFlags flags) { return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0; @@ -95,8 +62,6 @@ private: static int getBigramAddressAndAdvancePosition(const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos); - - static int getBigramTargetOffset(const int targetPtNodePos, const int entryPos); }; } // namespace latinime #endif // LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp deleted file mode 100644 index b1170e251..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h" - -#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h" -#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" -#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" - -namespace latinime { - -const int DynamicBigramListPolicy::CONTINUING_BIGRAM_LINK_COUNT_LIMIT = 10000; -const int DynamicBigramListPolicy::BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT = 100000; - -void DynamicBigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability, - bool *const outHasNext, int *const bigramEntryPos) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramEntryPos); - const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - *bigramEntryPos -= mBuffer->getOriginalBufferSize(); - } - BigramListReadWriteUtils::BigramFlags bigramFlags; - int originalBigramPos; - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(buffer, &bigramFlags, - &originalBigramPos, bigramEntryPos); - if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) { - originalBigramPos += mBuffer->getOriginalBufferSize(); - } - *outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(bigramFlags); - *outHasNext = BigramListReadWriteUtils::hasNext(bigramFlags); - if (mIsDecayingDict && !ForgettingCurveUtils::isValidEncodedProbability(*outProbability)) { - // This bigram is too weak to output. - *outBigramPos = NOT_A_DICT_POS; - } else { - *outBigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos); - } - if (usesAdditionalBuffer) { - *bigramEntryPos += mBuffer->getOriginalBufferSize(); - } -} - -void DynamicBigramListPolicy::skipAllBigrams(int *const bigramListPos) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos); - const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - *bigramListPos -= mBuffer->getOriginalBufferSize(); - } - BigramListReadWriteUtils::skipExistingBigrams(buffer, bigramListPos); - if (usesAdditionalBuffer) { - *bigramListPos += mBuffer->getOriginalBufferSize(); - } -} - -bool DynamicBigramListPolicy::copyAllBigrams(BufferWithExtendableBuffer *const bufferToWrite, - int *const fromPos, int *const toPos, int *const outBigramsCount) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*fromPos); - if (usesAdditionalBuffer) { - *fromPos -= mBuffer->getOriginalBufferSize(); - } - *outBigramsCount = 0; - BigramListReadWriteUtils::BigramFlags bigramFlags; - int bigramEntryCount = 0; - int lastWrittenEntryPos = NOT_A_DICT_POS; - do { - if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) { - AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d", - bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT); - ASSERT(false); - return false; - } - // The buffer address can be changed after calling buffer writing methods. - int originalBigramPos; - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos, - fromPos); - if (originalBigramPos == NOT_A_DICT_POS) { - // skip invalid bigram entry. - continue; - } - if (usesAdditionalBuffer) { - originalBigramPos += mBuffer->getOriginalBufferSize(); - } - const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos); - if (bigramPos == NOT_A_DICT_POS) { - // Target PtNode has been invalidated. - continue; - } - lastWrittenEntryPos = *toPos; - if (!BigramListReadWriteUtils::createAndWriteBigramEntry(bufferToWrite, bigramPos, - BigramListReadWriteUtils::getProbabilityFromFlags(bigramFlags), - BigramListReadWriteUtils::hasNext(bigramFlags), toPos)) { - return false; - } - (*outBigramsCount)++; - } while(BigramListReadWriteUtils::hasNext(bigramFlags)); - // Makes the last entry the terminal of the list. Updates the flags. - if (lastWrittenEntryPos != NOT_A_DICT_POS) { - if (!BigramListReadWriteUtils::setHasNextFlag(bufferToWrite, false /* hasNext */, - lastWrittenEntryPos)) { - return false; - } - } - if (usesAdditionalBuffer) { - *fromPos += mBuffer->getOriginalBufferSize(); - } - return true; -} - -// Finding useless bigram entries and remove them. Bigram entry is useless when the target PtNode -// has been deleted or is not a valid terminal. -bool DynamicBigramListPolicy::updateAllBigramEntriesAndDeleteUselessEntries( - int *const bigramListPos, int *const outValidBigramEntryCount) { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos); - if (usesAdditionalBuffer) { - *bigramListPos -= mBuffer->getOriginalBufferSize(); - } - DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy); - BigramListReadWriteUtils::BigramFlags bigramFlags; - int bigramEntryCount = 0; - do { - if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) { - AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d", - bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT); - ASSERT(false); - return false; - } - int bigramEntryPos = *bigramListPos; - int originalBigramPos; - // The buffer address can be changed after calling buffer writing methods. - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos, - bigramListPos); - if (usesAdditionalBuffer) { - bigramEntryPos += mBuffer->getOriginalBufferSize(); - } - if (originalBigramPos == NOT_A_DICT_POS) { - // This entry has already been removed. - continue; - } - if (usesAdditionalBuffer) { - originalBigramPos += mBuffer->getOriginalBufferSize(); - } - const int bigramTargetNodePos = - followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(bigramTargetNodePos); - if (nodeReader.isDeleted() || !nodeReader.isTerminal() - || bigramTargetNodePos == NOT_A_DICT_POS) { - // The target is no longer valid terminal. Invalidate the current bigram entry. - if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags, - NOT_A_DICT_POS /* targetPtNodePos */, &bigramEntryPos)) { - return false; - } - continue; - } - bool isRemoved = false; - if (!updateProbabilityForDecay(bigramFlags, bigramTargetNodePos, &bigramEntryPos, - &isRemoved)) { - return false; - } - if (!isRemoved) { - (*outValidBigramEntryCount) += 1; - } - } while(BigramListReadWriteUtils::hasNext(bigramFlags)); - return true; -} - -// Updates bigram target PtNode positions in the list after the placing step in GC. -bool DynamicBigramListPolicy::updateAllBigramTargetPtNodePositions(int *const bigramListPos, - const DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap *const - ptNodePositionRelocationMap, int *const outBigramEntryCount) { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos); - if (usesAdditionalBuffer) { - *bigramListPos -= mBuffer->getOriginalBufferSize(); - } - BigramListReadWriteUtils::BigramFlags bigramFlags; - int bigramEntryCount = 0; - do { - if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) { - AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d", - bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT); - ASSERT(false); - return false; - } - int bigramEntryPos = *bigramListPos; - if (usesAdditionalBuffer) { - bigramEntryPos += mBuffer->getOriginalBufferSize(); - } - int bigramTargetPtNodePos; - // The buffer address can be changed after calling buffer writing methods. - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &bigramTargetPtNodePos, - bigramListPos); - if (bigramTargetPtNodePos == NOT_A_DICT_POS) { - continue; - } - if (usesAdditionalBuffer) { - bigramTargetPtNodePos += mBuffer->getOriginalBufferSize(); - } - - DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::const_iterator it = - ptNodePositionRelocationMap->find(bigramTargetPtNodePos); - if (it != ptNodePositionRelocationMap->end()) { - bigramTargetPtNodePos = it->second; - } else { - bigramTargetPtNodePos = NOT_A_DICT_POS; - } - if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags, - bigramTargetPtNodePos, &bigramEntryPos)) { - return false; - } - } while(BigramListReadWriteUtils::hasNext(bigramFlags)); - (*outBigramEntryCount) = bigramEntryCount; - return true; -} - -bool DynamicBigramListPolicy::addNewBigramEntryToBigramList(const int bigramTargetPos, - const int probability, int *const bigramListPos, bool *const outAddedNewBigram) { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos); - if (usesAdditionalBuffer) { - *bigramListPos -= mBuffer->getOriginalBufferSize(); - } - BigramListReadWriteUtils::BigramFlags bigramFlags; - int bigramEntryCount = 0; - do { - if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) { - AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d", - bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT); - ASSERT(false); - return false; - } - int entryPos = *bigramListPos; - if (usesAdditionalBuffer) { - entryPos += mBuffer->getOriginalBufferSize(); - } - int originalBigramPos; - // The buffer address can be changed after calling buffer writing methods. - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos, - bigramListPos); - if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) { - originalBigramPos += mBuffer->getOriginalBufferSize(); - } - if (followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos) == bigramTargetPos) { - // Update this bigram entry. - *outAddedNewBigram = false; - const int originalProbability = BigramListReadWriteUtils::getProbabilityFromFlags( - bigramFlags); - const int probabilityToWrite = mIsDecayingDict ? - ForgettingCurveUtils::getUpdatedEncodedProbability(originalProbability, - probability) : probability; - const BigramListReadWriteUtils::BigramFlags updatedFlags = - BigramListReadWriteUtils::setProbabilityInFlags(bigramFlags, - probabilityToWrite); - return BigramListReadWriteUtils::writeBigramEntry(mBuffer, updatedFlags, - originalBigramPos, &entryPos); - } - if (BigramListReadWriteUtils::hasNext(bigramFlags)) { - continue; - } - // The current last entry is found. - // First, update the flags of the last entry. - if (!BigramListReadWriteUtils::setHasNextFlag(mBuffer, true /* hasNext */, entryPos)) { - *outAddedNewBigram = false; - return false; - } - if (usesAdditionalBuffer) { - *bigramListPos += mBuffer->getOriginalBufferSize(); - } - // Then, add a new entry after the last entry. - *outAddedNewBigram = true; - return writeNewBigramEntry(bigramTargetPos, probability, bigramListPos); - } while(BigramListReadWriteUtils::hasNext(bigramFlags)); - // We return directly from the while loop. - ASSERT(false); - return false; -} - -bool DynamicBigramListPolicy::writeNewBigramEntry(const int bigramTargetPos, const int probability, - int *const writingPos) { - // hasNext is false because we are adding a new bigram entry at the end of the bigram list. - const int probabilityToWrite = mIsDecayingDict ? - ForgettingCurveUtils::getUpdatedEncodedProbability(NOT_A_PROBABILITY, probability) : - probability; - return BigramListReadWriteUtils::createAndWriteBigramEntry(mBuffer, bigramTargetPos, - probabilityToWrite, false /* hasNext */, writingPos); -} - -bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int bigramTargetPos) { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(bigramListPos); - int pos = bigramListPos; - if (usesAdditionalBuffer) { - pos -= mBuffer->getOriginalBufferSize(); - } - BigramListReadWriteUtils::BigramFlags bigramFlags; - int bigramEntryCount = 0; - do { - if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) { - AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d", - bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT); - ASSERT(false); - return false; - } - int bigramEntryPos = pos; - int originalBigramPos; - // The buffer address can be changed after calling buffer writing methods. - BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos, &pos); - if (usesAdditionalBuffer) { - bigramEntryPos += mBuffer->getOriginalBufferSize(); - } - if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) { - originalBigramPos += mBuffer->getOriginalBufferSize(); - } - const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos); - if (bigramPos != bigramTargetPos) { - continue; - } - // Target entry is found. Write an invalid target position to mark the bigram invalid. - return BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags, - NOT_A_DICT_POS /* targetOffset */, &bigramEntryPos); - } while(BigramListReadWriteUtils::hasNext(bigramFlags)); - return false; -} - -int DynamicBigramListPolicy::followBigramLinkAndGetCurrentBigramPtNodePos( - const int originalBigramPos) const { - if (originalBigramPos == NOT_A_DICT_POS) { - return NOT_A_DICT_POS; - } - int currentPos = originalBigramPos; - DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(currentPos); - int bigramLinkCount = 0; - while (nodeReader.getBigramLinkedNodePos() != NOT_A_DICT_POS) { - currentPos = nodeReader.getBigramLinkedNodePos(); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(currentPos); - bigramLinkCount++; - if (bigramLinkCount > CONTINUING_BIGRAM_LINK_COUNT_LIMIT) { - AKLOGE("Bigram link is invalid. start position: %d", originalBigramPos); - ASSERT(false); - return NOT_A_DICT_POS; - } - } - return currentPos; -} - -bool DynamicBigramListPolicy::updateProbabilityForDecay( - const BigramListReadWriteUtils::BigramFlags bigramFlags, const int targetPtNodePos, - int *const bigramEntryPos, bool *const outRemoved) const { - *outRemoved = false; - if (mIsDecayingDict) { - // Update bigram probability for decaying. - const int newProbability = ForgettingCurveUtils::getEncodedProbabilityToSave( - BigramListReadWriteUtils::getProbabilityFromFlags(bigramFlags), mHeaderPolicy); - if (ForgettingCurveUtils::isValidEncodedProbability(newProbability)) { - // Write new probability. - const BigramListReadWriteUtils::BigramFlags updatedBigramFlags = - BigramListReadWriteUtils::setProbabilityInFlags( - bigramFlags, newProbability); - if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, updatedBigramFlags, - targetPtNodePos, bigramEntryPos)) { - return false; - } - } else { - // Remove current bigram entry. - *outRemoved = true; - if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags, - NOT_A_DICT_POS /* targetPtNodePos */, bigramEntryPos)) { - return false; - } - } - } - return true; -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h deleted file mode 100644 index 0504b59d5..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2013 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_DYNAMIC_BIGRAM_LIST_POLICY_H -#define LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H - -#include <stdint.h> - -#include "defines.h" -#include "suggest/core/policy/dictionary_bigrams_structure_policy.h" -#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h" - -namespace latinime { - -class BufferWithExtendableBuffer; -class DictionaryHeaderStructurePolicy; -class DictionaryShortcutsStructurePolicy; - -/* - * This is a dynamic version of BigramListPolicy and supports an additional buffer. - */ -class DynamicBigramListPolicy : public DictionaryBigramsStructurePolicy { - public: - DynamicBigramListPolicy(const DictionaryHeaderStructurePolicy *const headerPolicy, - BufferWithExtendableBuffer *const buffer, - const DictionaryShortcutsStructurePolicy *const shortcutPolicy, - const bool isDecayingDict) - : mHeaderPolicy(headerPolicy), mBuffer(buffer), mShortcutPolicy(shortcutPolicy), - mIsDecayingDict(isDecayingDict) {} - - ~DynamicBigramListPolicy() {} - - void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext, - int *const bigramEntryPos) const; - - void skipAllBigrams(int *const bigramListPos) const; - - // Copy bigrams from the bigram list that starts at fromPos in mBuffer to toPos in - // bufferToWrite and advance these positions after bigram lists. This method skips invalid - // bigram entries and write the valid bigram entry count to outBigramsCount. - bool copyAllBigrams(BufferWithExtendableBuffer *const bufferToWrite, int *const fromPos, - int *const toPos, int *const outBigramsCount) const; - - bool updateAllBigramEntriesAndDeleteUselessEntries(int *const bigramListPos, - int *const outBigramEntryCount); - - bool updateAllBigramTargetPtNodePositions(int *const bigramListPos, - const DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap *const - ptNodePositionRelocationMap, int *const outValidBigramEntryCount); - - bool addNewBigramEntryToBigramList(const int bigramTargetPos, const int probability, - int *const bigramListPos, bool *const outAddedNewBigram); - - bool writeNewBigramEntry(const int bigramTargetPos, const int probability, - int *const writingPos); - - // Return whether or not targetBigramPos is found. - bool removeBigram(const int bigramListPos, const int bigramTargetPos); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicBigramListPolicy); - - static const int CONTINUING_BIGRAM_LINK_COUNT_LIMIT; - static const int BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT; - - const DictionaryHeaderStructurePolicy *const mHeaderPolicy; - BufferWithExtendableBuffer *const mBuffer; - const DictionaryShortcutsStructurePolicy *const mShortcutPolicy; - const bool mIsDecayingDict; - - // Follow bigram link and return the position of bigram target PtNode that is currently valid. - int followBigramLinkAndGetCurrentBigramPtNodePos(const int originalBigramPos) const; - - bool updateProbabilityForDecay(const BigramListReadWriteUtils::BigramFlags bigramFlags, - const int targetPtNodePos, int *const bigramEntryPos, bool *const outRemoved) const; -}; -} // namespace latinime -#endif // LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp new file mode 100644 index 000000000..5df2096a4 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h" + +#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { + +void Ver4BigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability, + bool *const outHasNext, int *const bigramEntryPos) const { + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(bigramEntryPos); + if (outBigramPos) { + // Lookup target PtNode position. + *outBigramPos = mTerminalPositionLookupTable->getTerminalPtNodePosition( + bigramEntry.getTargetTerminalId()); + } + if (outProbability) { + if (bigramEntry.hasHistoricalInfo()) { + *outProbability = + ForgettingCurveUtils::decodeProbability(bigramEntry.getHistoricalInfo(), + mHeaderPolicy); + } else { + *outProbability = bigramEntry.getProbability(); + } + } + if (outHasNext) { + *outHasNext = bigramEntry.hasNext(); + } +} + +bool Ver4BigramListPolicy::addNewEntry(const int terminalId, const int newTargetTerminalId, + const int newProbability, const int timestamp, bool *const outAddedNewEntry) { + if (outAddedNewEntry) { + *outAddedNewEntry = false; + } + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Updating PtNode doesn't have a bigram list. + // Create new bigram list. + if (!mBigramDictContent->createNewBigramList(terminalId)) { + return false; + } + const BigramEntry newBigramEntry(false /* hasNext */, NOT_A_PROBABILITY, + newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom(&newBigramEntry, + newProbability, timestamp); + // Write an entry. + const int writingPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (!mBigramDictContent->writeBigramEntry(&bigramEntryToWrite, writingPos)) { + return false; + } + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + return true; + } + + const int entryPosToUpdate = getEntryPosToUpdate(newTargetTerminalId, bigramListPos); + if (entryPosToUpdate != NOT_A_DICT_POS) { + // Overwrite existing entry. + const BigramEntry originalBigramEntry = + mBigramDictContent->getBigramEntry(entryPosToUpdate); + if (!originalBigramEntry.isValid()) { + // Reuse invalid entry. + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + } + const BigramEntry updatedBigramEntry = + originalBigramEntry.updateTargetTerminalIdAndGetEntry(newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom( + &updatedBigramEntry, newProbability, timestamp); + return mBigramDictContent->writeBigramEntry(&bigramEntryToWrite, entryPosToUpdate); + } + + // Add new entry to the bigram list. + // Create new bigram list. + if (!mBigramDictContent->createNewBigramList(terminalId)) { + return false; + } + // Write new entry at a head position of the bigram list. + int writingPos = mBigramDictContent->getBigramListHeadPos(terminalId); + const BigramEntry newBigramEntry(true /* hasNext */, NOT_A_PROBABILITY, newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom( + &newBigramEntry, newProbability, timestamp); + if (!mBigramDictContent->writeBigramEntryAndAdvancePosition(&bigramEntryToWrite, &writingPos)) { + return false; + } + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + // Append existing entries by copying. + return mBigramDictContent->copyBigramList(bigramListPos, writingPos); +} + +bool Ver4BigramListPolicy::removeEntry(const int terminalId, const int targetTerminalId) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return false; + } + const int entryPosToUpdate = getEntryPosToUpdate(targetTerminalId, bigramListPos); + if (entryPosToUpdate == NOT_A_DICT_POS) { + // Bigram entry doesn't exist. + return false; + } + const BigramEntry bigramEntry = mBigramDictContent->getBigramEntry(entryPosToUpdate); + if (targetTerminalId != bigramEntry.getTargetTerminalId()) { + // Bigram entry doesn't exist. + return false; + } + // Remove bigram entry by marking it as invalid entry and overwriting the original entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + return mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPosToUpdate); +} + +bool Ver4BigramListPolicy::updateAllBigramEntriesAndDeleteUselessEntries(const int terminalId, + int *const outBigramCount) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return true; + } + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!bigramEntry.isValid()) { + continue; + } + const int targetPtNodePos = mTerminalPositionLookupTable->getTerminalPtNodePosition( + bigramEntry.getTargetTerminalId()); + if (targetPtNodePos == NOT_A_DICT_POS) { + // Invalidate bigram entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + } else if (bigramEntry.hasHistoricalInfo()) { + const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave( + bigramEntry.getHistoricalInfo(), mHeaderPolicy); + if (ForgettingCurveUtils::needsToKeep(&historicalInfo, mHeaderPolicy)) { + const BigramEntry updatedBigramEntry = + bigramEntry.updateHistoricalInfoAndGetEntry(&historicalInfo); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + *outBigramCount += 1; + } else { + // Remove entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + } + } else { + *outBigramCount += 1; + } + } + return true; +} + +int Ver4BigramListPolicy::getBigramEntryConut(const int terminalId) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return 0; + } + int bigramCount = 0; + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (bigramEntry.isValid()) { + bigramCount++; + } + } + return bigramCount; +} + +int Ver4BigramListPolicy::getEntryPosToUpdate(const int targetTerminalIdToFind, + const int bigramListPos) const { + bool hasNext = true; + int invalidEntryPos = NOT_A_DICT_POS; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (bigramEntry.getTargetTerminalId() == targetTerminalIdToFind) { + // Entry with same target is found. + return entryPos; + } else if (!bigramEntry.isValid()) { + // Invalid entry that can be reused is found. + invalidEntryPos = entryPos; + } + } + return invalidEntryPos; +} + +const BigramEntry Ver4BigramListPolicy::createUpdatedBigramEntryFrom( + const BigramEntry *const originalBigramEntry, const int newProbability, + const int timestamp) const { + // TODO: Consolidate historical info and probability. + if (mHeaderPolicy->hasHistoricalInfoOfWords()) { + const HistoricalInfo updatedHistoricalInfo = + ForgettingCurveUtils::createUpdatedHistoricalInfo( + originalBigramEntry->getHistoricalInfo(), newProbability, timestamp, + mHeaderPolicy); + return originalBigramEntry->updateHistoricalInfoAndGetEntry(&updatedHistoricalInfo); + } else { + return originalBigramEntry->updateProbabilityAndGetEntry(newProbability); + } +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h new file mode 100644 index 000000000..5b6c5a173 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 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_VER4_BIGRAM_LIST_POLICY_H +#define LATINIME_VER4_BIGRAM_LIST_POLICY_H + +#include "defines.h" +#include "suggest/core/policy/dictionary_bigrams_structure_policy.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h" + +namespace latinime { + +class BigramDictContent; +class HeaderPolicy; +class TerminalPositionLookupTable; + +class Ver4BigramListPolicy : public DictionaryBigramsStructurePolicy { + public: + Ver4BigramListPolicy(BigramDictContent *const bigramDictContent, + const TerminalPositionLookupTable *const terminalPositionLookupTable, + const HeaderPolicy *const headerPolicy) + : mBigramDictContent(bigramDictContent), + mTerminalPositionLookupTable(terminalPositionLookupTable), + mHeaderPolicy(headerPolicy) {} + + void getNextBigram(int *const outBigramPos, int *const outProbability, + bool *const outHasNext, int *const bigramEntryPos) const; + + void skipAllBigrams(int *const pos) const { + // Do nothing because we don't need to skip bigram lists in ver4 dictionaries. + } + + bool addNewEntry(const int terminalId, const int newTargetTerminalId, const int newProbability, + const int timestamp, bool *const outAddedNewEntry); + + bool removeEntry(const int terminalId, const int targetTerminalId); + + bool updateAllBigramEntriesAndDeleteUselessEntries(const int terminalId, + int *const outBigramCount); + + int getBigramEntryConut(const int terminalId); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4BigramListPolicy); + + int getEntryPosToUpdate(const int targetTerminalIdToFind, const int bigramListPos) const; + + const BigramEntry createUpdatedBigramEntryFrom(const BigramEntry *const originalBigramEntry, + const int newProbability, const int timestamp) const; + + BigramDictContent *const mBigramDictContent; + const TerminalPositionLookupTable *const mTerminalPositionLookupTable; + const HeaderPolicy *const mHeaderPolicy; +}; +} // namespace latinime +#endif /* LATINIME_VER4_BIGRAM_LIST_POLICY_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp deleted file mode 100644 index ff80dd2f6..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h" - -#include <stdint.h> - -#include "defines.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h" -#include "suggest/policyimpl/dictionary/patricia_trie_policy.h" -#include "suggest/policyimpl/dictionary/utils/format_utils.h" -#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" - -namespace latinime { - -/* static */ DictionaryStructureWithBufferPolicy *DictionaryStructureWithBufferPolicyFactory - ::newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset, - const int size, const bool isUpdatable) { - // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of - // impl classes of DictionaryStructureWithBufferPolicy. - const MmappedBuffer *const mmapedBuffer = MmappedBuffer::openBuffer(path, bufOffset, size, - isUpdatable); - if (!mmapedBuffer) { - return 0; - } - switch (FormatUtils::detectFormatVersion(mmapedBuffer->getBuffer(), - mmapedBuffer->getBufferSize())) { - case FormatUtils::VERSION_2: - return new PatriciaTriePolicy(mmapedBuffer); - case FormatUtils::VERSION_3: - return new DynamicPatriciaTriePolicy(mmapedBuffer); - default: - AKLOGE("DICT: dictionary format is unknown, bad magic number"); - delete mmapedBuffer; - ASSERT(false); - return 0; - } -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp deleted file mode 100644 index 5724c5d88..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h" - -#include "suggest/core/policy/dictionary_header_structure_policy.h" -#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" - -namespace latinime { - -bool DynamicPatriciaTrieGcEventListeners - ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted - ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints) { - // PtNode is useless when the PtNode is not a terminal and doesn't have any not useless - // children. - bool isUselessPtNode = !node->isTerminal(); - if (node->isTerminal() && mIsDecayingDict) { - const int newProbability = - ForgettingCurveUtils::getEncodedProbabilityToSave(node->getProbability(), - mHeaderPolicy); - int writingPos = node->getProbabilityFieldPos(); - // Update probability. - if (!DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition( - mBuffer, newProbability, &writingPos)) { - return false; - } - if (!ForgettingCurveUtils::isValidEncodedProbability(newProbability)) { - isUselessPtNode = true; - } - } - if (mChildrenValue > 0) { - isUselessPtNode = false; - } else if (node->isTerminal()) { - // Remove children as all children are useless. - int writingPos = node->getChildrenPosFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition( - mBuffer, NOT_A_DICT_POS /* childrenPosition */, &writingPos)) { - return false; - } - } - if (isUselessPtNode) { - // Current PtNode is no longer needed. Mark it as deleted. - if (!mWritingHelper->markNodeAsDeleted(node)) { - return false; - } - } else { - mValueStack.back() += 1; - if (node->isTerminal()) { - mValidUnigramCount += 1; - } - } - return true; -} - -bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateBigramProbability - ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints) { - if (!node->isDeleted()) { - int pos = node->getBigramsPos(); - if (pos != NOT_A_DICT_POS) { - int bigramEntryCount = 0; - if (!mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries(&pos, - &bigramEntryCount)) { - return false; - } - mValidBigramEntryCount += bigramEntryCount; - } - } - return true; -} - -// Writes dummy PtNode array size when the head of PtNode array is read. -bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer - ::onDescend(const int ptNodeArrayPos) { - mValidPtNodeCount = 0; - int writingPos = mBufferToWrite->getTailPosition(); - mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.insert( - DynamicPatriciaTrieWritingHelper::PtNodeArrayPositionRelocationMap::value_type( - ptNodeArrayPos, writingPos)); - // Writes dummy PtNode array size because arrays can have a forward link or needles PtNodes. - // This field will be updated later in onReadingPtNodeArrayTail() with actual PtNode count. - mPtNodeArraySizeFieldPos = writingPos; - return DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition( - mBufferToWrite, 0 /* arraySize */, &writingPos); -} - -// Write PtNode array terminal and actual PtNode array size. -bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer - ::onReadingPtNodeArrayTail() { - int writingPos = mBufferToWrite->getTailPosition(); - // Write PtNode array terminal. - if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition( - mBufferToWrite, NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { - return false; - } - // Write actual PtNode array size. - if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition( - mBufferToWrite, mValidPtNodeCount, &mPtNodeArraySizeFieldPos)) { - return false; - } - return true; -} - -// Write valid PtNode to buffer and memorize mapping from the old position to the new position. -bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer - ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints) { - if (node->isDeleted()) { - // Current PtNode is not written in new buffer because it has been deleted. - mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert( - DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::value_type( - node->getHeadPos(), NOT_A_DICT_POS)); - return true; - } - int writingPos = mBufferToWrite->getTailPosition(); - mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert( - DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::value_type( - node->getHeadPos(), writingPos)); - mValidPtNodeCount++; - // Writes current PtNode. - return mWritingHelper->writePtNodeToBufferByCopyingPtNodeInfo(mBufferToWrite, node, - node->getParentPos(), nodeCodePoints, node->getCodePointCount(), - node->getProbability(), &writingPos); -} - -bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateAllPositionFields - ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints) { - // Updates parent position. - int parentPos = node->getParentPos(); - if (parentPos != NOT_A_DICT_POS) { - DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::const_iterator it = - mDictPositionRelocationMap->mPtNodePositionRelocationMap.find(parentPos); - if (it != mDictPositionRelocationMap->mPtNodePositionRelocationMap.end()) { - parentPos = it->second; - } - } - int writingPos = node->getHeadPos() + DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE; - // Write updated parent offset. - if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(mBufferToWrite, - parentPos, node->getHeadPos(), &writingPos)) { - return false; - } - - // Updates children position. - int childrenPos = node->getChildrenPos(); - if (childrenPos != NOT_A_DICT_POS) { - DynamicPatriciaTrieWritingHelper::PtNodeArrayPositionRelocationMap::const_iterator it = - mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.find(childrenPos); - if (it != mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.end()) { - childrenPos = it->second; - } - } - writingPos = node->getChildrenPosFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBufferToWrite, - childrenPos, &writingPos)) { - return false; - } - - // Updates bigram target PtNode positions in the bigram list. - int bigramsPos = node->getBigramsPos(); - if (bigramsPos != NOT_A_DICT_POS) { - int bigramEntryCount; - if (!mBigramPolicy->updateAllBigramTargetPtNodePositions(&bigramsPos, - &mDictPositionRelocationMap->mPtNodePositionRelocationMap, &bigramEntryCount)) { - return false; - } - mBigramCount += bigramEntryCount; - } - if (node->isTerminal()) { - mUnigramCount++; - } - - return true; -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp deleted file mode 100644 index 2fa3111d3..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2013, 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. - */ - -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h" - -#include "suggest/core/policy/dictionary_bigrams_structure_policy.h" -#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" - -namespace latinime { - -void DynamicPatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProcessMovedPtNode( - const int ptNodePos, const int maxCodePointCount, int *const outCodePoints) { - if (ptNodePos < 0 || ptNodePos >= mBuffer->getTailPosition()) { - // Reading invalid position because of bug or broken dictionary. - AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d", - ptNodePos, mBuffer->getTailPosition()); - ASSERT(false); - invalidatePtNodeInfo(); - return; - } - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodePos); - const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); - int pos = ptNodePos; - mHeadPos = ptNodePos; - if (usesAdditionalBuffer) { - pos -= mBuffer->getOriginalBufferSize(); - } - mFlags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); - const int parentPosOffset = - DynamicPatriciaTrieReadingUtils::getParentPtNodePosOffsetAndAdvancePosition(dictBuf, - &pos); - mParentPos = DynamicPatriciaTrieReadingUtils::getParentPtNodePos(parentPosOffset, mHeadPos); - if (outCodePoints != 0) { - mCodePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition( - dictBuf, mFlags, maxCodePointCount, outCodePoints, &pos); - } else { - mCodePointCount = PatriciaTrieReadingUtils::skipCharacters( - dictBuf, mFlags, MAX_WORD_LENGTH, &pos); - } - if (isTerminal()) { - mProbabilityFieldPos = pos; - if (usesAdditionalBuffer) { - mProbabilityFieldPos += mBuffer->getOriginalBufferSize(); - } - mProbability = PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictBuf, &pos); - } else { - mProbabilityFieldPos = NOT_A_DICT_POS; - mProbability = NOT_A_PROBABILITY; - } - mChildrenPosFieldPos = pos; - if (usesAdditionalBuffer) { - mChildrenPosFieldPos += mBuffer->getOriginalBufferSize(); - } - mChildrenPos = DynamicPatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition( - dictBuf, &pos); - if (usesAdditionalBuffer && mChildrenPos != NOT_A_DICT_POS) { - mChildrenPos += mBuffer->getOriginalBufferSize(); - } - if (mSiblingPos == NOT_A_DICT_POS) { - if (DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) { - mBigramLinkedNodePos = mChildrenPos; - } else { - mBigramLinkedNodePos = NOT_A_DICT_POS; - } - } - if (usesAdditionalBuffer) { - pos += mBuffer->getOriginalBufferSize(); - } - if (PatriciaTrieReadingUtils::hasShortcutTargets(mFlags)) { - mShortcutPos = pos; - mShortcutsPolicy->skipAllShortcuts(&pos); - } else { - mShortcutPos = NOT_A_DICT_POS; - } - if (PatriciaTrieReadingUtils::hasBigrams(mFlags)) { - mBigramPos = pos; - mBigramsPolicy->skipAllBigrams(&pos); - } else { - mBigramPos = NOT_A_DICT_POS; - } - // Update siblingPos if needed. - if (mSiblingPos == NOT_A_DICT_POS) { - // Sibling position is the tail position of current node. - mSiblingPos = pos; - } - // Read destination node if the read node is a moved node. - if (DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) { - // The destination position is stored at the same place as the parent position. - fetchPtNodeInfoFromBufferAndProcessMovedPtNode(mParentPos, maxCodePointCount, - outCodePoints); - } -} - -void DynamicPatriciaTrieNodeReader::invalidatePtNodeInfo() { - mHeadPos = NOT_A_DICT_POS; - mFlags = 0; - mParentPos = NOT_A_DICT_POS; - mCodePointCount = 0; - mProbabilityFieldPos = NOT_A_DICT_POS; - mProbability = NOT_A_PROBABILITY; - mChildrenPosFieldPos = NOT_A_DICT_POS; - mChildrenPos = NOT_A_DICT_POS; - mBigramLinkedNodePos = NOT_A_DICT_POS; - mShortcutPos = NOT_A_DICT_POS; - mBigramPos = NOT_A_DICT_POS; - mSiblingPos = NOT_A_DICT_POS; -} - -} diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h deleted file mode 100644 index 3b36d425f..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2013, 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_DYNAMIC_PATRICIA_TRIE_NODE_READER_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H - -#include <stdint.h> - -#include "defines.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" - -namespace latinime { - -class BufferWithExtendableBuffer; -class DictionaryBigramsStructurePolicy; -class DictionaryShortcutsStructurePolicy; - -/* - * This class is used for helping to read nodes of dynamic patricia trie. This class handles moved - * node and reads node attributes. - */ -class DynamicPatriciaTrieNodeReader { - public: - DynamicPatriciaTrieNodeReader(const BufferWithExtendableBuffer *const buffer, - const DictionaryBigramsStructurePolicy *const bigramsPolicy, - const DictionaryShortcutsStructurePolicy *const shortcutsPolicy) - : mBuffer(buffer), mBigramsPolicy(bigramsPolicy), - mShortcutsPolicy(shortcutsPolicy), mHeadPos(NOT_A_DICT_POS), mFlags(0), - mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mProbabilityFieldPos(NOT_A_DICT_POS), - mProbability(NOT_A_PROBABILITY), mChildrenPosFieldPos(NOT_A_DICT_POS), - mChildrenPos(NOT_A_DICT_POS), mBigramLinkedNodePos(NOT_A_DICT_POS), - mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS), - mSiblingPos(NOT_A_DICT_POS) {} - - ~DynamicPatriciaTrieNodeReader() {} - - // Reads PtNode information from dictionary buffer and updates members with the information. - AK_FORCE_INLINE void fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) { - fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(ptNodePos , - 0 /* maxCodePointCount */, 0 /* outCodePoints */); - } - - AK_FORCE_INLINE void fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints( - const int ptNodePos, const int maxCodePointCount, int *const outCodePoints) { - mSiblingPos = NOT_A_DICT_POS; - mBigramLinkedNodePos = NOT_A_DICT_POS; - fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, maxCodePointCount, outCodePoints); - } - - // HeadPos is different from NodePos when the current PtNode is a moved PtNode. - AK_FORCE_INLINE int getHeadPos() const { - return mHeadPos; - } - - // Flags - AK_FORCE_INLINE bool isDeleted() const { - return DynamicPatriciaTrieReadingUtils::isDeleted(mFlags); - } - - AK_FORCE_INLINE bool hasChildren() const { - return mChildrenPos != NOT_A_DICT_POS; - } - - AK_FORCE_INLINE bool isTerminal() const { - return PatriciaTrieReadingUtils::isTerminal(mFlags); - } - - AK_FORCE_INLINE bool isBlacklisted() const { - return PatriciaTrieReadingUtils::isBlacklisted(mFlags); - } - - AK_FORCE_INLINE bool isNotAWord() const { - return PatriciaTrieReadingUtils::isNotAWord(mFlags); - } - - // Parent node position - AK_FORCE_INLINE int getParentPos() const { - return mParentPos; - } - - // Number of code points - AK_FORCE_INLINE uint8_t getCodePointCount() const { - return mCodePointCount; - } - - // Probability - AK_FORCE_INLINE int getProbabilityFieldPos() const { - return mProbabilityFieldPos; - } - - AK_FORCE_INLINE int getProbability() const { - return mProbability; - } - - // Children PtNode array position - AK_FORCE_INLINE int getChildrenPosFieldPos() const { - return mChildrenPosFieldPos; - } - - AK_FORCE_INLINE int getChildrenPos() const { - return mChildrenPos; - } - - // Bigram linked node position. - AK_FORCE_INLINE int getBigramLinkedNodePos() const { - return mBigramLinkedNodePos; - } - - // Shortcutlist position - AK_FORCE_INLINE int getShortcutPos() const { - return mShortcutPos; - } - - // Bigrams position - AK_FORCE_INLINE int getBigramsPos() const { - return mBigramPos; - } - - // Sibling node position - AK_FORCE_INLINE int getSiblingNodePos() const { - return mSiblingPos; - } - - private: - DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieNodeReader); - - const BufferWithExtendableBuffer *const mBuffer; - const DictionaryBigramsStructurePolicy *const mBigramsPolicy; - const DictionaryShortcutsStructurePolicy *const mShortcutsPolicy; - int mHeadPos; - DynamicPatriciaTrieReadingUtils::NodeFlags mFlags; - int mParentPos; - uint8_t mCodePointCount; - int mProbabilityFieldPos; - int mProbability; - int mChildrenPosFieldPos; - int mChildrenPos; - int mBigramLinkedNodePos; - int mShortcutPos; - int mBigramPos; - int mSiblingPos; - - void fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos, - const int maxCodePointCount, int *const outCodePoints); - - void invalidatePtNodeInfo(); -}; -} // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp deleted file mode 100644 index 495b146c2..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2013, 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. - */ - -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h" - -#include <cstdio> -#include <cstring> -#include <ctime> - -#include "defines.h" -#include "suggest/core/dicnode/dic_node.h" -#include "suggest/core/dicnode/dic_node_vector.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h" -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" -#include "suggest/policyimpl/dictionary/utils/probability_utils.h" - -namespace latinime { - -// Note that these are corresponding definitions in Java side in BinaryDictionaryTests and -// BinaryDictionaryDecayingTests. -const char *const DynamicPatriciaTriePolicy::UNIGRAM_COUNT_QUERY = "UNIGRAM_COUNT"; -const char *const DynamicPatriciaTriePolicy::BIGRAM_COUNT_QUERY = "BIGRAM_COUNT"; -const char *const DynamicPatriciaTriePolicy::MAX_UNIGRAM_COUNT_QUERY = "MAX_UNIGRAM_COUNT"; -const char *const DynamicPatriciaTriePolicy::MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; -const char *const DynamicPatriciaTriePolicy::SET_NEEDS_TO_DECAY_FOR_TESTING_QUERY = - "SET_NEEDS_TO_DECAY_FOR_TESTING"; -const int DynamicPatriciaTriePolicy::MAX_DICT_EXTENDED_REGION_SIZE = 1024 * 1024; -const int DynamicPatriciaTriePolicy::MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS = - DynamicPatriciaTrieWritingHelper::MAX_DICTIONARY_SIZE - 1024; - -void DynamicPatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode, - DicNodeVector *const childDicNodes) const { - if (!dicNode->hasChildren()) { - return; - } - DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - readingHelper.initWithPtNodeArrayPos(dicNode->getChildrenPos()); - const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader(); - while (!readingHelper.isEnd()) { - bool isTerminal = nodeReader->isTerminal() && !nodeReader->isDeleted(); - if (isTerminal && mHeaderPolicy.isDecayingDict()) { - // A DecayingDict may have a terminal PtNode that has a terminal DicNode whose - // probability is NOT_A_PROBABILITY. In such case, we don't want to treat it as a - // valid terminal DicNode. - isTerminal = getProbability(nodeReader->getProbability(), NOT_A_PROBABILITY) - != NOT_A_PROBABILITY; - } - childDicNodes->pushLeavingChild(dicNode, nodeReader->getHeadPos(), - nodeReader->getChildrenPos(), nodeReader->getProbability(), isTerminal, - nodeReader->hasChildren(), nodeReader->isBlacklisted() || nodeReader->isNotAWord(), - nodeReader->getCodePointCount(), readingHelper.getMergedNodeCodePoints()); - readingHelper.readNextSiblingNode(); - } -} - -int DynamicPatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( - const int ptNodePos, const int maxCodePointCount, int *const outCodePoints, - int *const outUnigramProbability) const { - // This method traverses parent nodes from the terminal by following parent pointers; thus, - // node code points are stored in the buffer in the reverse order. - int reverseCodePoints[maxCodePointCount]; - DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - // First, read the terminal node and get its probability. - readingHelper.initWithPtNodePos(ptNodePos); - if (!readingHelper.isValidTerminalNode()) { - // Node at the ptNodePos is not a valid terminal node. - *outUnigramProbability = NOT_A_PROBABILITY; - return 0; - } - // Store terminal node probability. - *outUnigramProbability = readingHelper.getNodeReader()->getProbability(); - // Then, following parent node link to the dictionary root and fetch node code points. - while (!readingHelper.isEnd()) { - if (readingHelper.getTotalCodePointCount() > maxCodePointCount) { - // The ptNodePos is not a valid terminal node position in the dictionary. - *outUnigramProbability = NOT_A_PROBABILITY; - return 0; - } - // Store node code points to buffer in the reverse order. - readingHelper.fetchMergedNodeCodePointsInReverseOrder( - readingHelper.getPrevTotalCodePointCount(), reverseCodePoints); - // Follow parent node toward the root node. - readingHelper.readParentNode(); - } - if (readingHelper.isError()) { - // The node position or the dictionary is invalid. - *outUnigramProbability = NOT_A_PROBABILITY; - return 0; - } - // Reverse the stored code points to output them. - const int codePointCount = readingHelper.getTotalCodePointCount(); - for (int i = 0; i < codePointCount; ++i) { - outCodePoints[i] = reverseCodePoints[codePointCount - i - 1]; - } - return codePointCount; -} - -int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord, - const int length, const bool forceLowerCaseSearch) const { - int searchCodePoints[length]; - for (int i = 0; i < length; ++i) { - searchCodePoints[i] = forceLowerCaseSearch ? CharUtils::toLowerCase(inWord[i]) : inWord[i]; - } - DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - readingHelper.initWithPtNodeArrayPos(getRootPosition()); - const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader(); - while (!readingHelper.isEnd()) { - const int matchedCodePointCount = readingHelper.getPrevTotalCodePointCount(); - if (readingHelper.getTotalCodePointCount() > length - || !readingHelper.isMatchedCodePoint(0 /* index */, - searchCodePoints[matchedCodePointCount])) { - // Current node has too many code points or its first code point is different from - // target code point. Skip this node and read the next sibling node. - readingHelper.readNextSiblingNode(); - continue; - } - // Check following merged node code points. - const int nodeCodePointCount = nodeReader->getCodePointCount(); - for (int j = 1; j < nodeCodePointCount; ++j) { - if (!readingHelper.isMatchedCodePoint( - j, searchCodePoints[matchedCodePointCount + j])) { - // Different code point is found. The given word is not included in the dictionary. - return NOT_A_DICT_POS; - } - } - // All characters are matched. - if (length == readingHelper.getTotalCodePointCount()) { - // Terminal position is found. - return nodeReader->getHeadPos(); - } - if (!nodeReader->hasChildren()) { - return NOT_A_DICT_POS; - } - // Advance to the children nodes. - readingHelper.readChildNode(); - } - // If we already traversed the tree further than the word is long, there means - // there was no match (or we would have found it). - return NOT_A_DICT_POS; -} - -int DynamicPatriciaTriePolicy::getProbability(const int unigramProbability, - const int bigramProbability) const { - if (mHeaderPolicy.isDecayingDict()) { - return ForgettingCurveUtils::getProbability(unigramProbability, bigramProbability); - } else { - if (unigramProbability == NOT_A_PROBABILITY) { - return NOT_A_PROBABILITY; - } else if (bigramProbability == NOT_A_PROBABILITY) { - return ProbabilityUtils::backoff(unigramProbability); - } else { - return ProbabilityUtils::computeProbabilityForBigram(unigramProbability, - bigramProbability); - } - } -} - -int DynamicPatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { - return NOT_A_PROBABILITY; - } - DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); - if (nodeReader.isDeleted() || nodeReader.isBlacklisted() || nodeReader.isNotAWord()) { - return NOT_A_PROBABILITY; - } - return getProbability(nodeReader.getProbability(), NOT_A_PROBABILITY); -} - -int DynamicPatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { - return NOT_A_DICT_POS; - } - DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); - if (nodeReader.isDeleted()) { - return NOT_A_DICT_POS; - } - return nodeReader.getShortcutPos(); -} - -int DynamicPatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const { - if (ptNodePos == NOT_A_DICT_POS) { - return NOT_A_DICT_POS; - } - DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); - if (nodeReader.isDeleted()) { - return NOT_A_DICT_POS; - } - return nodeReader.getBigramsPos(); -} - -bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int length, - const int probability) { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary."); - return false; - } - if (mBufferWithExtendableBuffer.getTailPosition() - >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { - AKLOGE("The dictionary is too large to dynamically update."); - return false; - } - DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer, - getBigramsStructurePolicy(), getShortcutsStructurePolicy()); - readingHelper.initWithPtNodeArrayPos(getRootPosition()); - DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer, - &mBigramListPolicy, &mShortcutListPolicy, mHeaderPolicy.isDecayingDict()); - bool addedNewUnigram = false; - if (writingHelper.addUnigramWord(&readingHelper, word, length, probability, - &addedNewUnigram)) { - if (addedNewUnigram) { - mUnigramCount++; - } - return true; - } else { - return false; - } -} - -bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int length0, - const int *const word1, const int length1, const int probability) { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); - return false; - } - if (mBufferWithExtendableBuffer.getTailPosition() - >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { - AKLOGE("The dictionary is too large to dynamically update."); - return false; - } - const int word0Pos = getTerminalNodePositionOfWord(word0, length0, - false /* forceLowerCaseSearch */); - if (word0Pos == NOT_A_DICT_POS) { - return false; - } - const int word1Pos = getTerminalNodePositionOfWord(word1, length1, - false /* forceLowerCaseSearch */); - if (word1Pos == NOT_A_DICT_POS) { - return false; - } - DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer, - &mBigramListPolicy, &mShortcutListPolicy, mHeaderPolicy.isDecayingDict()); - bool addedNewBigram = false; - if (writingHelper.addBigramWords(word0Pos, word1Pos, probability, &addedNewBigram)) { - if (addedNewBigram) { - mBigramCount++; - } - return true; - } else { - return false; - } -} - -bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0, - const int *const word1, const int length1) { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: removeBigramWords() is called for non-updatable dictionary."); - return false; - } - if (mBufferWithExtendableBuffer.getTailPosition() - >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { - AKLOGE("The dictionary is too large to dynamically update."); - return false; - } - const int word0Pos = getTerminalNodePositionOfWord(word0, length0, - false /* forceLowerCaseSearch */); - if (word0Pos == NOT_A_DICT_POS) { - return false; - } - const int word1Pos = getTerminalNodePositionOfWord(word1, length1, - false /* forceLowerCaseSearch */); - if (word1Pos == NOT_A_DICT_POS) { - return false; - } - DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer, - &mBigramListPolicy, &mShortcutListPolicy, mHeaderPolicy.isDecayingDict()); - if (writingHelper.removeBigramWords(word0Pos, word1Pos)) { - mBigramCount--; - return true; - } else { - return false; - } -} - -void DynamicPatriciaTriePolicy::flush(const char *const filePath) { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: flush() is called for non-updatable dictionary."); - return; - } - DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer, - &mBigramListPolicy, &mShortcutListPolicy, false /* needsToDecay */); - writingHelper.writeToDictFile(filePath, &mHeaderPolicy, mUnigramCount, mBigramCount); -} - -void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary."); - return; - } - const bool needsToDecay = mHeaderPolicy.isDecayingDict() - && (mNeedsToDecayForTesting || ForgettingCurveUtils::needsToDecay( - false /* mindsBlockByDecay */, mUnigramCount, mBigramCount, &mHeaderPolicy)); - DynamicBigramListPolicy bigramListPolicyForGC(&mHeaderPolicy, &mBufferWithExtendableBuffer, - &mShortcutListPolicy, needsToDecay); - DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer, - &bigramListPolicyForGC, &mShortcutListPolicy, needsToDecay); - writingHelper.writeToDictFileWithGC(getRootPosition(), filePath, &mHeaderPolicy); - mNeedsToDecayForTesting = false; -} - -bool DynamicPatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const { - if (!mBuffer->isUpdatable()) { - AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary."); - return false; - } - if (mBufferWithExtendableBuffer.isNearSizeLimit()) { - // Additional buffer size is near the limit. - return true; - } else if (mHeaderPolicy.getExtendedRegionSize() - + mBufferWithExtendableBuffer.getUsedAdditionalBufferSize() - > MAX_DICT_EXTENDED_REGION_SIZE) { - // Total extended region size exceeds the limit. - return true; - } else if (mBufferWithExtendableBuffer.getTailPosition() - >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS - && mBufferWithExtendableBuffer.getUsedAdditionalBufferSize() > 0) { - // Needs to reduce dictionary size. - return true; - } else if (mHeaderPolicy.isDecayingDict()) { - return mNeedsToDecayForTesting || ForgettingCurveUtils::needsToDecay( - mindsBlockByGC, mUnigramCount, mBigramCount, &mHeaderPolicy); - } - return false; -} - -void DynamicPatriciaTriePolicy::getProperty(const char *const query, char *const outResult, - const int maxResultLength) { - if (strncmp(query, UNIGRAM_COUNT_QUERY, maxResultLength) == 0) { - snprintf(outResult, maxResultLength, "%d", mUnigramCount); - } else if (strncmp(query, BIGRAM_COUNT_QUERY, maxResultLength) == 0) { - snprintf(outResult, maxResultLength, "%d", mBigramCount); - } else if (strncmp(query, MAX_UNIGRAM_COUNT_QUERY, maxResultLength) == 0) { - snprintf(outResult, maxResultLength, "%d", - mHeaderPolicy.isDecayingDict() ? ForgettingCurveUtils::MAX_UNIGRAM_COUNT : - static_cast<int>(DynamicPatriciaTrieWritingHelper::MAX_DICTIONARY_SIZE)); - } else if (strncmp(query, MAX_BIGRAM_COUNT_QUERY, maxResultLength) == 0) { - snprintf(outResult, maxResultLength, "%d", - mHeaderPolicy.isDecayingDict() ? ForgettingCurveUtils::MAX_BIGRAM_COUNT : - static_cast<int>(DynamicPatriciaTrieWritingHelper::MAX_DICTIONARY_SIZE)); - } else if (strncmp(query, SET_NEEDS_TO_DECAY_FOR_TESTING_QUERY, maxResultLength) == 0) { - mNeedsToDecayForTesting = true; - } -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h deleted file mode 100644 index be97ee1a5..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2013, 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_DYNAMIC_PATRICIA_TRIE_POLICY_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H - -#include "defines.h" -#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" -#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h" -#include "suggest/policyimpl/dictionary/header/header_policy.h" -#include "suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h" -#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" -#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" - -namespace latinime { - -class DicNode; -class DicNodeVector; - -class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { - public: - DynamicPatriciaTriePolicy(const MmappedBuffer *const buffer) - : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), buffer->getBufferSize()), - mBufferWithExtendableBuffer(mBuffer->getBuffer() + mHeaderPolicy.getSize(), - mBuffer->getBufferSize() - mHeaderPolicy.getSize()), - mShortcutListPolicy(&mBufferWithExtendableBuffer), - mBigramListPolicy(&mHeaderPolicy, &mBufferWithExtendableBuffer, &mShortcutListPolicy, - mHeaderPolicy.isDecayingDict()), - mUnigramCount(mHeaderPolicy.getUnigramCount()), - mBigramCount(mHeaderPolicy.getBigramCount()), mNeedsToDecayForTesting(false) {} - - ~DynamicPatriciaTriePolicy() { - delete mBuffer; - } - - AK_FORCE_INLINE int getRootPosition() const { - return 0; - } - - void createAndGetAllChildNodes(const DicNode *const dicNode, - DicNodeVector *const childDicNodes) const; - - int getCodePointsAndProbabilityAndReturnCodePointCount( - const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints, - int *const outUnigramProbability) const; - - int getTerminalNodePositionOfWord(const int *const inWord, - const int length, const bool forceLowerCaseSearch) const; - - int getProbability(const int unigramProbability, const int bigramProbability) const; - - int getUnigramProbabilityOfPtNode(const int ptNodePos) const; - - int getShortcutPositionOfPtNode(const int ptNodePos) const; - - int getBigramsPositionOfPtNode(const int ptNodePos) const; - - const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const { - return &mHeaderPolicy; - } - - const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const { - return &mBigramListPolicy; - } - - const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const { - return &mShortcutListPolicy; - } - - bool addUnigramWord(const int *const word, const int length, const int probability); - - bool addBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1, const int probability); - - bool removeBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1); - - void flush(const char *const filePath); - - void flushWithGC(const char *const filePath); - - bool needsToRunGC(const bool mindsBlockByGC) const; - - void getProperty(const char *const query, char *const outResult, - const int maxResultLength); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTriePolicy); - - static const char *const UNIGRAM_COUNT_QUERY; - static const char *const BIGRAM_COUNT_QUERY; - static const char *const MAX_UNIGRAM_COUNT_QUERY; - static const char *const MAX_BIGRAM_COUNT_QUERY; - static const char *const SET_NEEDS_TO_DECAY_FOR_TESTING_QUERY; - static const int MAX_DICT_EXTENDED_REGION_SIZE; - static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS; - - const MmappedBuffer *const mBuffer; - const HeaderPolicy mHeaderPolicy; - BufferWithExtendableBuffer mBufferWithExtendableBuffer; - DynamicShortcutListPolicy mShortcutListPolicy; - DynamicBigramListPolicy mBigramListPolicy; - int mUnigramCount; - int mBigramCount; - int mNeedsToDecayForTesting; -}; -} // namespace latinime -#endif // LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp deleted file mode 100644 index f108c219f..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2013, 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. - */ - -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h" - -#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" - -namespace latinime { - -// To avoid infinite loop caused by invalid or malicious forward links. -const int DynamicPatriciaTrieReadingHelper::MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP = 100000; -const int DynamicPatriciaTrieReadingHelper::MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP = 100000; -const size_t DynamicPatriciaTrieReadingHelper::MAX_READING_STATE_STACK_SIZE = MAX_WORD_LENGTH; - -// Visits all PtNodes in post-order depth first manner. -// For example, visits c -> b -> y -> x -> a for the following dictionary: -// a _ b _ c -// \ x _ y -bool DynamicPatriciaTrieReadingHelper::traverseAllPtNodesInPostorderDepthFirstManner( - TraversingEventListener *const listener) { - bool alreadyVisitedChildren = false; - // Descend from the root to the root PtNode array. - if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) { - return false; - } - while (!isEnd()) { - if (!alreadyVisitedChildren) { - if (mNodeReader.hasChildren()) { - // Move to the first child. - if (!listener->onDescend(mNodeReader.getChildrenPos())) { - return false; - } - pushReadingStateToStack(); - readChildNode(); - } else { - alreadyVisitedChildren = true; - } - } else { - if (!listener->onVisitingPtNode(&mNodeReader, mMergedNodeCodePoints)) { - return false; - } - readNextSiblingNode(); - if (isEnd()) { - // All PtNodes in current linked PtNode arrays have been visited. - // Return to the parent. - if (!listener->onReadingPtNodeArrayTail()) { - return false; - } - if (mReadingStateStack.size() <= 0) { - break; - } - if (!listener->onAscend()) { - return false; - } - popReadingStateFromStack(); - alreadyVisitedChildren = true; - } else { - // Process sibling PtNode. - alreadyVisitedChildren = false; - } - } - } - // Ascend from the root PtNode array to the root. - if (!listener->onAscend()) { - return false; - } - return !isError(); -} - -// Visits all PtNodes in PtNode array level pre-order depth first manner, which is the same order -// that PtNodes are written in the dictionary buffer. -// For example, visits a -> b -> x -> c -> y for the following dictionary: -// a _ b _ c -// \ x _ y -bool DynamicPatriciaTrieReadingHelper::traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( - TraversingEventListener *const listener) { - bool alreadyVisitedAllPtNodesInArray = false; - bool alreadyVisitedChildren = false; - // Descend from the root to the root PtNode array. - if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) { - return false; - } - if (isEnd()) { - // Empty dictionary. Needs to notify the listener of the tail of empty PtNode array. - if (!listener->onReadingPtNodeArrayTail()) { - return false; - } - } - pushReadingStateToStack(); - while (!isEnd()) { - if (alreadyVisitedAllPtNodesInArray) { - if (alreadyVisitedChildren) { - // Move to next sibling PtNode's children. - readNextSiblingNode(); - if (isEnd()) { - // Return to the parent PTNode. - if (!listener->onAscend()) { - return false; - } - if (mReadingStateStack.size() <= 0) { - break; - } - popReadingStateFromStack(); - alreadyVisitedChildren = true; - alreadyVisitedAllPtNodesInArray = true; - } else { - alreadyVisitedChildren = false; - } - } else { - if (mNodeReader.hasChildren()) { - // Move to the first child. - if (!listener->onDescend(mNodeReader.getChildrenPos())) { - return false; - } - pushReadingStateToStack(); - readChildNode(); - // Push state to return the head of PtNode array. - pushReadingStateToStack(); - alreadyVisitedAllPtNodesInArray = false; - alreadyVisitedChildren = false; - } else { - alreadyVisitedChildren = true; - } - } - } else { - if (!listener->onVisitingPtNode(&mNodeReader, mMergedNodeCodePoints)) { - return false; - } - readNextSiblingNode(); - if (isEnd()) { - if (!listener->onReadingPtNodeArrayTail()) { - return false; - } - // Return to the head of current PtNode array. - popReadingStateFromStack(); - alreadyVisitedAllPtNodesInArray = true; - } - } - } - popReadingStateFromStack(); - // Ascend from the root PtNode array to the root. - if (!listener->onAscend()) { - return false; - } - return !isError(); -} - -// Read node array size and process empty node arrays. Nodes and arrays are counted up in this -// method to avoid an infinite loop. -void DynamicPatriciaTrieReadingHelper::nextPtNodeArray() { - if (mReadingState.mPos < 0 || mReadingState.mPos >= mBuffer->getTailPosition()) { - // Reading invalid position because of a bug or a broken dictionary. - AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d", - mReadingState.mPos, mBuffer->getTailPosition()); - ASSERT(false); - mIsError = true; - mReadingState.mPos = NOT_A_DICT_POS; - return; - } - mReadingState.mPosOfLastPtNodeArrayHead = mReadingState.mPos; - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(mReadingState.mPos); - const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - mReadingState.mPos -= mBuffer->getOriginalBufferSize(); - } - mReadingState.mNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition( - dictBuf, &mReadingState.mPos); - if (usesAdditionalBuffer) { - mReadingState.mPos += mBuffer->getOriginalBufferSize(); - } - // Count up nodes and node arrays to avoid infinite loop. - mReadingState.mTotalNodeCount += mReadingState.mNodeCount; - mReadingState.mNodeArrayCount++; - if (mReadingState.mNodeCount < 0 - || mReadingState.mTotalNodeCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP - || mReadingState.mNodeArrayCount > MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP) { - // Invalid dictionary. - AKLOGI("Invalid dictionary. nodeCount: %d, totalNodeCount: %d, MAX_CHILD_COUNT: %d" - "nodeArrayCount: %d, MAX_NODE_ARRAY_COUNT: %d", - mReadingState.mNodeCount, mReadingState.mTotalNodeCount, - MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP, mReadingState.mNodeArrayCount, - MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP); - ASSERT(false); - mIsError = true; - mReadingState.mPos = NOT_A_DICT_POS; - return; - } - if (mReadingState.mNodeCount == 0) { - // Empty node array. Try following forward link. - followForwardLink(); - } -} - -// Follow the forward link and read the next node array if exists. -void DynamicPatriciaTrieReadingHelper::followForwardLink() { - if (mReadingState.mPos < 0 || mReadingState.mPos >= mBuffer->getTailPosition()) { - // Reading invalid position because of bug or broken dictionary. - AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d", - mReadingState.mPos, mBuffer->getTailPosition()); - ASSERT(false); - mIsError = true; - mReadingState.mPos = NOT_A_DICT_POS; - return; - } - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(mReadingState.mPos); - const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - mReadingState.mPos -= mBuffer->getOriginalBufferSize(); - } - const int forwardLinkPosition = - DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(dictBuf, mReadingState.mPos); - if (usesAdditionalBuffer) { - mReadingState.mPos += mBuffer->getOriginalBufferSize(); - } - mReadingState.mPosOfLastForwardLinkField = mReadingState.mPos; - if (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(forwardLinkPosition)) { - // Follow the forward link. - mReadingState.mPos += forwardLinkPosition; - nextPtNodeArray(); - } else { - // All node arrays have been read. - mReadingState.mPos = NOT_A_DICT_POS; - } -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h deleted file mode 100644 index a71c06971..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2013, 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_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H - -#include <cstddef> -#include <vector> - -#include "defines.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" - -namespace latinime { - -class BufferWithExtendableBuffer; -class DictionaryBigramsStructurePolicy; -class DictionaryShortcutsStructurePolicy; - -/* - * This class is used for traversing dynamic patricia trie. This class supports iterating nodes and - * dealing with additional buffer. This class counts nodes and node arrays to avoid infinite loop. - */ -class DynamicPatriciaTrieReadingHelper { - public: - class TraversingEventListener { - public: - virtual ~TraversingEventListener() {}; - - // Returns whether the event handling was succeeded or not. - virtual bool onAscend() = 0; - - // Returns whether the event handling was succeeded or not. - virtual bool onDescend(const int ptNodeArrayPos) = 0; - - // Returns whether the event handling was succeeded or not. - virtual bool onReadingPtNodeArrayTail() = 0; - - // Returns whether the event handling was succeeded or not. - virtual bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints) = 0; - - protected: - TraversingEventListener() {}; - - private: - DISALLOW_COPY_AND_ASSIGN(TraversingEventListener); - }; - - DynamicPatriciaTrieReadingHelper(const BufferWithExtendableBuffer *const buffer, - const DictionaryBigramsStructurePolicy *const bigramsPolicy, - const DictionaryShortcutsStructurePolicy *const shortcutsPolicy) - : mIsError(false), mReadingState(), mBuffer(buffer), - mNodeReader(mBuffer, bigramsPolicy, shortcutsPolicy), mReadingStateStack() {} - - ~DynamicPatriciaTrieReadingHelper() {} - - AK_FORCE_INLINE bool isError() const { - return mIsError; - } - - AK_FORCE_INLINE bool isEnd() const { - return mReadingState.mPos == NOT_A_DICT_POS; - } - - // Initialize reading state with the head position of a PtNode array. - AK_FORCE_INLINE void initWithPtNodeArrayPos(const int ptNodeArrayPos) { - if (ptNodeArrayPos == NOT_A_DICT_POS) { - mReadingState.mPos = NOT_A_DICT_POS; - } else { - mIsError = false; - mReadingState.mPos = ptNodeArrayPos; - mReadingState.mPrevTotalCodePointCount = 0; - mReadingState.mTotalNodeCount = 0; - mReadingState.mNodeArrayCount = 0; - mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; - mReadingStateStack.clear(); - nextPtNodeArray(); - if (!isEnd()) { - fetchPtNodeInfo(); - } - } - } - - // Initialize reading state with the head position of a node. - AK_FORCE_INLINE void initWithPtNodePos(const int ptNodePos) { - if (ptNodePos == NOT_A_DICT_POS) { - mReadingState.mPos = NOT_A_DICT_POS; - } else { - mIsError = false; - mReadingState.mPos = ptNodePos; - mReadingState.mNodeCount = 1; - mReadingState.mPrevTotalCodePointCount = 0; - mReadingState.mTotalNodeCount = 1; - mReadingState.mNodeArrayCount = 1; - mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; - mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS; - mReadingStateStack.clear(); - fetchPtNodeInfo(); - } - } - - AK_FORCE_INLINE const DynamicPatriciaTrieNodeReader* getNodeReader() const { - return &mNodeReader; - } - - AK_FORCE_INLINE bool isValidTerminalNode() const { - return !isEnd() && !mNodeReader.isDeleted() && mNodeReader.isTerminal(); - } - - AK_FORCE_INLINE bool isMatchedCodePoint(const int index, const int codePoint) const { - return mMergedNodeCodePoints[index] == codePoint; - } - - // Return code point count exclude the last read node's code points. - AK_FORCE_INLINE int getPrevTotalCodePointCount() const { - return mReadingState.mPrevTotalCodePointCount; - } - - // Return code point count include the last read node's code points. - AK_FORCE_INLINE int getTotalCodePointCount() const { - return mReadingState.mPrevTotalCodePointCount + mNodeReader.getCodePointCount(); - } - - AK_FORCE_INLINE void fetchMergedNodeCodePointsInReverseOrder( - const int index, int *const outCodePoints) const { - const int nodeCodePointCount = mNodeReader.getCodePointCount(); - for (int i = 0; i < nodeCodePointCount; ++i) { - outCodePoints[index + i] = mMergedNodeCodePoints[nodeCodePointCount - 1 - i]; - } - } - - AK_FORCE_INLINE const int *getMergedNodeCodePoints() const { - return mMergedNodeCodePoints; - } - - AK_FORCE_INLINE void readNextSiblingNode() { - mReadingState.mNodeCount -= 1; - mReadingState.mPos = mNodeReader.getSiblingNodePos(); - if (mReadingState.mNodeCount <= 0) { - // All nodes in the current node array have been read. - followForwardLink(); - if (!isEnd()) { - fetchPtNodeInfo(); - } - } else { - fetchPtNodeInfo(); - } - } - - // Read the first child node of the current node. - AK_FORCE_INLINE void readChildNode() { - if (mNodeReader.hasChildren()) { - mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount(); - mReadingState.mTotalNodeCount = 0; - mReadingState.mNodeArrayCount = 0; - mReadingState.mPos = mNodeReader.getChildrenPos(); - mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; - // Read children node array. - nextPtNodeArray(); - if (!isEnd()) { - fetchPtNodeInfo(); - } - } else { - mReadingState.mPos = NOT_A_DICT_POS; - } - } - - // Read the parent node of the current node. - AK_FORCE_INLINE void readParentNode() { - if (mNodeReader.getParentPos() != NOT_A_DICT_POS) { - mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount(); - mReadingState.mTotalNodeCount = 1; - mReadingState.mNodeArrayCount = 1; - mReadingState.mNodeCount = 1; - mReadingState.mPos = mNodeReader.getParentPos(); - mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; - mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS; - fetchPtNodeInfo(); - } else { - mReadingState.mPos = NOT_A_DICT_POS; - } - } - - AK_FORCE_INLINE int getPosOfLastForwardLinkField() const { - return mReadingState.mPosOfLastForwardLinkField; - } - - AK_FORCE_INLINE int getPosOfLastPtNodeArrayHead() const { - return mReadingState.mPosOfLastPtNodeArrayHead; - } - - AK_FORCE_INLINE void reloadCurrentPtNodeInfo() { - if (!isEnd()) { - fetchPtNodeInfo(); - } - } - - bool traverseAllPtNodesInPostorderDepthFirstManner(TraversingEventListener *const listener); - - bool traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( - TraversingEventListener *const listener); - - private: - DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieReadingHelper); - - class ReadingState { - public: - // Note that copy constructor and assignment operator are used for this class to use - // std::vector. - ReadingState() : mPos(NOT_A_DICT_POS), mNodeCount(0), mPrevTotalCodePointCount(0), - mTotalNodeCount(0), mNodeArrayCount(0), mPosOfLastForwardLinkField(NOT_A_DICT_POS), - mPosOfLastPtNodeArrayHead(NOT_A_DICT_POS) {} - - int mPos; - // Node count of a node array. - int mNodeCount; - int mPrevTotalCodePointCount; - int mTotalNodeCount; - int mNodeArrayCount; - int mPosOfLastForwardLinkField; - int mPosOfLastPtNodeArrayHead; - }; - - static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP; - static const int MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP; - static const size_t MAX_READING_STATE_STACK_SIZE; - - // TODO: Introduce error code to track what caused the error. - bool mIsError; - ReadingState mReadingState; - const BufferWithExtendableBuffer *const mBuffer; - DynamicPatriciaTrieNodeReader mNodeReader; - int mMergedNodeCodePoints[MAX_WORD_LENGTH]; - std::vector<ReadingState> mReadingStateStack; - - void nextPtNodeArray(); - - void followForwardLink(); - - AK_FORCE_INLINE void fetchPtNodeInfo() { - mNodeReader.fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(mReadingState.mPos, - MAX_WORD_LENGTH, mMergedNodeCodePoints); - if (mNodeReader.getCodePointCount() <= 0) { - // Empty node is not allowed. - mIsError = true; - mReadingState.mPos = NOT_A_DICT_POS; - } - } - - AK_FORCE_INLINE void pushReadingStateToStack() { - if (mReadingStateStack.size() > MAX_READING_STATE_STACK_SIZE) { - AKLOGI("Reading state stack overflow. Max size: %zd", MAX_READING_STATE_STACK_SIZE); - ASSERT(false); - mIsError = true; - mReadingState.mPos = NOT_A_DICT_POS; - } else { - mReadingStateStack.push_back(mReadingState); - } - } - - AK_FORCE_INLINE void popReadingStateFromStack() { - if (mReadingStateStack.empty()) { - mReadingState.mPos = NOT_A_DICT_POS; - } else { - mReadingState = mReadingStateStack.back(); - mReadingStateStack.pop_back(); - if (!isEnd()) { - fetchPtNodeInfo(); - } - } - } -}; -} // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp deleted file mode 100644 index 052558bfc..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2013, 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. - */ - -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h" - -#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h" -#include "suggest/policyimpl/dictionary/header/header_policy.h" -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" -#include "suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h" -#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" -#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" -#include "utils/hash_map_compat.h" - -namespace latinime { - -const int DynamicPatriciaTrieWritingHelper::CHILDREN_POSITION_FIELD_SIZE = 3; -// TODO: Make MAX_DICTIONARY_SIZE 8MB. -const size_t DynamicPatriciaTrieWritingHelper::MAX_DICTIONARY_SIZE = 2 * 1024 * 1024; - -bool DynamicPatriciaTrieWritingHelper::addUnigramWord( - DynamicPatriciaTrieReadingHelper *const readingHelper, - const int *const wordCodePoints, const int codePointCount, const int probability, - bool *const outAddedNewUnigram) { - int parentPos = NOT_A_DICT_POS; - while (!readingHelper->isEnd()) { - const int matchedCodePointCount = readingHelper->getPrevTotalCodePointCount(); - if (!readingHelper->isMatchedCodePoint(0 /* index */, - wordCodePoints[matchedCodePointCount])) { - // The first code point is different from target code point. Skip this node and read - // the next sibling node. - readingHelper->readNextSiblingNode(); - continue; - } - // Check following merged node code points. - const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper->getNodeReader(); - const int nodeCodePointCount = nodeReader->getCodePointCount(); - for (int j = 1; j < nodeCodePointCount; ++j) { - const int nextIndex = matchedCodePointCount + j; - if (nextIndex >= codePointCount || !readingHelper->isMatchedCodePoint(j, - wordCodePoints[matchedCodePointCount + j])) { - *outAddedNewUnigram = true; - return reallocatePtNodeAndAddNewPtNodes(nodeReader, - readingHelper->getMergedNodeCodePoints(), j, - getUpdatedProbability(NOT_A_PROBABILITY /* originalProbability */, - probability), - wordCodePoints + matchedCodePointCount, - codePointCount - matchedCodePointCount); - } - } - // All characters are matched. - if (codePointCount == readingHelper->getTotalCodePointCount()) { - return setPtNodeProbability(nodeReader, probability, - readingHelper->getMergedNodeCodePoints(), outAddedNewUnigram); - } - if (!nodeReader->hasChildren()) { - *outAddedNewUnigram = true; - return createChildrenPtNodeArrayAndAChildPtNode(nodeReader, - getUpdatedProbability(NOT_A_PROBABILITY /* originalProbability */, probability), - wordCodePoints + readingHelper->getTotalCodePointCount(), - codePointCount - readingHelper->getTotalCodePointCount()); - } - // Advance to the children nodes. - parentPos = nodeReader->getHeadPos(); - readingHelper->readChildNode(); - } - if (readingHelper->isError()) { - // The dictionary is invalid. - return false; - } - int pos = readingHelper->getPosOfLastForwardLinkField(); - *outAddedNewUnigram = true; - return createAndInsertNodeIntoPtNodeArray(parentPos, - wordCodePoints + readingHelper->getPrevTotalCodePointCount(), - codePointCount - readingHelper->getPrevTotalCodePointCount(), - getUpdatedProbability(NOT_A_PROBABILITY /* originalProbability */, probability), &pos); -} - -bool DynamicPatriciaTrieWritingHelper::addBigramWords(const int word0Pos, const int word1Pos, - const int probability, bool *const outAddedNewBigram) { - int mMergedNodeCodePoints[MAX_WORD_LENGTH]; - DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy); - nodeReader.fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(word0Pos, MAX_WORD_LENGTH, - mMergedNodeCodePoints); - // Move node to add bigram entry. - const int newNodePos = mBuffer->getTailPosition(); - if (!markNodeAsMovedAndSetPosition(&nodeReader, newNodePos, newNodePos)) { - return false; - } - int writingPos = newNodePos; - // Write a new PtNode using original PtNode's info to the tail of the dictionary in mBuffer. - if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, &nodeReader, nodeReader.getParentPos(), - mMergedNodeCodePoints, nodeReader.getCodePointCount(), nodeReader.getProbability(), - &writingPos)) { - return false; - } - nodeReader.fetchNodeInfoInBufferFromPtNodePos(newNodePos); - if (nodeReader.getBigramsPos() != NOT_A_DICT_POS) { - // Insert a new bigram entry into the existing bigram list. - int bigramListPos = nodeReader.getBigramsPos(); - return mBigramPolicy->addNewBigramEntryToBigramList(word1Pos, probability, &bigramListPos, - outAddedNewBigram); - } else { - // The PtNode doesn't have a bigram list. - *outAddedNewBigram = true; - // First, Write a bigram entry at the tail position of the PtNode. - if (!mBigramPolicy->writeNewBigramEntry(word1Pos, probability, &writingPos)) { - return false; - } - // Then, Mark as the PtNode having bigram list in the flags. - const PatriciaTrieReadingUtils::NodeFlags updatedFlags = - PatriciaTrieReadingUtils::createAndGetFlags(nodeReader.isBlacklisted(), - nodeReader.isNotAWord(), nodeReader.getProbability() != NOT_A_PROBABILITY, - nodeReader.getShortcutPos() != NOT_A_DICT_POS, true /* hasBigrams */, - nodeReader.getCodePointCount() > 1, CHILDREN_POSITION_FIELD_SIZE); - writingPos = newNodePos; - // Write updated flags into the moved PtNode's flags field. - return DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags, - &writingPos); - } -} - -// Remove a bigram relation from word0Pos to word1Pos. -bool DynamicPatriciaTrieWritingHelper::removeBigramWords(const int word0Pos, const int word1Pos) { - DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(word0Pos); - if (nodeReader.getBigramsPos() == NOT_A_DICT_POS) { - return false; - } - return mBigramPolicy->removeBigram(nodeReader.getBigramsPos(), word1Pos); -} - -void DynamicPatriciaTrieWritingHelper::writeToDictFile(const char *const fileName, - const HeaderPolicy *const headerPolicy, const int unigramCount, const int bigramCount) { - BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); - const int extendedRegionSize = headerPolicy->getExtendedRegionSize() + - mBuffer->getUsedAdditionalBufferSize(); - if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, false /* updatesLastUpdatedTime */, - false /* updatesLastDecayedTime */, unigramCount, bigramCount, extendedRegionSize)) { - return; - } - DictFileWritingUtils::flushAllHeaderAndBodyToFile(fileName, &headerBuffer, mBuffer); -} - -void DynamicPatriciaTrieWritingHelper::writeToDictFileWithGC(const int rootPtNodeArrayPos, - const char *const fileName, const HeaderPolicy *const headerPolicy) { - BufferWithExtendableBuffer newDictBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */, - MAX_DICTIONARY_SIZE); - int unigramCount = 0; - int bigramCount = 0; - if (mNeedsToDecay) { - ForgettingCurveUtils::sTimeKeeper.setCurrentTime(); - } - if (!runGC(rootPtNodeArrayPos, headerPolicy, &newDictBuffer, &unigramCount, &bigramCount)) { - return; - } - BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); - if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */, - mNeedsToDecay, unigramCount, bigramCount, 0 /* extendedRegionSize */)) { - return; - } - DictFileWritingUtils::flushAllHeaderAndBodyToFile(fileName, &headerBuffer, &newDictBuffer); -} - -bool DynamicPatriciaTrieWritingHelper::markNodeAsDeleted( - const DynamicPatriciaTrieNodeReader *const nodeToUpdate) { - int pos = nodeToUpdate->getHeadPos(); - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(pos); - const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - pos -= mBuffer->getOriginalBufferSize(); - } - // Read original flags - const PatriciaTrieReadingUtils::NodeFlags originalFlags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); - const PatriciaTrieReadingUtils::NodeFlags updatedFlags = - DynamicPatriciaTrieReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */, - true /* isDeleted */); - int writingPos = nodeToUpdate->getHeadPos(); - // Update flags. - return DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags, - &writingPos); -} - -bool DynamicPatriciaTrieWritingHelper::markNodeAsMovedAndSetPosition( - const DynamicPatriciaTrieNodeReader *const originalNode, const int movedPos, - const int bigramLinkedNodePos) { - int pos = originalNode->getHeadPos(); - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(pos); - const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - pos -= mBuffer->getOriginalBufferSize(); - } - // Read original flags - const PatriciaTrieReadingUtils::NodeFlags originalFlags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); - const PatriciaTrieReadingUtils::NodeFlags updatedFlags = - DynamicPatriciaTrieReadingUtils::updateAndGetFlags(originalFlags, true /* isMoved */, - false /* isDeleted */); - int writingPos = originalNode->getHeadPos(); - // Update flags. - if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags, - &writingPos)) { - return false; - } - // Update moved position, which is stored in the parent offset field. - if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition( - mBuffer, movedPos, originalNode->getHeadPos(), &writingPos)) { - return false; - } - // Update bigram linked node position, which is stored in the children position field. - int childrenPosFieldPos = originalNode->getChildrenPosFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition( - mBuffer, bigramLinkedNodePos, &childrenPosFieldPos)) { - return false; - } - if (originalNode->hasChildren()) { - // Update children's parent position. - DynamicPatriciaTrieReadingHelper readingHelper(mBuffer, mBigramPolicy, mShortcutPolicy); - const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader(); - readingHelper.initWithPtNodeArrayPos(originalNode->getChildrenPos()); - while (!readingHelper.isEnd()) { - int parentOffsetFieldPos = nodeReader->getHeadPos() - + DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE; - if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition( - mBuffer, bigramLinkedNodePos, nodeReader->getHeadPos(), - &parentOffsetFieldPos)) { - // Parent offset cannot be written because of a bug or a broken dictionary; thus, - // we give up to update dictionary. - return false; - } - readingHelper.readNextSiblingNode(); - } - } - return true; -} - -// Write new PtNode at writingPos. -bool DynamicPatriciaTrieWritingHelper::writePtNodeWithFullInfoToBuffer( - BufferWithExtendableBuffer *const bufferToWrite, const bool isBlacklisted, - const bool isNotAWord, const int parentPos, const int *const codePoints, - const int codePointCount, const int probability, const int childrenPos, - const int originalBigramListPos, const int originalShortcutListPos, - int *const writingPos) { - const int nodePos = *writingPos; - // Write dummy flags. The Node flags are updated with appropriate flags at the last step of the - // PtNode writing. - if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(bufferToWrite, - 0 /* nodeFlags */, writingPos)) { - return false; - } - // Calculate a parent offset and write the offset. - if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(bufferToWrite, - parentPos, nodePos, writingPos)) { - return false; - } - // Write code points - if (!DynamicPatriciaTrieWritingUtils::writeCodePointsAndAdvancePosition(bufferToWrite, - codePoints, codePointCount, writingPos)) { - return false; - } - // Write probability when the probability is a valid probability, which means this node is - // terminal. - if (probability != NOT_A_PROBABILITY) { - if (!DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition(bufferToWrite, - probability, writingPos)) { - return false; - } - } - // Write children position - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(bufferToWrite, - childrenPos, writingPos)) { - return false; - } - // Copy shortcut list when the originalShortcutListPos is valid dictionary position. - if (originalShortcutListPos != NOT_A_DICT_POS) { - int fromPos = originalShortcutListPos; - if (!mShortcutPolicy->copyAllShortcutsAndReturnIfSucceededOrNot(bufferToWrite, &fromPos, - writingPos)) { - return false; - } - } - // Copy bigram list when the originalBigramListPos is valid dictionary position. - int bigramCount = 0; - if (originalBigramListPos != NOT_A_DICT_POS) { - int fromPos = originalBigramListPos; - if (!mBigramPolicy->copyAllBigrams(bufferToWrite, &fromPos, writingPos, &bigramCount)) { - return false; - } - } - // Create node flags and write them. - PatriciaTrieReadingUtils::NodeFlags nodeFlags = - PatriciaTrieReadingUtils::createAndGetFlags(isBlacklisted, isNotAWord, - probability != NOT_A_PROBABILITY /* isTerminal */, - originalShortcutListPos != NOT_A_DICT_POS /* hasShortcutTargets */, - bigramCount > 0 /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */, - CHILDREN_POSITION_FIELD_SIZE); - int flagsFieldPos = nodePos; - if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(bufferToWrite, nodeFlags, - &flagsFieldPos)) { - return false; - } - return true; -} - -bool DynamicPatriciaTrieWritingHelper::writePtNodeToBuffer( - BufferWithExtendableBuffer *const bufferToWrite, const int parentPos, - const int *const codePoints, const int codePointCount, const int probability, - int *const writingPos) { - return writePtNodeWithFullInfoToBuffer(bufferToWrite, false /* isBlacklisted */, - false /* isNotAWord */, parentPos, codePoints, codePointCount, probability, - NOT_A_DICT_POS /* childrenPos */, NOT_A_DICT_POS /* originalBigramsPos */, - NOT_A_DICT_POS /* originalShortcutPos */, writingPos); -} - -bool DynamicPatriciaTrieWritingHelper::writePtNodeToBufferByCopyingPtNodeInfo( - BufferWithExtendableBuffer *const bufferToWrite, - const DynamicPatriciaTrieNodeReader *const originalNode, const int parentPos, - const int *const codePoints, const int codePointCount, const int probability, - int *const writingPos) { - return writePtNodeWithFullInfoToBuffer(bufferToWrite, originalNode->isBlacklisted(), - originalNode->isNotAWord(), parentPos, codePoints, codePointCount, probability, - originalNode->getChildrenPos(), originalNode->getBigramsPos(), - originalNode->getShortcutPos(), writingPos); -} - -bool DynamicPatriciaTrieWritingHelper::createAndInsertNodeIntoPtNodeArray(const int parentPos, - const int *const nodeCodePoints, const int nodeCodePointCount, const int probability, - int *const forwardLinkFieldPos) { - const int newPtNodeArrayPos = mBuffer->getTailPosition(); - if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, - newPtNodeArrayPos, forwardLinkFieldPos)) { - return false; - } - return createNewPtNodeArrayWithAChildPtNode(parentPos, nodeCodePoints, nodeCodePointCount, - probability); -} - -bool DynamicPatriciaTrieWritingHelper::setPtNodeProbability( - const DynamicPatriciaTrieNodeReader *const originalPtNode, const int probability, - const int *const codePoints, bool *const outAddedNewUnigram) { - if (originalPtNode->isTerminal()) { - // Overwrites the probability. - *outAddedNewUnigram = false; - const int probabilityToWrite = getUpdatedProbability(originalPtNode->getProbability(), - probability); - int probabilityFieldPos = originalPtNode->getProbabilityFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition(mBuffer, - probabilityToWrite, &probabilityFieldPos)) { - return false; - } - } else { - // Make the node terminal and write the probability. - *outAddedNewUnigram = true; - int movedPos = mBuffer->getTailPosition(); - if (!markNodeAsMovedAndSetPosition(originalPtNode, movedPos, movedPos)) { - return false; - } - if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, originalPtNode, - originalPtNode->getParentPos(), codePoints, originalPtNode->getCodePointCount(), - getUpdatedProbability(NOT_A_PROBABILITY /* originalProbability */, probability), - &movedPos)) { - return false; - } - } - return true; -} - -bool DynamicPatriciaTrieWritingHelper::createChildrenPtNodeArrayAndAChildPtNode( - const DynamicPatriciaTrieNodeReader *const parentNode, const int probability, - const int *const codePoints, const int codePointCount) { - const int newPtNodeArrayPos = mBuffer->getTailPosition(); - int childrenPosFieldPos = parentNode->getChildrenPosFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBuffer, - newPtNodeArrayPos, &childrenPosFieldPos)) { - return false; - } - return createNewPtNodeArrayWithAChildPtNode(parentNode->getHeadPos(), codePoints, - codePointCount, probability); -} - -bool DynamicPatriciaTrieWritingHelper::createNewPtNodeArrayWithAChildPtNode( - const int parentPtNodePos, const int *const nodeCodePoints, const int nodeCodePointCount, - const int probability) { - int writingPos = mBuffer->getTailPosition(); - if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer, - 1 /* arraySize */, &writingPos)) { - return false; - } - if (!writePtNodeToBuffer(mBuffer, parentPtNodePos, nodeCodePoints, nodeCodePointCount, - probability, &writingPos)) { - return false; - } - if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, - NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { - return false; - } - return true; -} - -// Returns whether the dictionary updating was succeeded or not. -bool DynamicPatriciaTrieWritingHelper::reallocatePtNodeAndAddNewPtNodes( - const DynamicPatriciaTrieNodeReader *const reallocatingPtNode, - const int *const reallocatingPtNodeCodePoints, const int overlappingCodePointCount, - const int probabilityOfNewPtNode, const int *const newNodeCodePoints, - const int newNodeCodePointCount) { - // When addsExtraChild is true, split the reallocating PtNode and add new child. - // Reallocating PtNode: abcde, newNode: abcxy. - // abc (1st, not terminal) __ de (2nd) - // \_ xy (extra child, terminal) - // Otherwise, this method makes 1st part terminal and write probabilityOfNewPtNode. - // Reallocating PtNode: abcde, newNode: abc. - // abc (1st, terminal) __ de (2nd) - const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount; - const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition(); - int writingPos = firstPartOfReallocatedPtNodePos; - // Write the 1st part of the reallocating node. The children position will be updated later - // with actual children position. - const int newProbability = addsExtraChild ? NOT_A_PROBABILITY : probabilityOfNewPtNode; - if (!writePtNodeToBuffer(mBuffer, reallocatingPtNode->getParentPos(), - reallocatingPtNodeCodePoints, overlappingCodePointCount, newProbability, - &writingPos)) { - return false; - } - const int actualChildrenPos = writingPos; - // Create new children PtNode array. - const size_t newPtNodeCount = addsExtraChild ? 2 : 1; - if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer, - newPtNodeCount, &writingPos)) { - return false; - } - // Write the 2nd part of the reallocating node. - const int secondPartOfReallocatedPtNodePos = writingPos; - if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, reallocatingPtNode, - firstPartOfReallocatedPtNodePos, - reallocatingPtNodeCodePoints + overlappingCodePointCount, - reallocatingPtNode->getCodePointCount() - overlappingCodePointCount, - reallocatingPtNode->getProbability(), &writingPos)) { - return false; - } - if (addsExtraChild) { - if (!writePtNodeToBuffer(mBuffer, firstPartOfReallocatedPtNodePos, - newNodeCodePoints + overlappingCodePointCount, - newNodeCodePointCount - overlappingCodePointCount, probabilityOfNewPtNode, - &writingPos)) { - return false; - } - } - if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, - NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { - return false; - } - // Update original reallocatingPtNode as moved. - if (!markNodeAsMovedAndSetPosition(reallocatingPtNode, firstPartOfReallocatedPtNodePos, - secondPartOfReallocatedPtNodePos)) { - return false; - } - // Load node info. Information of the 1st part will be fetched. - DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy); - nodeReader.fetchNodeInfoInBufferFromPtNodePos(firstPartOfReallocatedPtNodePos); - // Update children position. - int childrenPosFieldPos = nodeReader.getChildrenPosFieldPos(); - if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBuffer, - actualChildrenPos, &childrenPosFieldPos)) { - return false; - } - return true; -} - -bool DynamicPatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos, - const HeaderPolicy *const headerPolicy, BufferWithExtendableBuffer *const bufferToWrite, - int *const outUnigramCount, int *const outBigramCount) { - DynamicPatriciaTrieReadingHelper readingHelper(mBuffer, mBigramPolicy, mShortcutPolicy); - readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); - DynamicPatriciaTrieGcEventListeners - ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted - traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted( - headerPolicy, this, mBuffer, mNeedsToDecay); - if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( - &traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted)) { - return false; - } - if (mNeedsToDecay && traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted - .getValidUnigramCount() > ForgettingCurveUtils::MAX_UNIGRAM_COUNT_AFTER_GC) { - // TODO: Remove more unigrams. - } - - readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); - DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateBigramProbability - traversePolicyToUpdateBigramProbability(mBigramPolicy); - if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( - &traversePolicyToUpdateBigramProbability)) { - return false; - } - if (mNeedsToDecay && traversePolicyToUpdateBigramProbability.getValidBigramEntryCount() - > ForgettingCurveUtils::MAX_BIGRAM_COUNT_AFTER_GC) { - // TODO: Remove more bigrams. - } - - // Mapping from positions in mBuffer to positions in bufferToWrite. - DictPositionRelocationMap dictPositionRelocationMap; - readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); - DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer - traversePolicyToPlaceAndWriteValidPtNodesToBuffer(this, bufferToWrite, - &dictPositionRelocationMap); - if (!readingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( - &traversePolicyToPlaceAndWriteValidPtNodesToBuffer)) { - return false; - } - - // Create policy instance for the GCed dictionary. - DynamicShortcutListPolicy newDictShortcutPolicy(bufferToWrite); - DynamicBigramListPolicy newDictBigramPolicy(headerPolicy, bufferToWrite, &newDictShortcutPolicy, - mNeedsToDecay); - // Create reading helper for the GCed dictionary. - DynamicPatriciaTrieReadingHelper newDictReadingHelper(bufferToWrite, &newDictBigramPolicy, - &newDictShortcutPolicy); - newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); - DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateAllPositionFields - traversePolicyToUpdateAllPositionFields(this, &newDictBigramPolicy, bufferToWrite, - &dictPositionRelocationMap); - if (!newDictReadingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( - &traversePolicyToUpdateAllPositionFields)) { - return false; - } - *outUnigramCount = traversePolicyToUpdateAllPositionFields.getUnigramCount(); - *outBigramCount = traversePolicyToUpdateAllPositionFields.getBigramCount(); - return true; -} - -int DynamicPatriciaTrieWritingHelper::getUpdatedProbability(const int originalProbability, - const int newProbability) { - if (mNeedsToDecay) { - return ForgettingCurveUtils::getUpdatedEncodedProbability(originalProbability, - newProbability); - } else { - return newProbability; - } -} - -} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h deleted file mode 100644 index ca8664729..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2013, 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_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H - -#include <stdint.h> - -#include "defines.h" -#include "utils/hash_map_compat.h" - -namespace latinime { - -class BufferWithExtendableBuffer; -class DynamicBigramListPolicy; -class DynamicPatriciaTrieNodeReader; -class DynamicPatriciaTrieReadingHelper; -class DynamicShortcutListPolicy; -class HeaderPolicy; - -class DynamicPatriciaTrieWritingHelper { - public: - typedef hash_map_compat<int, int> PtNodeArrayPositionRelocationMap; - typedef hash_map_compat<int, int> PtNodePositionRelocationMap; - struct DictPositionRelocationMap { - public: - DictPositionRelocationMap() - : mPtNodeArrayPositionRelocationMap(), mPtNodePositionRelocationMap() {} - - PtNodeArrayPositionRelocationMap mPtNodeArrayPositionRelocationMap; - PtNodePositionRelocationMap mPtNodePositionRelocationMap; - - private: - DISALLOW_COPY_AND_ASSIGN(DictPositionRelocationMap); - }; - - static const size_t MAX_DICTIONARY_SIZE; - - DynamicPatriciaTrieWritingHelper(BufferWithExtendableBuffer *const buffer, - DynamicBigramListPolicy *const bigramPolicy, - DynamicShortcutListPolicy *const shortcutPolicy, const bool needsToDecay) - : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortcutPolicy(shortcutPolicy), - mNeedsToDecay(needsToDecay) {} - - ~DynamicPatriciaTrieWritingHelper() {} - - // Add a word to the dictionary. If the word already exists, update the probability. - bool addUnigramWord(DynamicPatriciaTrieReadingHelper *const readingHelper, - const int *const wordCodePoints, const int codePointCount, const int probability, - bool *const outAddedNewUnigram); - - // Add a bigram relation from word0Pos to word1Pos. - bool addBigramWords(const int word0Pos, const int word1Pos, const int probability, - bool *const outAddedNewBigram); - - // Remove a bigram relation from word0Pos to word1Pos. - bool removeBigramWords(const int word0Pos, const int word1Pos); - - void writeToDictFile(const char *const fileName, const HeaderPolicy *const headerPolicy, - const int unigramCount, const int bigramCount); - - void writeToDictFileWithGC(const int rootPtNodeArrayPos, const char *const fileName, - const HeaderPolicy *const headerPolicy); - - // CAVEAT: This method must be called only from inner classes of - // DynamicPatriciaTrieGcEventListeners. - bool markNodeAsDeleted(const DynamicPatriciaTrieNodeReader *const nodeToUpdate); - - // CAVEAT: This method must be called only from this class or inner classes of - // DynamicPatriciaTrieGcEventListeners. - bool writePtNodeToBufferByCopyingPtNodeInfo(BufferWithExtendableBuffer *const bufferToWrite, - const DynamicPatriciaTrieNodeReader *const originalNode, const int parentPos, - const int *const codePoints, const int codePointCount, const int probability, - int *const writingPos); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieWritingHelper); - - static const int CHILDREN_POSITION_FIELD_SIZE; - - BufferWithExtendableBuffer *const mBuffer; - DynamicBigramListPolicy *const mBigramPolicy; - DynamicShortcutListPolicy *const mShortcutPolicy; - const bool mNeedsToDecay; - - bool markNodeAsMovedAndSetPosition(const DynamicPatriciaTrieNodeReader *const nodeToUpdate, - const int movedPos, const int bigramLinkedNodePos); - - bool writePtNodeWithFullInfoToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const bool isBlacklisted, const bool isNotAWord, - const int parentPos, const int *const codePoints, const int codePointCount, - const int probability, const int childrenPos, const int originalBigramListPos, - const int originalShortcutListPos, int *const writingPos); - - bool writePtNodeToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const int parentPos, const int *const codePoints, const int codePointCount, - const int probability, int *const writingPos); - - bool createAndInsertNodeIntoPtNodeArray(const int parentPos, const int *const nodeCodePoints, - const int nodeCodePointCount, const int probability, int *const forwardLinkFieldPos); - - bool setPtNodeProbability(const DynamicPatriciaTrieNodeReader *const originalNode, - const int probability, const int *const codePoints, bool *const outAddedNewUnigram); - - bool createChildrenPtNodeArrayAndAChildPtNode( - const DynamicPatriciaTrieNodeReader *const parentNode, const int probability, - const int *const codePoints, const int codePointCount); - - bool createNewPtNodeArrayWithAChildPtNode(const int parentPos, const int *const nodeCodePoints, - const int nodeCodePointCount, const int probability); - - bool reallocatePtNodeAndAddNewPtNodes( - const DynamicPatriciaTrieNodeReader *const reallocatingPtNode, - const int *const reallocatingPtNodeCodePoints, const int overlappingCodePointCount, - const int probabilityOfNewPtNode, const int *const newNodeCodePoints, - const int newNodeCodePointCount); - - bool runGC(const int rootPtNodeArrayPos, const HeaderPolicy *const headerPolicy, - BufferWithExtendableBuffer *const bufferToWrite, int *const outUnigramCount, - int *const outBigramCount); - - int getUpdatedProbability(const int originalProbability, const int newProbability); -}; -} // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp index eb072fbaf..6ed65d921 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp @@ -16,19 +16,45 @@ #include "suggest/policyimpl/dictionary/header/header_policy.h" +#include <algorithm> + namespace latinime { -// Note that these are corresponding definitions in Java side in FormatSpec.FileHeader. +// Note that these are corresponding definitions in Java side in DictionaryHeader. const char *const HeaderPolicy::MULTIPLE_WORDS_DEMOTION_RATE_KEY = "MULTIPLE_WORDS_DEMOTION_RATE"; +const char *const HeaderPolicy::REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY = + "REQUIRES_GERMAN_UMLAUT_PROCESSING"; // TODO: Change attribute string to "IS_DECAYING_DICT". const char *const HeaderPolicy::IS_DECAYING_DICT_KEY = "USES_FORGETTING_CURVE"; -const char *const HeaderPolicy::LAST_UPDATED_TIME_KEY = "date"; +const char *const HeaderPolicy::DATE_KEY = "date"; const char *const HeaderPolicy::LAST_DECAYED_TIME_KEY = "LAST_DECAYED_TIME"; const char *const HeaderPolicy::UNIGRAM_COUNT_KEY = "UNIGRAM_COUNT"; const char *const HeaderPolicy::BIGRAM_COUNT_KEY = "BIGRAM_COUNT"; const char *const HeaderPolicy::EXTENDED_REGION_SIZE_KEY = "EXTENDED_REGION_SIZE"; +// Historical info is information that is needed to support decaying such as timestamp, level and +// count. +const char *const HeaderPolicy::HAS_HISTORICAL_INFO_KEY = "HAS_HISTORICAL_INFO"; +const char *const HeaderPolicy::LOCALE_KEY = "locale"; // match Java declaration +const char *const HeaderPolicy::FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY = + "FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP"; +const char *const HeaderPolicy::FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY = + "FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID"; +const char *const HeaderPolicy::FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY = + "FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS"; + +const char *const HeaderPolicy::MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_COUNT"; +const char *const HeaderPolicy::MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_COUNT"; + const int HeaderPolicy::DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE = 100; const float HeaderPolicy::MULTIPLE_WORD_COST_MULTIPLIER_SCALE = 100.0f; +const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP = 2; +const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID = 3; +// 30 days +const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS = + 30 * 24 * 60 * 60; + +const int HeaderPolicy::DEFAULT_MAX_UNIGRAM_COUNT = 10000; +const int HeaderPolicy::DEFAULT_MAX_BIGRAM_COUNT = 10000; // Used for logging. Question mark is used to indicate that the key is not found. void HeaderPolicy::readHeaderValueOrQuestionMark(const char *const key, int *outValue, @@ -40,20 +66,25 @@ void HeaderPolicy::readHeaderValueOrQuestionMark(const char *const key, int *out } std::vector<int> keyCodePointVector; HeaderReadWriteUtils::insertCharactersIntoVector(key, &keyCodePointVector); - HeaderReadWriteUtils::AttributeMap::const_iterator it = mAttributeMap.find(keyCodePointVector); + DictionaryHeaderStructurePolicy::AttributeMap::const_iterator it = + mAttributeMap.find(keyCodePointVector); if (it == mAttributeMap.end()) { // The key was not found. outValue[0] = '?'; outValue[1] = '\0'; return; } - const int terminalIndex = min(static_cast<int>(it->second.size()), outValueSize - 1); + const int terminalIndex = std::min(static_cast<int>(it->second.size()), outValueSize - 1); for (int i = 0; i < terminalIndex; ++i) { outValue[i] = it->second[i]; } outValue[terminalIndex] = '\0'; } +const std::vector<int> HeaderPolicy::readLocale() const { + return HeaderReadWriteUtils::readCodePointVectorAttributeValue(&mAttributeMap, LOCALE_KEY); +} + float HeaderPolicy::readMultipleWordCostMultiplier() const { const int demotionRate = HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, MULTIPLE_WORDS_DEMOTION_RATE_KEY, DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE); @@ -63,54 +94,65 @@ float HeaderPolicy::readMultipleWordCostMultiplier() const { return MULTIPLE_WORD_COST_MULTIPLIER_SCALE / static_cast<float>(demotionRate); } -bool HeaderPolicy::writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const bool updatesLastUpdatedTime, const bool updatesLastDecayedTime, - const int unigramCount, const int bigramCount, const int extendedRegionSize) const { +bool HeaderPolicy::readRequiresGermanUmlautProcessing() const { + return HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap, + REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY, false); +} + +bool HeaderPolicy::fillInAndWriteHeaderToBuffer(const bool updatesLastDecayedTime, + const int unigramCount, const int bigramCount, + const int extendedRegionSize, BufferWithExtendableBuffer *const outBuffer) const { int writingPos = 0; - if (!HeaderReadWriteUtils::writeDictionaryVersion(bufferToWrite, mDictFormatVersion, + DictionaryHeaderStructurePolicy::AttributeMap attributeMapToWrite(mAttributeMap); + fillInHeader(updatesLastDecayedTime, unigramCount, bigramCount, + extendedRegionSize, &attributeMapToWrite); + if (!HeaderReadWriteUtils::writeDictionaryVersion(outBuffer, mDictFormatVersion, &writingPos)) { return false; } - if (!HeaderReadWriteUtils::writeDictionaryFlags(bufferToWrite, mDictionaryFlags, + if (!HeaderReadWriteUtils::writeDictionaryFlags(outBuffer, mDictionaryFlags, &writingPos)) { return false; } // Temporarily writes a dummy header size. int headerSizeFieldPos = writingPos; - if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, 0 /* size */, + if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(outBuffer, 0 /* size */, &writingPos)) { return false; } - HeaderReadWriteUtils::AttributeMap attributeMapTowrite(mAttributeMap); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, UNIGRAM_COUNT_KEY, unigramCount); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, BIGRAM_COUNT_KEY, bigramCount); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, EXTENDED_REGION_SIZE_KEY, - extendedRegionSize); - if (updatesLastUpdatedTime) { - // Set current time as a last updated time. - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_UPDATED_TIME_KEY, - time(0)); - } - if (updatesLastDecayedTime) { - // Set current time as a last updated time. - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_DECAYED_TIME_KEY, - time(0)); - } - if (!HeaderReadWriteUtils::writeHeaderAttributes(bufferToWrite, &attributeMapTowrite, + if (!HeaderReadWriteUtils::writeHeaderAttributes(outBuffer, &attributeMapToWrite, &writingPos)) { return false; } - // Writes an actual header size. - if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, writingPos, + // Writes the actual header size. + if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(outBuffer, writingPos, &headerSizeFieldPos)) { return false; } return true; } -/* static */ HeaderReadWriteUtils::AttributeMap +void HeaderPolicy::fillInHeader(const bool updatesLastDecayedTime, const int unigramCount, + const int bigramCount, const int extendedRegionSize, + DictionaryHeaderStructurePolicy::AttributeMap *outAttributeMap) const { + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, UNIGRAM_COUNT_KEY, unigramCount); + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, BIGRAM_COUNT_KEY, bigramCount); + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, EXTENDED_REGION_SIZE_KEY, + extendedRegionSize); + // Set the current time as the generation time. + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, DATE_KEY, + TimeKeeper::peekCurrentTime()); + HeaderReadWriteUtils::setCodePointVectorAttribute(outAttributeMap, LOCALE_KEY, mLocale); + if (updatesLastDecayedTime) { + // Set current time as the last updated time. + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, LAST_DECAYED_TIME_KEY, + TimeKeeper::peekCurrentTime()); + } +} + +/* static */ DictionaryHeaderStructurePolicy::AttributeMap HeaderPolicy::createAttributeMapAndReadAllAttributes(const uint8_t *const dictBuf) { - HeaderReadWriteUtils::AttributeMap attributeMap; + DictionaryHeaderStructurePolicy::AttributeMap attributeMap; HeaderReadWriteUtils::fetchAllHeaderAttributes(dictBuf, &attributeMap); return attributeMap; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h index a9c7805a8..251a71941 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h @@ -17,69 +17,149 @@ #ifndef LATINIME_HEADER_POLICY_H #define LATINIME_HEADER_POLICY_H -#include <ctime> -#include <stdint.h> +#include <cstdint> #include "defines.h" #include "suggest/core/policy/dictionary_header_structure_policy.h" #include "suggest/policyimpl/dictionary/header/header_read_write_utils.h" #include "suggest/policyimpl/dictionary/utils/format_utils.h" +#include "utils/char_utils.h" +#include "utils/time_keeper.h" namespace latinime { class HeaderPolicy : public DictionaryHeaderStructurePolicy { public: // Reads information from existing dictionary buffer. - HeaderPolicy(const uint8_t *const dictBuf, const int dictSize) - : mDictFormatVersion(FormatUtils::detectFormatVersion(dictBuf, dictSize)), + HeaderPolicy(const uint8_t *const dictBuf, const FormatUtils::FORMAT_VERSION formatVersion) + : mDictFormatVersion(formatVersion), mDictionaryFlags(HeaderReadWriteUtils::getFlags(dictBuf)), mSize(HeaderReadWriteUtils::getHeaderSize(dictBuf)), mAttributeMap(createAttributeMapAndReadAllAttributes(dictBuf)), + mLocale(readLocale()), mMultiWordCostMultiplier(readMultipleWordCostMultiplier()), + mRequiresGermanUmlautProcessing(readRequiresGermanUmlautProcessing()), mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap, IS_DECAYING_DICT_KEY, false /* defaultValue */)), - mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, - LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)), + mDate(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, + DATE_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)), mLastDecayedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, - LAST_DECAYED_TIME_KEY, time(0) /* defaultValue */)), + LAST_DECAYED_TIME_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)), mUnigramCount(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, UNIGRAM_COUNT_KEY, 0 /* defaultValue */)), mBigramCount(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, BIGRAM_COUNT_KEY, 0 /* defaultValue */)), mExtendedRegionSize(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, - EXTENDED_REGION_SIZE_KEY, 0 /* defaultValue */)) {} + EXTENDED_REGION_SIZE_KEY, 0 /* defaultValue */)), + mHasHistoricalInfoOfWords(HeaderReadWriteUtils::readBoolAttributeValue( + &mAttributeMap, HAS_HISTORICAL_INFO_KEY, false /* defaultValue */)), + mForgettingCurveOccurrencesToLevelUp(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY, + DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP)), + mForgettingCurveProbabilityValuesTableId(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY, + DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID)), + mForgettingCurveDurationToLevelDown(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY, + DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS)), + mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)), + mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)) {} // Constructs header information using an attribute map. HeaderPolicy(const FormatUtils::FORMAT_VERSION dictFormatVersion, - const HeaderReadWriteUtils::AttributeMap *const attributeMap) + const std::vector<int> &locale, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) : mDictFormatVersion(dictFormatVersion), mDictionaryFlags(HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap( - attributeMap)), mSize(0), mAttributeMap(*attributeMap), + attributeMap)), mSize(0), mAttributeMap(*attributeMap), mLocale(locale), mMultiWordCostMultiplier(readMultipleWordCostMultiplier()), + mRequiresGermanUmlautProcessing(readRequiresGermanUmlautProcessing()), mIsDecayingDict(HeaderReadWriteUtils::readBoolAttributeValue(&mAttributeMap, IS_DECAYING_DICT_KEY, false /* defaultValue */)), - mLastUpdatedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, - LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)), + mDate(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, + DATE_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)), mLastDecayedTime(HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, - LAST_UPDATED_TIME_KEY, time(0) /* defaultValue */)), - mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0) {} + DATE_KEY, TimeKeeper::peekCurrentTime() /* defaultValue */)), + mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0), + mHasHistoricalInfoOfWords(HeaderReadWriteUtils::readBoolAttributeValue( + &mAttributeMap, HAS_HISTORICAL_INFO_KEY, false /* defaultValue */)), + mForgettingCurveOccurrencesToLevelUp(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY, + DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP)), + mForgettingCurveProbabilityValuesTableId(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY, + DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID)), + mForgettingCurveDurationToLevelDown(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY, + DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS)), + mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)), + mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue( + &mAttributeMap, MAX_BIGRAM_COUNT_KEY, DEFAULT_MAX_BIGRAM_COUNT)) {} - ~HeaderPolicy() {} + // Copy header information + HeaderPolicy(const HeaderPolicy *const headerPolicy) + : mDictFormatVersion(headerPolicy->mDictFormatVersion), + mDictionaryFlags(headerPolicy->mDictionaryFlags), mSize(headerPolicy->mSize), + mAttributeMap(headerPolicy->mAttributeMap), mLocale(headerPolicy->mLocale), + mMultiWordCostMultiplier(headerPolicy->mMultiWordCostMultiplier), + mRequiresGermanUmlautProcessing(headerPolicy->mRequiresGermanUmlautProcessing), + mIsDecayingDict(headerPolicy->mIsDecayingDict), + mDate(headerPolicy->mDate), mLastDecayedTime(headerPolicy->mLastDecayedTime), + mUnigramCount(headerPolicy->mUnigramCount), mBigramCount(headerPolicy->mBigramCount), + mExtendedRegionSize(headerPolicy->mExtendedRegionSize), + mHasHistoricalInfoOfWords(headerPolicy->mHasHistoricalInfoOfWords), + mForgettingCurveOccurrencesToLevelUp( + headerPolicy->mForgettingCurveOccurrencesToLevelUp), + mForgettingCurveProbabilityValuesTableId( + headerPolicy->mForgettingCurveProbabilityValuesTableId), + mForgettingCurveDurationToLevelDown( + headerPolicy->mForgettingCurveDurationToLevelDown), + mMaxUnigramCount(headerPolicy->mMaxUnigramCount), + mMaxBigramCount(headerPolicy->mMaxBigramCount) {} - AK_FORCE_INLINE int getSize() const { - return mSize; - } + // Temporary dummy header. + HeaderPolicy() + : mDictFormatVersion(FormatUtils::UNKNOWN_VERSION), mDictionaryFlags(0), mSize(0), + mAttributeMap(), mLocale(CharUtils::EMPTY_STRING), mMultiWordCostMultiplier(0.0f), + mRequiresGermanUmlautProcessing(false), mIsDecayingDict(false), + mDate(0), mLastDecayedTime(0), mUnigramCount(0), mBigramCount(0), + mExtendedRegionSize(0), mHasHistoricalInfoOfWords(false), + mForgettingCurveOccurrencesToLevelUp(0), mForgettingCurveProbabilityValuesTableId(0), + mForgettingCurveDurationToLevelDown(0), mMaxUnigramCount(0), mMaxBigramCount(0) {} - AK_FORCE_INLINE bool supportsDynamicUpdate() const { - return HeaderReadWriteUtils::supportsDynamicUpdate(mDictionaryFlags); + ~HeaderPolicy() {} + + virtual int getFormatVersionNumber() const { + // Conceptually this converts the symbolic value we use in the code into the + // hardcoded of the bytes in the file. But we want the constants to be the + // same so we use them for both here. + switch (mDictFormatVersion) { + case FormatUtils::VERSION_2: + return FormatUtils::VERSION_2; + case FormatUtils::VERSION_4: + return FormatUtils::VERSION_4; + default: + return FormatUtils::UNKNOWN_VERSION; + } } - AK_FORCE_INLINE bool requiresGermanUmlautProcessing() const { - return HeaderReadWriteUtils::requiresGermanUmlautProcessing(mDictionaryFlags); + AK_FORCE_INLINE bool isValid() const { + // Decaying dictionary must have historical information. + if (!mIsDecayingDict) { + return true; + } + if (mHasHistoricalInfoOfWords) { + return true; + } else { + return false; + } } - AK_FORCE_INLINE bool requiresFrenchLigatureProcessing() const { - return HeaderReadWriteUtils::requiresFrenchLigatureProcessing(mDictionaryFlags); + AK_FORCE_INLINE int getSize() const { + return mSize; } AK_FORCE_INLINE float getMultiWordCostMultiplier() const { @@ -90,8 +170,12 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { return mIsDecayingDict; } - AK_FORCE_INLINE int getLastUpdatedTime() const { - return mLastUpdatedTime; + AK_FORCE_INLINE bool requiresGermanUmlautProcessing() const { + return mRequiresGermanUmlautProcessing; + } + + AK_FORCE_INLINE int getDate() const { + return mDate; } AK_FORCE_INLINE int getLastDecayedTime() const { @@ -110,41 +194,101 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { return mExtendedRegionSize; } + AK_FORCE_INLINE bool hasHistoricalInfoOfWords() const { + return mHasHistoricalInfoOfWords; + } + + AK_FORCE_INLINE bool shouldBoostExactMatches() const { + // TODO: Investigate better ways to handle exact matches for personalized dictionaries. + return !isDecayingDict(); + } + + const DictionaryHeaderStructurePolicy::AttributeMap *getAttributeMap() const { + return &mAttributeMap; + } + + AK_FORCE_INLINE int getForgettingCurveOccurrencesToLevelUp() const { + return mForgettingCurveOccurrencesToLevelUp; + } + + AK_FORCE_INLINE int getForgettingCurveProbabilityValuesTableId() const { + return mForgettingCurveProbabilityValuesTableId; + } + + AK_FORCE_INLINE int getForgettingCurveDurationToLevelDown() const { + return mForgettingCurveDurationToLevelDown; + } + + AK_FORCE_INLINE int getMaxUnigramCount() const { + return mMaxUnigramCount; + } + + AK_FORCE_INLINE int getMaxBigramCount() const { + return mMaxBigramCount; + } + void readHeaderValueOrQuestionMark(const char *const key, int *outValue, int outValueSize) const; - bool writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const bool updatesLastUpdatedTime, const bool updatesLastDecayedTime, - const int unigramCount, const int bigramCount, const int extendedRegionSize) const; + bool fillInAndWriteHeaderToBuffer(const bool updatesLastDecayedTime, + const int unigramCount, const int bigramCount, + const int extendedRegionSize, BufferWithExtendableBuffer *const outBuffer) const; + + void fillInHeader(const bool updatesLastDecayedTime, + const int unigramCount, const int bigramCount, const int extendedRegionSize, + DictionaryHeaderStructurePolicy::AttributeMap *outAttributeMap) const; private: - DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPolicy); + DISALLOW_COPY_AND_ASSIGN(HeaderPolicy); static const char *const MULTIPLE_WORDS_DEMOTION_RATE_KEY; + static const char *const REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY; static const char *const IS_DECAYING_DICT_KEY; - static const char *const LAST_UPDATED_TIME_KEY; + static const char *const DATE_KEY; static const char *const LAST_DECAYED_TIME_KEY; static const char *const UNIGRAM_COUNT_KEY; static const char *const BIGRAM_COUNT_KEY; static const char *const EXTENDED_REGION_SIZE_KEY; + static const char *const HAS_HISTORICAL_INFO_KEY; + static const char *const LOCALE_KEY; + static const char *const FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY; + static const char *const FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY; + static const char *const FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY; + static const char *const MAX_UNIGRAM_COUNT_KEY; + static const char *const MAX_BIGRAM_COUNT_KEY; static const int DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE; static const float MULTIPLE_WORD_COST_MULTIPLIER_SCALE; + static const int DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP; + static const int DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID; + static const int DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS; + static const int DEFAULT_MAX_UNIGRAM_COUNT; + static const int DEFAULT_MAX_BIGRAM_COUNT; const FormatUtils::FORMAT_VERSION mDictFormatVersion; const HeaderReadWriteUtils::DictionaryFlags mDictionaryFlags; const int mSize; - HeaderReadWriteUtils::AttributeMap mAttributeMap; + DictionaryHeaderStructurePolicy::AttributeMap mAttributeMap; + const std::vector<int> mLocale; const float mMultiWordCostMultiplier; + const bool mRequiresGermanUmlautProcessing; const bool mIsDecayingDict; - const int mLastUpdatedTime; + const int mDate; const int mLastDecayedTime; const int mUnigramCount; const int mBigramCount; const int mExtendedRegionSize; + const bool mHasHistoricalInfoOfWords; + const int mForgettingCurveOccurrencesToLevelUp; + const int mForgettingCurveProbabilityValuesTableId; + const int mForgettingCurveDurationToLevelDown; + const int mMaxUnigramCount; + const int mMaxBigramCount; + const std::vector<int> readLocale() const; float readMultipleWordCostMultiplier() const; + bool readRequiresGermanUmlautProcessing() const; - static HeaderReadWriteUtils::AttributeMap createAttributeMapAndReadAllAttributes( + static DictionaryHeaderStructurePolicy::AttributeMap createAttributeMapAndReadAllAttributes( const uint8_t *const dictBuf); }; } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp index 5ded8f6a1..5608e27d4 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp @@ -26,6 +26,13 @@ namespace latinime { +// Number of base-10 digits in the largest integer + 1 to leave room for a zero terminator. +// As such, this is the maximum number of characters will be needed to represent an int as a +// string, including the terminator; this is used as the size of a string buffer large enough to +// hold any value that is intended to fit in an integer, e.g. in the code that reads the header +// of the binary dictionary where a {key,value} string pair scheme is used. +const int HeaderReadWriteUtils::LARGEST_INT_DIGIT_COUNT = 11; + const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256; const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256; @@ -35,22 +42,8 @@ const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2; const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4; const HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::NO_FLAGS = 0; -// Flags for special processing -// Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAG) or -// something very bad (like, the apocalypse) will happen. Please update both at the same time. -const HeaderReadWriteUtils::DictionaryFlags - HeaderReadWriteUtils::GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; -const HeaderReadWriteUtils::DictionaryFlags - HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_FLAG = 0x2; -const HeaderReadWriteUtils::DictionaryFlags - HeaderReadWriteUtils::FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; - -// Note that these are corresponding definitions in Java side in FormatSpec.FileHeader. -const char *const HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_KEY = "SUPPORTS_DYNAMIC_UPDATE"; -const char *const HeaderReadWriteUtils::REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY = - "REQUIRES_GERMAN_UMLAUT_PROCESSING"; -const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY = - "REQUIRES_FRENCH_LIGATURE_PROCESSING"; + +typedef DictionaryHeaderStructurePolicy::AttributeMap AttributeMap; /* static */ int HeaderReadWriteUtils::getHeaderSize(const uint8_t *const dictBuf) { // See the format of the header in the comment in @@ -67,18 +60,8 @@ const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY /* static */ HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap( - const HeaderReadWriteUtils::AttributeMap *const attributeMap) { - const bool requiresGermanUmlautProcessing = readBoolAttributeValue(attributeMap, - REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY, false /* defaultValue */); - const bool requiresFrenchLigatureProcessing = readBoolAttributeValue(attributeMap, - REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY, false /* defaultValue */); - const bool supportsDynamicUpdate = readBoolAttributeValue(attributeMap, - SUPPORTS_DYNAMIC_UPDATE_KEY, false /* defaultValue */); - DictionaryFlags dictflags = NO_FLAGS; - dictflags |= requiresGermanUmlautProcessing ? GERMAN_UMLAUT_PROCESSING_FLAG : 0; - dictflags |= requiresFrenchLigatureProcessing ? FRENCH_LIGATURE_PROCESSING_FLAG : 0; - dictflags |= supportsDynamicUpdate ? SUPPORTS_DYNAMIC_UPDATE_FLAG : 0; - return dictflags; + const AttributeMap *const attributeMap) { + return NO_FLAGS; } /* static */ void HeaderReadWriteUtils::fetchAllHeaderAttributes(const uint8_t *const dictBuf, @@ -115,8 +98,8 @@ const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY case FormatUtils::VERSION_2: // Version 2 dictionary writing is not supported. return false; - case FormatUtils::VERSION_3: - return buffer->writeUintAndAdvancePosition(3 /* data */, + case FormatUtils::VERSION_4: + return buffer->writeUintAndAdvancePosition(FormatUtils::VERSION_4 /* data */, HEADER_DICTIONARY_VERSION_SIZE, writingPos); default: return false; @@ -156,6 +139,13 @@ const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY return true; } +/* static */ void HeaderReadWriteUtils::setCodePointVectorAttribute( + AttributeMap *const headerAttributes, const char *const key, const std::vector<int> value) { + AttributeMap::key_type keyVector; + insertCharactersIntoVector(key, &keyVector); + (*headerAttributes)[keyVector] = value; +} + /* static */ void HeaderReadWriteUtils::setBoolAttribute(AttributeMap *const headerAttributes, const char *const key, const bool value) { setIntAttribute(headerAttributes, key, value ? 1 : 0); @@ -171,12 +161,24 @@ const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY /* static */ void HeaderReadWriteUtils::setIntAttributeInner(AttributeMap *const headerAttributes, const AttributeMap::key_type *const key, const int value) { AttributeMap::mapped_type valueVector; - char charBuf[LARGEST_INT_DIGIT_COUNT + 1]; - snprintf(charBuf, LARGEST_INT_DIGIT_COUNT + 1, "%d", value); + char charBuf[LARGEST_INT_DIGIT_COUNT]; + snprintf(charBuf, sizeof(charBuf), "%d", value); insertCharactersIntoVector(charBuf, &valueVector); (*headerAttributes)[*key] = valueVector; } +/* static */ const std::vector<int> HeaderReadWriteUtils::readCodePointVectorAttributeValue( + const AttributeMap *const headerAttributes, const char *const key) { + AttributeMap::key_type keyVector; + insertCharactersIntoVector(key, &keyVector); + AttributeMap::const_iterator it = headerAttributes->find(keyVector); + if (it == headerAttributes->end()) { + return std::vector<int>(); + } else { + return it->second; + } +} + /* static */ bool HeaderReadWriteUtils::readBoolAttributeValue( const AttributeMap *const headerAttributes, const char *const key, const bool defaultValue) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h index 225968323..9b90488fc 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h @@ -17,11 +17,10 @@ #ifndef LATINIME_HEADER_READ_WRITE_UTILS_H #define LATINIME_HEADER_READ_WRITE_UTILS_H -#include <map> -#include <stdint.h> -#include <vector> +#include <cstdint> #include "defines.h" +#include "suggest/core/policy/dictionary_header_structure_policy.h" #include "suggest/policyimpl/dictionary/utils/format_utils.h" namespace latinime { @@ -31,34 +30,21 @@ class BufferWithExtendableBuffer; class HeaderReadWriteUtils { public: typedef uint16_t DictionaryFlags; - typedef std::map<std::vector<int>, std::vector<int> > AttributeMap; static int getHeaderSize(const uint8_t *const dictBuf); static DictionaryFlags getFlags(const uint8_t *const dictBuf); - static AK_FORCE_INLINE bool supportsDynamicUpdate(const DictionaryFlags flags) { - return (flags & SUPPORTS_DYNAMIC_UPDATE_FLAG) != 0; - } - - static AK_FORCE_INLINE bool requiresGermanUmlautProcessing(const DictionaryFlags flags) { - return (flags & GERMAN_UMLAUT_PROCESSING_FLAG) != 0; - } - - static AK_FORCE_INLINE bool requiresFrenchLigatureProcessing(const DictionaryFlags flags) { - return (flags & FRENCH_LIGATURE_PROCESSING_FLAG) != 0; - } - static AK_FORCE_INLINE int getHeaderOptionsPosition() { return HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE + HEADER_SIZE_FIELD_SIZE; } static DictionaryFlags createAndGetDictionaryFlagsUsingAttributeMap( - const HeaderReadWriteUtils::AttributeMap *const attributeMap); + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap); static void fetchAllHeaderAttributes(const uint8_t *const dictBuf, - AttributeMap *const headerAttributes); + DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes); static bool writeDictionaryVersion(BufferWithExtendableBuffer *const buffer, const FormatUtils::FORMAT_VERSION version, int *const writingPos); @@ -70,29 +56,43 @@ class HeaderReadWriteUtils { const int size, int *const writingPos); static bool writeHeaderAttributes(BufferWithExtendableBuffer *const buffer, - const AttributeMap *const headerAttributes, int *const writingPos); + const DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, + int *const writingPos); /** * Methods for header attributes. */ - static void setBoolAttribute(AttributeMap *const headerAttributes, + static void setCodePointVectorAttribute( + DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, + const char *const key, const std::vector<int> value); + + static void setBoolAttribute( + DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, const char *const key, const bool value); - static void setIntAttribute(AttributeMap *const headerAttributes, + static void setIntAttribute( + DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, const char *const key, const int value); - static bool readBoolAttributeValue(const AttributeMap *const headerAttributes, + static const std::vector<int> readCodePointVectorAttributeValue( + const DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, + const char *const key); + + static bool readBoolAttributeValue( + const DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, const char *const key, const bool defaultValue); - static int readIntAttributeValue(const AttributeMap *const headerAttributes, + static int readIntAttributeValue( + const DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, const char *const key, const int defaultValue); static void insertCharactersIntoVector(const char *const characters, - AttributeMap::key_type *const key); + DictionaryHeaderStructurePolicy::AttributeMap::key_type *const key); private: DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderReadWriteUtils); + static const int LARGEST_INT_DIGIT_COUNT; static const int MAX_ATTRIBUTE_KEY_LENGTH; static const int MAX_ATTRIBUTE_VALUE_LENGTH; @@ -101,23 +101,18 @@ class HeaderReadWriteUtils { static const int HEADER_FLAG_SIZE; static const int HEADER_SIZE_FIELD_SIZE; + // Value for the "flags" field. It's unused at the moment. static const DictionaryFlags NO_FLAGS; - // Flags for special processing - // Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAGS) or - // something very bad (like, the apocalypse) will happen. Please update both at the same time. - static const DictionaryFlags GERMAN_UMLAUT_PROCESSING_FLAG; - static const DictionaryFlags SUPPORTS_DYNAMIC_UPDATE_FLAG; - static const DictionaryFlags FRENCH_LIGATURE_PROCESSING_FLAG; - - static const char *const SUPPORTS_DYNAMIC_UPDATE_KEY; - static const char *const REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY; - static const char *const REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY; - - static void setIntAttributeInner(AttributeMap *const headerAttributes, - const AttributeMap::key_type *const key, const int value); - - static int readIntAttributeValueInner(const AttributeMap *const headerAttributes, - const AttributeMap::key_type *const key, const int defaultValue); + + static void setIntAttributeInner( + DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, + const DictionaryHeaderStructurePolicy::AttributeMap::key_type *const key, + const int value); + + static int readIntAttributeValueInner( + const DictionaryHeaderStructurePolicy::AttributeMap *const headerAttributes, + const DictionaryHeaderStructurePolicy::AttributeMap::key_type *const key, + const int defaultValue); }; } #endif /* LATINIME_HEADER_READ_WRITE_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h deleted file mode 100644 index bd3211f6a..000000000 --- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2013 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_DYNAMIC_SHORTCUT_LIST_POLICY_H -#define LATINIME_DYNAMIC_SHORTCUT_LIST_POLICY_H - -#include <stdint.h> - -#include "defines.h" -#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" -#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h" -#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" - -namespace latinime { - -/* - * This is a dynamic version of ShortcutListPolicy and supports an additional buffer. - */ -class DynamicShortcutListPolicy : public DictionaryShortcutsStructurePolicy { - public: - explicit DynamicShortcutListPolicy(const BufferWithExtendableBuffer *const buffer) - : mBuffer(buffer) {} - - ~DynamicShortcutListPolicy() {} - - int getStartPos(const int pos) const { - if (pos == NOT_A_DICT_POS) { - return NOT_A_DICT_POS; - } - return pos + ShortcutListReadingUtils::getShortcutListSizeFieldSize(); - } - - void getNextShortcut(const int maxCodePointCount, int *const outCodePoint, - int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext, - int *const pos) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos); - const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - *pos -= mBuffer->getOriginalBufferSize(); - } - const ShortcutListReadingUtils::ShortcutFlags flags = - ShortcutListReadingUtils::getFlagsAndForwardPointer(buffer, pos); - if (outHasNext) { - *outHasNext = ShortcutListReadingUtils::hasNext(flags); - } - if (outIsWhitelist) { - *outIsWhitelist = ShortcutListReadingUtils::isWhitelist(flags); - } - if (outCodePoint) { - *outCodePointCount = ShortcutListReadingUtils::readShortcutTarget( - buffer, maxCodePointCount, outCodePoint, pos); - } - if (usesAdditionalBuffer) { - *pos += mBuffer->getOriginalBufferSize(); - } - } - - void skipAllShortcuts(int *const pos) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos); - const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer); - if (usesAdditionalBuffer) { - *pos -= mBuffer->getOriginalBufferSize(); - } - const int shortcutListSize = ShortcutListReadingUtils - ::getShortcutListSizeAndForwardPointer(buffer, pos); - *pos += shortcutListSize; - if (usesAdditionalBuffer) { - *pos += mBuffer->getOriginalBufferSize(); - } - } - - // Copy shortcuts from the shortcut list that starts at fromPos in mBuffer to toPos in - // bufferToWrite and advance these positions after the shortcut lists. This returns whether - // the copy was succeeded or not. - bool copyAllShortcutsAndReturnIfSucceededOrNot(BufferWithExtendableBuffer *const bufferToWrite, - int *const fromPos, int *const toPos) const { - const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*fromPos); - if (usesAdditionalBuffer) { - *fromPos -= mBuffer->getOriginalBufferSize(); - } - const int shortcutListSize = ShortcutListReadingUtils - ::getShortcutListSizeAndForwardPointer(mBuffer->getBuffer(usesAdditionalBuffer), - fromPos); - // Copy shortcut list size. - if (!bufferToWrite->writeUintAndAdvancePosition( - shortcutListSize + ShortcutListReadingUtils::getShortcutListSizeFieldSize(), - ShortcutListReadingUtils::getShortcutListSizeFieldSize(), toPos)) { - return false; - } - // Copy shortcut list. - for (int i = 0; i < shortcutListSize; ++i) { - const uint8_t data = ByteArrayUtils::readUint8AndAdvancePosition( - mBuffer->getBuffer(usesAdditionalBuffer), fromPos); - if (!bufferToWrite->writeUintAndAdvancePosition(data, 1 /* size */, toPos)) { - return false; - } - } - if (usesAdditionalBuffer) { - *fromPos += mBuffer->getOriginalBufferSize(); - } - return true; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicShortcutListPolicy); - - const BufferWithExtendableBuffer *const mBuffer; -}; -} // namespace latinime -#endif // LATINIME_DYNAMIC_SHORTCUT_LIST_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h index d73f73953..6d2b4778c 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h @@ -17,7 +17,7 @@ #ifndef LATINIME_SHORTCUT_LIST_POLICY_H #define LATINIME_SHORTCUT_LIST_POLICY_H -#include <stdint.h> +#include <cstdint> #include "defines.h" #include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h index a83ed5a50..d065bf7fd 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h @@ -17,7 +17,7 @@ #ifndef LATINIME_SHORTCUT_LIST_READING_UTILS_H #define LATINIME_SHORTCUT_LIST_READING_UTILS_H -#include <stdint.h> +#include <cstdint> #include "defines.h" diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h new file mode 100644 index 000000000..fe984615c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 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_VER4_SHORTCUT_LIST_POLICY_H +#define LATINIME_VER4_SHORTCUT_LIST_POLICY_H + +#include "defines.h" +#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" +#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" + +namespace latinime { + +class Ver4ShortcutListPolicy : public DictionaryShortcutsStructurePolicy { + public: + Ver4ShortcutListPolicy(ShortcutDictContent *const shortcutDictContent, + const TerminalPositionLookupTable *const terminalPositionLookupTable) + : mShortcutDictContent(shortcutDictContent) {} + + ~Ver4ShortcutListPolicy() {} + + int getStartPos(const int pos) const { + // The first shortcut entry is located at the head position of the shortcut list. + return pos; + } + + void getNextShortcut(const int maxCodePointCount, int *const outCodePoint, + int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext, + int *const pos) const { + int probability = 0; + mShortcutDictContent->getShortcutEntryAndAdvancePosition(maxCodePointCount, + outCodePoint, outCodePointCount, &probability, outHasNext, pos); + if (outIsWhitelist) { + *outIsWhitelist = ShortcutListReadingUtils::isWhitelist(probability); + } + } + + void skipAllShortcuts(int *const pos) const { + // Do nothing because we don't need to skip shortcut lists in ver4 dictionaries. + } + + bool addNewShortcut(const int terminalId, const int *const codePoints, const int codePointCount, + const int probability) { + const int shortcutListPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + if (shortcutListPos == NOT_A_DICT_POS) { + // Create shortcut list. + if (!mShortcutDictContent->createNewShortcutList(terminalId)) { + AKLOGE("Cannot create new shortcut list. terminal id: %d", terminalId); + return false; + } + const int writingPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + return mShortcutDictContent->writeShortcutEntry(codePoints, codePointCount, probability, + false /* hasNext */, writingPos); + } + const int entryPos = mShortcutDictContent->findShortcutEntryAndGetPos(shortcutListPos, + codePoints, codePointCount); + if (entryPos == NOT_A_DICT_POS) { + // Add new entry to the shortcut list. + // Create new shortcut list. + if (!mShortcutDictContent->createNewShortcutList(terminalId)) { + AKLOGE("Cannot create new shortcut list. terminal id: %d", terminalId); + return false; + } + int writingPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + if (!mShortcutDictContent->writeShortcutEntryAndAdvancePosition(codePoints, + codePointCount, probability, true /* hasNext */, &writingPos)) { + AKLOGE("Cannot write shortcut entry. terminal id: %d, pos: %d", terminalId, + writingPos); + return false; + } + return mShortcutDictContent->copyShortcutList(shortcutListPos, writingPos); + } + // Overwrite existing entry. + bool hasNext = false; + mShortcutDictContent->getShortcutEntry(MAX_WORD_LENGTH, 0 /* outCodePoint */, + 0 /* outCodePointCount */ , 0 /* probability */, &hasNext, entryPos); + if (!mShortcutDictContent->writeShortcutEntry(codePoints, + codePointCount, probability, hasNext, entryPos)) { + AKLOGE("Cannot overwrite shortcut entry. terminal id: %d, pos: %d", terminalId, + entryPos); + return false; + } + return true; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4ShortcutListPolicy); + + ShortcutDictContent *const mShortcutDictContent; +}; +} // namespace latinime +#endif // LATINIME_VER4_SHORTCUT_LIST_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp new file mode 100644 index 000000000..be7e43b98 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" + +#include <climits> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" +#include "suggest/policyimpl/dictionary/utils/format_utils.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +namespace latinime { + +/* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr + DictionaryStructureWithBufferPolicyFactory::newPolicyForExistingDictFile( + const char *const path, const int bufOffset, const int size, + const bool isUpdatable) { + if (FileUtils::existsDir(path)) { + // Given path represents a directory. + return newPolicyForDirectoryDict(path, isUpdatable); + } else { + if (isUpdatable) { + AKLOGE("One file dictionaries don't support updating. path: %s", path); + ASSERT(false); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + return newPolicyForFileDict(path, bufOffset, size); + } +} + +/* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr + DictionaryStructureWithBufferPolicyFactory:: newPolicyForOnMemoryDict( + const int formatVersion, const std::vector<int> &locale, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { + switch (formatVersion) { + case FormatUtils::VERSION_4: { + HeaderPolicy headerPolicy(FormatUtils::VERSION_4, locale, attributeMap); + Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers = + Ver4DictBuffers::createVer4DictBuffers(&headerPolicy, + Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE); + if (!DynamicPtWritingUtils::writeEmptyDictionary( + dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { + AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( + new Ver4PatriciaTriePolicy(std::move(dictBuffers))); + } + default: + AKLOGE("DICT: dictionary format %d is not supported for on memory dictionary", + formatVersion); + break; + } + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); +} + +/* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr + DictionaryStructureWithBufferPolicyFactory::newPolicyForDirectoryDict( + const char *const path, const bool isUpdatable) { + const int headerFilePathBufSize = PATH_MAX + 1 /* terminator */; + char headerFilePath[headerFilePathBufSize]; + getHeaderFilePathInDictDir(path, headerFilePathBufSize, headerFilePath); + // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of + // MmappedBufferPtr if the instance has the responsibility. + MmappedBuffer::MmappedBufferPtr mmappedBuffer( + MmappedBuffer::openBuffer(headerFilePath, isUpdatable)); + if (!mmappedBuffer) { + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + switch (FormatUtils::detectFormatVersion(mmappedBuffer->getBuffer(), + mmappedBuffer->getBufferSize())) { + case FormatUtils::VERSION_2: + AKLOGE("Given path is a directory but the format is version 2. path: %s", path); + break; + case FormatUtils::VERSION_4: { + const int dictDirPathBufSize = strlen(headerFilePath) + 1 /* terminator */; + char dictPath[dictDirPathBufSize]; + if (!FileUtils::getFilePathWithoutSuffix(headerFilePath, + Ver4DictConstants::HEADER_FILE_EXTENSION, dictDirPathBufSize, dictPath)) { + AKLOGE("Dictionary file name is not valid as a ver4 dictionary. path: %s", path); + ASSERT(false); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers( + Ver4DictBuffers::openVer4DictBuffers(dictPath, std::move(mmappedBuffer))); + if (!dictBuffers || !dictBuffers->isValid()) { + AKLOGE("DICT: The dictionary doesn't satisfy ver4 format requirements. path: %s", + path); + ASSERT(false); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( + new Ver4PatriciaTriePolicy(std::move(dictBuffers))); + } + default: + AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); + break; + } + ASSERT(false); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); +} + +/* static */ DictionaryStructureWithBufferPolicy::StructurePolicyPtr + DictionaryStructureWithBufferPolicyFactory::newPolicyForFileDict( + const char *const path, const int bufOffset, const int size) { + // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of + // MmappedBufferPtr if the instance has the responsibility. + MmappedBuffer::MmappedBufferPtr mmappedBuffer( + MmappedBuffer::openBuffer(path, bufOffset, size, false /* isUpdatable */)); + if (!mmappedBuffer) { + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); + } + switch (FormatUtils::detectFormatVersion(mmappedBuffer->getBuffer(), + mmappedBuffer->getBufferSize())) { + case FormatUtils::VERSION_2: + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr( + new PatriciaTriePolicy(std::move(mmappedBuffer))); + case FormatUtils::VERSION_4: + AKLOGE("Given path is a file but the format is version 4. path: %s", path); + break; + default: + AKLOGE("DICT: dictionary format is unknown, bad magic number. path: %s", path); + break; + } + ASSERT(false); + return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(nullptr); +} + +/* static */ void DictionaryStructureWithBufferPolicyFactory::getHeaderFilePathInDictDir( + const char *const dictDirPath, const int outHeaderFileBufSize, + char *const outHeaderFilePath) { + const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; + char dictName[dictNameBufSize]; + FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); + snprintf(outHeaderFilePath, outHeaderFileBufSize, "%s/%s%s", dictDirPath, + dictName, Ver4DictConstants::HEADER_FILE_EXTENSION); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h index 8cebc3b16..f71447e23 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h @@ -17,20 +17,36 @@ #ifndef LATINIME_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H #define LATINIME_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H -#include <stdint.h> +#include <vector> #include "defines.h" +#include "suggest/core/policy/dictionary_header_structure_policy.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" namespace latinime { class DictionaryStructureWithBufferPolicyFactory { public: - static DictionaryStructureWithBufferPolicy *newDictionaryStructureWithBufferPolicy( - const char *const path, const int bufOffset, const int size, const bool isUpdatable); + static DictionaryStructureWithBufferPolicy::StructurePolicyPtr + newPolicyForExistingDictFile(const char *const path, const int bufOffset, + const int size, const bool isUpdatable); + + static DictionaryStructureWithBufferPolicy::StructurePolicyPtr + newPolicyForOnMemoryDict(const int formatVersion, + const std::vector<int> &locale, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap); private: DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructureWithBufferPolicyFactory); + + static DictionaryStructureWithBufferPolicy::StructurePolicyPtr + newPolicyForDirectoryDict(const char *const path, const bool isUpdatable); + + static DictionaryStructureWithBufferPolicy::StructurePolicyPtr + newPolicyForFileDict(const char *const path, const int bufOffset, const int size); + + static void getHeaderFilePathInDictDir(const char *const dirPath, + const int outHeaderFileBufSize, char *const outHeaderFilePath); }; } // namespace latinime #endif // LATINIME_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp new file mode 100644 index 000000000..8f42df6d2 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h" + +#include "suggest/core/policy/dictionary_header_structure_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h" + +namespace latinime { + +bool DynamicPtGcEventListeners + ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + // PtNode is useless when the PtNode is not a terminal and doesn't have any not useless + // children. + bool isUselessPtNode = !ptNodeParams->isTerminal(); + if (ptNodeParams->isTerminal()) { + bool needsToKeepPtNode = true; + if (!mPtNodeWriter->updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC(ptNodeParams, + &needsToKeepPtNode)) { + AKLOGE("Cannot update PtNode probability or get needs to keep PtNode after GC."); + return false; + } + if (!needsToKeepPtNode) { + isUselessPtNode = true; + } + } + if (mChildrenValue > 0) { + isUselessPtNode = false; + } else if (ptNodeParams->isTerminal()) { + // Remove children as all children are useless. + if (!mPtNodeWriter->updateChildrenPosition(ptNodeParams, + NOT_A_DICT_POS /* newChildrenPosition */)) { + return false; + } + } + if (isUselessPtNode) { + // Current PtNode is no longer needed. Mark it as deleted. + if (!mPtNodeWriter->markPtNodeAsDeleted(ptNodeParams)) { + return false; + } + } else { + mValueStack.back() += 1; + if (ptNodeParams->isTerminal()) { + mValidUnigramCount += 1; + } + } + return true; +} + +bool DynamicPtGcEventListeners::TraversePolicyToUpdateBigramProbability + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + if (!ptNodeParams->isDeleted() && ptNodeParams->hasBigrams()) { + int bigramEntryCount = 0; + if (!mPtNodeWriter->updateAllBigramEntriesAndDeleteUselessEntries(ptNodeParams, + &bigramEntryCount)) { + return false; + } + mValidBigramEntryCount += bigramEntryCount; + } + return true; +} + +// Writes dummy PtNode array size when the head of PtNode array is read. +bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer + ::onDescend(const int ptNodeArrayPos) { + mValidPtNodeCount = 0; + int writingPos = mBufferToWrite->getTailPosition(); + mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.insert( + PtNodeWriter::PtNodeArrayPositionRelocationMap::value_type(ptNodeArrayPos, writingPos)); + // Writes dummy PtNode array size because arrays can have a forward link or needles PtNodes. + // This field will be updated later in onReadingPtNodeArrayTail() with actual PtNode count. + mPtNodeArraySizeFieldPos = writingPos; + return DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition( + mBufferToWrite, 0 /* arraySize */, &writingPos); +} + +// Write PtNode array terminal and actual PtNode array size. +bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer + ::onReadingPtNodeArrayTail() { + int writingPos = mBufferToWrite->getTailPosition(); + // Write PtNode array terminal. + if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition( + mBufferToWrite, NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { + return false; + } + // Write actual PtNode array size. + if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition( + mBufferToWrite, mValidPtNodeCount, &mPtNodeArraySizeFieldPos)) { + return false; + } + return true; +} + +// Write valid PtNode to buffer and memorize mapping from the old position to the new position. +bool DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + if (ptNodeParams->isDeleted()) { + // Current PtNode is not written in new buffer because it has been deleted. + mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert( + PtNodeWriter::PtNodePositionRelocationMap::value_type( + ptNodeParams->getHeadPos(), NOT_A_DICT_POS)); + return true; + } + int writingPos = mBufferToWrite->getTailPosition(); + mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert( + PtNodeWriter::PtNodePositionRelocationMap::value_type( + ptNodeParams->getHeadPos(), writingPos)); + mValidPtNodeCount++; + // Writes current PtNode. + return mPtNodeWriter->writePtNodeAndAdvancePosition(ptNodeParams, &writingPos); +} + +bool DynamicPtGcEventListeners::TraversePolicyToUpdateAllPositionFields + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + // Updates parent position. + int bigramCount = 0; + if (!mPtNodeWriter->updateAllPositionFields(ptNodeParams, mDictPositionRelocationMap, + &bigramCount)) { + return false; + } + mBigramCount += bigramCount; + if (ptNodeParams->isTerminal()) { + mUnigramCount++; + } + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h index 9755120b0..2aa402748 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h @@ -14,37 +14,31 @@ * limitations under the License. */ -#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H +#ifndef LATINIME_DYNAMIC_PT_GC_EVENT_LISTENERS_H +#define LATINIME_DYNAMIC_PT_GC_EVENT_LISTENERS_H #include <vector> #include "defines.h" -#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h" #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" -#include "utils/hash_map_compat.h" namespace latinime { -class DictionaryHeaderStructurePolicy; +class PtNodeParams; -class DynamicPatriciaTrieGcEventListeners { +class DynamicPtGcEventListeners { public: // Updates all PtNodes that can be reached from the root. Checks if each PtNode is useless or // not and marks useless PtNodes as deleted. Such deleted PtNodes will be discarded in the GC. // TODO: Concatenate non-terminal PtNodes. class TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted - : public DynamicPatriciaTrieReadingHelper::TraversingEventListener { + : public DynamicPtReadingHelper::TraversingEventListener { public: TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted( - const DictionaryHeaderStructurePolicy *const headerPolicy, - DynamicPatriciaTrieWritingHelper *const writingHelper, - BufferWithExtendableBuffer *const buffer, const bool isDecayingDict) - : mHeaderPolicy(headerPolicy), mWritingHelper(writingHelper), mBuffer(buffer), - mIsDecayingDict(isDecayingDict), mValueStack(), mChildrenValue(0), + PtNodeWriter *const ptNodeWriter) + : mPtNodeWriter(ptNodeWriter), mValueStack(), mChildrenValue(0), mValidUnigramCount(0) {} ~TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted() {}; @@ -66,8 +60,7 @@ class DynamicPatriciaTrieGcEventListeners { bool onReadingPtNodeArrayTail() { return true; } - bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints); + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); int getValidUnigramCount() const { return mValidUnigramCount; @@ -77,10 +70,7 @@ class DynamicPatriciaTrieGcEventListeners { DISALLOW_IMPLICIT_CONSTRUCTORS( TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted); - const DictionaryHeaderStructurePolicy *const mHeaderPolicy; - DynamicPatriciaTrieWritingHelper *const mWritingHelper; - BufferWithExtendableBuffer *const mBuffer; - const bool mIsDecayingDict; + PtNodeWriter *const mPtNodeWriter; std::vector<int> mValueStack; int mChildrenValue; int mValidUnigramCount; @@ -89,11 +79,10 @@ class DynamicPatriciaTrieGcEventListeners { // Updates all bigram entries that are held by valid PtNodes. This removes useless bigram // entries. class TraversePolicyToUpdateBigramProbability - : public DynamicPatriciaTrieReadingHelper::TraversingEventListener { + : public DynamicPtReadingHelper::TraversingEventListener { public: - TraversePolicyToUpdateBigramProbability( - DynamicBigramListPolicy *const bigramPolicy) - : mBigramPolicy(bigramPolicy), mValidBigramEntryCount(0) {} + TraversePolicyToUpdateBigramProbability(PtNodeWriter *const ptNodeWriter) + : mPtNodeWriter(ptNodeWriter), mValidBigramEntryCount(0) {} bool onAscend() { return true; } @@ -101,8 +90,7 @@ class DynamicPatriciaTrieGcEventListeners { bool onReadingPtNodeArrayTail() { return true; } - bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints); + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); int getValidBigramEntryCount() const { return mValidBigramEntryCount; @@ -111,19 +99,17 @@ class DynamicPatriciaTrieGcEventListeners { private: DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateBigramProbability); - DynamicBigramListPolicy *const mBigramPolicy; + PtNodeWriter *const mPtNodeWriter; int mValidBigramEntryCount; }; class TraversePolicyToPlaceAndWriteValidPtNodesToBuffer - : public DynamicPatriciaTrieReadingHelper::TraversingEventListener { + : public DynamicPtReadingHelper::TraversingEventListener { public: TraversePolicyToPlaceAndWriteValidPtNodesToBuffer( - DynamicPatriciaTrieWritingHelper *const writingHelper, - BufferWithExtendableBuffer *const bufferToWrite, - DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const - dictPositionRelocationMap) - : mWritingHelper(writingHelper), mBufferToWrite(bufferToWrite), + PtNodeWriter *const ptNodeWriter, BufferWithExtendableBuffer *const bufferToWrite, + PtNodeWriter::DictPositionRelocationMap *const dictPositionRelocationMap) + : mPtNodeWriter(ptNodeWriter), mBufferToWrite(bufferToWrite), mDictPositionRelocationMap(dictPositionRelocationMap), mValidPtNodeCount(0), mPtNodeArraySizeFieldPos(NOT_A_DICT_POS) {}; @@ -133,31 +119,24 @@ class DynamicPatriciaTrieGcEventListeners { bool onReadingPtNodeArrayTail(); - bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints); + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); private: DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToPlaceAndWriteValidPtNodesToBuffer); - DynamicPatriciaTrieWritingHelper *const mWritingHelper; + PtNodeWriter *const mPtNodeWriter; BufferWithExtendableBuffer *const mBufferToWrite; - DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const - mDictPositionRelocationMap; + PtNodeWriter::DictPositionRelocationMap *const mDictPositionRelocationMap; int mValidPtNodeCount; int mPtNodeArraySizeFieldPos; }; class TraversePolicyToUpdateAllPositionFields - : public DynamicPatriciaTrieReadingHelper::TraversingEventListener { + : public DynamicPtReadingHelper::TraversingEventListener { public: - TraversePolicyToUpdateAllPositionFields( - DynamicPatriciaTrieWritingHelper *const writingHelper, - DynamicBigramListPolicy *const bigramPolicy, - BufferWithExtendableBuffer *const bufferToWrite, - const DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const - dictPositionRelocationMap) - : mWritingHelper(writingHelper), mBigramPolicy(bigramPolicy), - mBufferToWrite(bufferToWrite), + TraversePolicyToUpdateAllPositionFields(PtNodeWriter *const ptNodeWriter, + const PtNodeWriter::DictPositionRelocationMap *const dictPositionRelocationMap) + : mPtNodeWriter(ptNodeWriter), mDictPositionRelocationMap(dictPositionRelocationMap), mUnigramCount(0), mBigramCount(0) {}; @@ -167,8 +146,7 @@ class DynamicPatriciaTrieGcEventListeners { bool onReadingPtNodeArrayTail() { return true; } - bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node, - const int *const nodeCodePoints); + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); int getUnigramCount() const { return mUnigramCount; @@ -181,17 +159,14 @@ class DynamicPatriciaTrieGcEventListeners { private: DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateAllPositionFields); - DynamicPatriciaTrieWritingHelper *const mWritingHelper; - DynamicBigramListPolicy *const mBigramPolicy; - BufferWithExtendableBuffer *const mBufferToWrite; - const DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const - mDictPositionRelocationMap; + PtNodeWriter *const mPtNodeWriter; + const PtNodeWriter::DictPositionRelocationMap *const mDictPositionRelocationMap; int mUnigramCount; int mBigramCount; }; private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieGcEventListeners); + DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtGcEventListeners); }; } // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H */ +#endif /* LATINIME_DYNAMIC_PT_GC_EVENT_LISTENERS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp new file mode 100644 index 000000000..086d98b4a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h" +#include "utils/char_utils.h" + +namespace latinime { + +// To avoid infinite loop caused by invalid or malicious forward links. +const int DynamicPtReadingHelper::MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP = 100000; +const int DynamicPtReadingHelper::MAX_PT_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP = 100000; +const size_t DynamicPtReadingHelper::MAX_READING_STATE_STACK_SIZE = MAX_WORD_LENGTH; + +bool DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions::onVisitingPtNode( + const PtNodeParams *const ptNodeParams) { + if (ptNodeParams->isTerminal() && !ptNodeParams->isDeleted()) { + mTerminalPositions->push_back(ptNodeParams->getHeadPos()); + } + return true; +} + +// Visits all PtNodes in post-order depth first manner. +// For example, visits c -> b -> y -> x -> a for the following dictionary: +// a _ b _ c +// \ x _ y +bool DynamicPtReadingHelper::traverseAllPtNodesInPostorderDepthFirstManner( + TraversingEventListener *const listener) { + bool alreadyVisitedChildren = false; + // Descend from the root to the root PtNode array. + if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) { + return false; + } + while (!isEnd()) { + const PtNodeParams ptNodeParams(getPtNodeParams()); + if (!ptNodeParams.isValid()) { + break; + } + if (!alreadyVisitedChildren) { + if (ptNodeParams.hasChildren()) { + // Move to the first child. + if (!listener->onDescend(ptNodeParams.getChildrenPos())) { + return false; + } + pushReadingStateToStack(); + readChildNode(ptNodeParams); + } else { + alreadyVisitedChildren = true; + } + } else { + if (!listener->onVisitingPtNode(&ptNodeParams)) { + return false; + } + readNextSiblingNode(ptNodeParams); + if (isEnd()) { + // All PtNodes in current linked PtNode arrays have been visited. + // Return to the parent. + if (!listener->onReadingPtNodeArrayTail()) { + return false; + } + if (mReadingStateStack.size() <= 0) { + break; + } + if (!listener->onAscend()) { + return false; + } + popReadingStateFromStack(); + alreadyVisitedChildren = true; + } else { + // Process sibling PtNode. + alreadyVisitedChildren = false; + } + } + } + // Ascend from the root PtNode array to the root. + if (!listener->onAscend()) { + return false; + } + return !isError(); +} + +// Visits all PtNodes in PtNode array level pre-order depth first manner, which is the same order +// that PtNodes are written in the dictionary buffer. +// For example, visits a -> b -> x -> c -> y for the following dictionary: +// a _ b _ c +// \ x _ y +bool DynamicPtReadingHelper::traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + TraversingEventListener *const listener) { + bool alreadyVisitedAllPtNodesInArray = false; + bool alreadyVisitedChildren = false; + // Descend from the root to the root PtNode array. + if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) { + return false; + } + if (isEnd()) { + // Empty dictionary. Needs to notify the listener of the tail of empty PtNode array. + if (!listener->onReadingPtNodeArrayTail()) { + return false; + } + } + pushReadingStateToStack(); + while (!isEnd()) { + const PtNodeParams ptNodeParams(getPtNodeParams()); + if (!ptNodeParams.isValid()) { + break; + } + if (alreadyVisitedAllPtNodesInArray) { + if (alreadyVisitedChildren) { + // Move to next sibling PtNode's children. + readNextSiblingNode(ptNodeParams); + if (isEnd()) { + // Return to the parent PTNode. + if (!listener->onAscend()) { + return false; + } + if (mReadingStateStack.size() <= 0) { + break; + } + popReadingStateFromStack(); + alreadyVisitedChildren = true; + alreadyVisitedAllPtNodesInArray = true; + } else { + alreadyVisitedChildren = false; + } + } else { + if (ptNodeParams.hasChildren()) { + // Move to the first child. + if (!listener->onDescend(ptNodeParams.getChildrenPos())) { + return false; + } + pushReadingStateToStack(); + readChildNode(ptNodeParams); + // Push state to return the head of PtNode array. + pushReadingStateToStack(); + alreadyVisitedAllPtNodesInArray = false; + alreadyVisitedChildren = false; + } else { + alreadyVisitedChildren = true; + } + } + } else { + if (!listener->onVisitingPtNode(&ptNodeParams)) { + return false; + } + readNextSiblingNode(ptNodeParams); + if (isEnd()) { + if (!listener->onReadingPtNodeArrayTail()) { + return false; + } + // Return to the head of current PtNode array. + popReadingStateFromStack(); + alreadyVisitedAllPtNodesInArray = true; + } + } + } + popReadingStateFromStack(); + // Ascend from the root PtNode array to the root. + if (!listener->onAscend()) { + return false; + } + return !isError(); +} + +int DynamicPtReadingHelper::getCodePointsAndProbabilityAndReturnCodePointCount( + const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) { + // This method traverses parent nodes from the terminal by following parent pointers; thus, + // node code points are stored in the buffer in the reverse order. + int reverseCodePoints[maxCodePointCount]; + const PtNodeParams terminalPtNodeParams(getPtNodeParams()); + // First, read the terminal node and get its probability. + if (!isValidTerminalNode(terminalPtNodeParams)) { + // Node at the ptNodePos is not a valid terminal node. + *outUnigramProbability = NOT_A_PROBABILITY; + return 0; + } + // Store terminal node probability. + *outUnigramProbability = terminalPtNodeParams.getProbability(); + // Then, following parent node link to the dictionary root and fetch node code points. + int totalCodePointCount = 0; + while (!isEnd()) { + const PtNodeParams ptNodeParams(getPtNodeParams()); + totalCodePointCount = getTotalCodePointCount(ptNodeParams); + if (!ptNodeParams.isValid() || totalCodePointCount > maxCodePointCount) { + // The ptNodePos is not a valid terminal node position in the dictionary. + *outUnigramProbability = NOT_A_PROBABILITY; + return 0; + } + // Store node code points to buffer in the reverse order. + fetchMergedNodeCodePointsInReverseOrder(ptNodeParams, getPrevTotalCodePointCount(), + reverseCodePoints); + // Follow parent node toward the root node. + readParentNode(ptNodeParams); + } + if (isError()) { + // The node position or the dictionary is invalid. + *outUnigramProbability = NOT_A_PROBABILITY; + return 0; + } + // Reverse the stored code points to output them. + for (int i = 0; i < totalCodePointCount; ++i) { + outCodePoints[i] = reverseCodePoints[totalCodePointCount - i - 1]; + } + return totalCodePointCount; +} + +int DynamicPtReadingHelper::getTerminalPtNodePositionOfWord(const int *const inWord, + const int length, const bool forceLowerCaseSearch) { + int searchCodePoints[length]; + for (int i = 0; i < length; ++i) { + searchCodePoints[i] = forceLowerCaseSearch ? CharUtils::toLowerCase(inWord[i]) : inWord[i]; + } + while (!isEnd()) { + const PtNodeParams ptNodeParams(getPtNodeParams()); + const int matchedCodePointCount = getPrevTotalCodePointCount(); + if (getTotalCodePointCount(ptNodeParams) > length + || !isMatchedCodePoint(ptNodeParams, 0 /* index */, + searchCodePoints[matchedCodePointCount])) { + // Current node has too many code points or its first code point is different from + // target code point. Skip this node and read the next sibling node. + readNextSiblingNode(ptNodeParams); + continue; + } + // Check following merged node code points. + const int nodeCodePointCount = ptNodeParams.getCodePointCount(); + for (int j = 1; j < nodeCodePointCount; ++j) { + if (!isMatchedCodePoint(ptNodeParams, j, searchCodePoints[matchedCodePointCount + j])) { + // Different code point is found. The given word is not included in the dictionary. + return NOT_A_DICT_POS; + } + } + // All characters are matched. + if (length == getTotalCodePointCount(ptNodeParams)) { + if (!ptNodeParams.isTerminal()) { + return NOT_A_DICT_POS; + } + // Terminal position is found. + return ptNodeParams.getHeadPos(); + } + if (!ptNodeParams.hasChildren()) { + return NOT_A_DICT_POS; + } + // Advance to the children nodes. + readChildNode(ptNodeParams); + } + // If we already traversed the tree further than the word is long, there means + // there was no match (or we would have found it). + return NOT_A_DICT_POS; +} + +// Read node array size and process empty node arrays. Nodes and arrays are counted up in this +// method to avoid an infinite loop. +void DynamicPtReadingHelper::nextPtNodeArray() { + int ptNodeCountInArray = 0; + int firstPtNodePos = NOT_A_DICT_POS; + if (!mPtNodeArrayReader->readPtNodeArrayInfoAndReturnIfValid( + mReadingState.mPos, &ptNodeCountInArray, &firstPtNodePos)) { + mIsError = true; + mReadingState.mPos = NOT_A_DICT_POS; + return; + } + mReadingState.mPosOfThisPtNodeArrayHead = mReadingState.mPos; + mReadingState.mRemainingPtNodeCountInThisArray = ptNodeCountInArray; + mReadingState.mPos = firstPtNodePos; + // Count up nodes and node arrays to avoid infinite loop. + mReadingState.mTotalPtNodeIndexInThisArrayChain += + mReadingState.mRemainingPtNodeCountInThisArray; + mReadingState.mPtNodeArrayIndexInThisArrayChain++; + if (mReadingState.mRemainingPtNodeCountInThisArray < 0 + || mReadingState.mTotalPtNodeIndexInThisArrayChain + > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP + || mReadingState.mPtNodeArrayIndexInThisArrayChain + > MAX_PT_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP) { + // Invalid dictionary. + AKLOGI("Invalid dictionary. nodeCount: %d, totalNodeCount: %d, MAX_CHILD_COUNT: %d" + "nodeArrayCount: %d, MAX_NODE_ARRAY_COUNT: %d", + mReadingState.mRemainingPtNodeCountInThisArray, + mReadingState.mTotalPtNodeIndexInThisArrayChain, + MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP, + mReadingState.mPtNodeArrayIndexInThisArrayChain, + MAX_PT_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP); + ASSERT(false); + mIsError = true; + mReadingState.mPos = NOT_A_DICT_POS; + return; + } + if (mReadingState.mRemainingPtNodeCountInThisArray == 0) { + // Empty node array. Try following forward link. + followForwardLink(); + } +} + +// Follow the forward link and read the next node array if exists. +void DynamicPtReadingHelper::followForwardLink() { + int nextPtNodeArrayPos = NOT_A_DICT_POS; + if (!mPtNodeArrayReader->readForwardLinkAndReturnIfValid( + mReadingState.mPos, &nextPtNodeArrayPos)) { + mIsError = true; + mReadingState.mPos = NOT_A_DICT_POS; + return; + } + mReadingState.mPosOfLastForwardLinkField = mReadingState.mPos; + if (nextPtNodeArrayPos != NOT_A_DICT_POS) { + // Follow the forward link. + mReadingState.mPos = nextPtNodeArrayPos; + nextPtNodeArray(); + } else { + // All node arrays have been read. + mReadingState.mPos = NOT_A_DICT_POS; + } +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h new file mode 100644 index 000000000..cc7b5ff70 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2013, 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_DYNAMIC_PT_READING_HELPER_H +#define LATINIME_DYNAMIC_PT_READING_HELPER_H + +#include <cstddef> +#include <vector> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h" + +namespace latinime { + +class DictionaryBigramsStructurePolicy; +class DictionaryShortcutsStructurePolicy; +class PtNodeArrayReader; + +/* + * This class is used for traversing dynamic patricia trie. This class supports iterating nodes and + * dealing with additional buffer. This class counts nodes and node arrays to avoid infinite loop. + */ +class DynamicPtReadingHelper { + public: + class TraversingEventListener { + public: + virtual ~TraversingEventListener() {}; + + // Returns whether the event handling was succeeded or not. + virtual bool onAscend() = 0; + + // Returns whether the event handling was succeeded or not. + virtual bool onDescend(const int ptNodeArrayPos) = 0; + + // Returns whether the event handling was succeeded or not. + virtual bool onReadingPtNodeArrayTail() = 0; + + // Returns whether the event handling was succeeded or not. + virtual bool onVisitingPtNode(const PtNodeParams *const node) = 0; + + protected: + TraversingEventListener() {}; + + private: + DISALLOW_COPY_AND_ASSIGN(TraversingEventListener); + }; + + class TraversePolicyToGetAllTerminalPtNodePositions : public TraversingEventListener { + public: + TraversePolicyToGetAllTerminalPtNodePositions(std::vector<int> *const terminalPositions) + : mTerminalPositions(terminalPositions) {} + bool onAscend() { return true; } + bool onDescend(const int ptNodeArrayPos) { return true; } + bool onReadingPtNodeArrayTail() { return true; } + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToGetAllTerminalPtNodePositions); + + std::vector<int> *const mTerminalPositions; + }; + + DynamicPtReadingHelper(const PtNodeReader *const ptNodeReader, + const PtNodeArrayReader *const ptNodeArrayReader) + : mIsError(false), mReadingState(), mPtNodeReader(ptNodeReader), + mPtNodeArrayReader(ptNodeArrayReader), mReadingStateStack() {} + + ~DynamicPtReadingHelper() {} + + AK_FORCE_INLINE bool isError() const { + return mIsError; + } + + AK_FORCE_INLINE bool isEnd() const { + return mReadingState.mPos == NOT_A_DICT_POS; + } + + // Initialize reading state with the head position of a PtNode array. + AK_FORCE_INLINE void initWithPtNodeArrayPos(const int ptNodeArrayPos) { + if (ptNodeArrayPos == NOT_A_DICT_POS) { + mReadingState.mPos = NOT_A_DICT_POS; + } else { + mIsError = false; + mReadingState.mPos = ptNodeArrayPos; + mReadingState.mTotalCodePointCountSinceInitialization = 0; + mReadingState.mTotalPtNodeIndexInThisArrayChain = 0; + mReadingState.mPtNodeArrayIndexInThisArrayChain = 0; + mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; + mReadingStateStack.clear(); + nextPtNodeArray(); + } + } + + // Initialize reading state with the head position of a node. + AK_FORCE_INLINE void initWithPtNodePos(const int ptNodePos) { + if (ptNodePos == NOT_A_DICT_POS) { + mReadingState.mPos = NOT_A_DICT_POS; + } else { + mIsError = false; + mReadingState.mPos = ptNodePos; + mReadingState.mRemainingPtNodeCountInThisArray = 1; + mReadingState.mTotalCodePointCountSinceInitialization = 0; + mReadingState.mTotalPtNodeIndexInThisArrayChain = 1; + mReadingState.mPtNodeArrayIndexInThisArrayChain = 1; + mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; + mReadingState.mPosOfThisPtNodeArrayHead = NOT_A_DICT_POS; + mReadingStateStack.clear(); + } + } + + AK_FORCE_INLINE const PtNodeParams getPtNodeParams() const { + if (isEnd()) { + return PtNodeParams(); + } + return mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(mReadingState.mPos); + } + + AK_FORCE_INLINE bool isValidTerminalNode(const PtNodeParams &ptNodeParams) const { + return !isEnd() && !ptNodeParams.isDeleted() && ptNodeParams.isTerminal(); + } + + AK_FORCE_INLINE bool isMatchedCodePoint(const PtNodeParams &ptNodeParams, const int index, + const int codePoint) const { + return ptNodeParams.getCodePoints()[index] == codePoint; + } + + // Return code point count exclude the last read node's code points. + AK_FORCE_INLINE int getPrevTotalCodePointCount() const { + return mReadingState.mTotalCodePointCountSinceInitialization; + } + + // Return code point count include the last read node's code points. + AK_FORCE_INLINE int getTotalCodePointCount(const PtNodeParams &ptNodeParams) const { + return mReadingState.mTotalCodePointCountSinceInitialization + + ptNodeParams.getCodePointCount(); + } + + AK_FORCE_INLINE void fetchMergedNodeCodePointsInReverseOrder(const PtNodeParams &ptNodeParams, + const int index, int *const outCodePoints) const { + const int nodeCodePointCount = ptNodeParams.getCodePointCount(); + const int *const nodeCodePoints = ptNodeParams.getCodePoints(); + for (int i = 0; i < nodeCodePointCount; ++i) { + outCodePoints[index + i] = nodeCodePoints[nodeCodePointCount - 1 - i]; + } + } + + AK_FORCE_INLINE void readNextSiblingNode(const PtNodeParams &ptNodeParams) { + mReadingState.mRemainingPtNodeCountInThisArray -= 1; + mReadingState.mPos = ptNodeParams.getSiblingNodePos(); + if (mReadingState.mRemainingPtNodeCountInThisArray <= 0) { + // All nodes in the current node array have been read. + followForwardLink(); + } + } + + // Read the first child node of the current node. + AK_FORCE_INLINE void readChildNode(const PtNodeParams &ptNodeParams) { + if (ptNodeParams.hasChildren()) { + mReadingState.mTotalCodePointCountSinceInitialization += + ptNodeParams.getCodePointCount(); + mReadingState.mTotalPtNodeIndexInThisArrayChain = 0; + mReadingState.mPtNodeArrayIndexInThisArrayChain = 0; + mReadingState.mPos = ptNodeParams.getChildrenPos(); + mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; + // Read children node array. + nextPtNodeArray(); + } else { + mReadingState.mPos = NOT_A_DICT_POS; + } + } + + // Read the parent node of the current node. + AK_FORCE_INLINE void readParentNode(const PtNodeParams &ptNodeParams) { + if (ptNodeParams.getParentPos() != NOT_A_DICT_POS) { + mReadingState.mTotalCodePointCountSinceInitialization += + ptNodeParams.getCodePointCount(); + mReadingState.mTotalPtNodeIndexInThisArrayChain = 1; + mReadingState.mPtNodeArrayIndexInThisArrayChain = 1; + mReadingState.mRemainingPtNodeCountInThisArray = 1; + mReadingState.mPos = ptNodeParams.getParentPos(); + mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS; + mReadingState.mPosOfThisPtNodeArrayHead = NOT_A_DICT_POS; + } else { + mReadingState.mPos = NOT_A_DICT_POS; + } + } + + AK_FORCE_INLINE int getPosOfLastForwardLinkField() const { + return mReadingState.mPosOfLastForwardLinkField; + } + + AK_FORCE_INLINE int getPosOfLastPtNodeArrayHead() const { + return mReadingState.mPosOfThisPtNodeArrayHead; + } + + bool traverseAllPtNodesInPostorderDepthFirstManner(TraversingEventListener *const listener); + + bool traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + TraversingEventListener *const listener); + + int getCodePointsAndProbabilityAndReturnCodePointCount(const int maxCodePointCount, + int *const outCodePoints, int *const outUnigramProbability); + + int getTerminalPtNodePositionOfWord(const int *const inWord, const int length, + const bool forceLowerCaseSearch); + + private: + DISALLOW_COPY_AND_ASSIGN(DynamicPtReadingHelper); + + // This class encapsulates the reading state of a position in the dictionary. It points at a + // specific PtNode in the dictionary. + class PtNodeReadingState { + public: + // Note that copy constructor and assignment operator are used for this class to use + // std::vector. + PtNodeReadingState() : mPos(NOT_A_DICT_POS), mRemainingPtNodeCountInThisArray(0), + mTotalCodePointCountSinceInitialization(0), mTotalPtNodeIndexInThisArrayChain(0), + mPtNodeArrayIndexInThisArrayChain(0), mPosOfLastForwardLinkField(NOT_A_DICT_POS), + mPosOfThisPtNodeArrayHead(NOT_A_DICT_POS) {} + + int mPos; + // Remaining node count in the current array. + int mRemainingPtNodeCountInThisArray; + int mTotalCodePointCountSinceInitialization; + // Counter of PtNodes used to avoid infinite loops caused by broken or malicious links. + int mTotalPtNodeIndexInThisArrayChain; + // Counter of PtNode arrays used to avoid infinite loops caused by cyclic links of empty + // PtNode arrays. + int mPtNodeArrayIndexInThisArrayChain; + int mPosOfLastForwardLinkField; + int mPosOfThisPtNodeArrayHead; + }; + + static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP; + static const int MAX_PT_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP; + static const size_t MAX_READING_STATE_STACK_SIZE; + + // TODO: Introduce error code to track what caused the error. + bool mIsError; + PtNodeReadingState mReadingState; + const PtNodeReader *const mPtNodeReader; + const PtNodeArrayReader *const mPtNodeArrayReader; + std::vector<PtNodeReadingState> mReadingStateStack; + + void nextPtNodeArray(); + + void followForwardLink(); + + AK_FORCE_INLINE void pushReadingStateToStack() { + if (mReadingStateStack.size() > MAX_READING_STATE_STACK_SIZE) { + AKLOGI("Reading state stack overflow. Max size: %zd", MAX_READING_STATE_STACK_SIZE); + ASSERT(false); + mIsError = true; + mReadingState.mPos = NOT_A_DICT_POS; + } else { + mReadingStateStack.push_back(mReadingState); + } + } + + AK_FORCE_INLINE void popReadingStateFromStack() { + if (mReadingStateStack.empty()) { + mReadingState.mPos = NOT_A_DICT_POS; + } else { + mReadingState = mReadingStateStack.back(); + mReadingStateStack.pop_back(); + } + } +}; +} // namespace latinime +#endif /* LATINIME_DYNAMIC_PT_READING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.cpp index d68446db6..3586b50ab 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.cpp @@ -14,38 +14,38 @@ * limitations under the License. */ -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" #include "defines.h" #include "suggest/policyimpl/dictionary/utils/byte_array_utils.h" namespace latinime { -typedef DynamicPatriciaTrieReadingUtils DptReadingUtils; - -const DptReadingUtils::NodeFlags DptReadingUtils::MASK_MOVED = 0xC0; -const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_NOT_MOVED = 0xC0; -const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_MOVED = 0x40; -const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_DELETED = 0x80; +const DynamicPtReadingUtils::NodeFlags DynamicPtReadingUtils::MASK_MOVED = 0xC0; +const DynamicPtReadingUtils::NodeFlags DynamicPtReadingUtils::FLAG_IS_NOT_MOVED = 0xC0; +const DynamicPtReadingUtils::NodeFlags DynamicPtReadingUtils::FLAG_IS_MOVED = 0x40; +const DynamicPtReadingUtils::NodeFlags DynamicPtReadingUtils::FLAG_IS_DELETED = 0x80; +const DynamicPtReadingUtils::NodeFlags DynamicPtReadingUtils::FLAG_WILL_BECOME_NON_TERMINAL = 0x00; // TODO: Make DICT_OFFSET_ZERO_OFFSET = 0. // Currently, DICT_OFFSET_INVALID is 0 in Java side but offset can be 0 during GC. So, the maximum // value of offsets, which is 0x7FFFFF is used to represent 0 offset. -const int DptReadingUtils::DICT_OFFSET_INVALID = 0; -const int DptReadingUtils::DICT_OFFSET_ZERO_OFFSET = 0x7FFFFF; +const int DynamicPtReadingUtils::DICT_OFFSET_INVALID = 0; +const int DynamicPtReadingUtils::DICT_OFFSET_ZERO_OFFSET = 0x7FFFFF; -/* static */ int DptReadingUtils::getForwardLinkPosition(const uint8_t *const buffer, +/* static */ int DynamicPtReadingUtils::getForwardLinkPosition(const uint8_t *const buffer, const int pos) { int linkAddressPos = pos; return ByteArrayUtils::readSint24AndAdvancePosition(buffer, &linkAddressPos); } -/* static */ int DptReadingUtils::getParentPtNodePosOffsetAndAdvancePosition( +/* static */ int DynamicPtReadingUtils::getParentPtNodePosOffsetAndAdvancePosition( const uint8_t *const buffer, int *const pos) { return ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos); } -/* static */ int DptReadingUtils::getParentPtNodePos(const int parentOffset, const int ptNodePos) { +/* static */ int DynamicPtReadingUtils::getParentPtNodePos(const int parentOffset, + const int ptNodePos) { if (parentOffset == DICT_OFFSET_INVALID) { return NOT_A_DICT_POS; } else if (parentOffset == DICT_OFFSET_ZERO_OFFSET) { @@ -55,7 +55,7 @@ const int DptReadingUtils::DICT_OFFSET_ZERO_OFFSET = 0x7FFFFF; } } -/* static */ int DptReadingUtils::readChildrenPositionAndAdvancePosition( +/* static */ int DynamicPtReadingUtils::readChildrenPositionAndAdvancePosition( const uint8_t *const buffer, int *const pos) { const int base = *pos; const int offset = ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos); diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h index 67c3cc57e..b13a075d5 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h @@ -14,16 +14,16 @@ * limitations under the License. */ -#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_READING_UTILS_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_READING_UTILS_H +#ifndef LATINIME_DYNAMIC_PT_READING_UTILS_H +#define LATINIME_DYNAMIC_PT_READING_UTILS_H -#include <stdint.h> +#include <cstdint> #include "defines.h" namespace latinime { -class DynamicPatriciaTrieReadingUtils { +class DynamicPtReadingUtils { public: typedef uint8_t NodeFlags; @@ -54,22 +54,30 @@ class DynamicPatriciaTrieReadingUtils { return FLAG_IS_DELETED == (MASK_MOVED & flags); } + static AK_FORCE_INLINE bool willBecomeNonTerminal(const NodeFlags flags) { + return FLAG_WILL_BECOME_NON_TERMINAL == (MASK_MOVED & flags); + } + static AK_FORCE_INLINE NodeFlags updateAndGetFlags(const NodeFlags originalFlags, - const bool isMoved, const bool isDeleted) { + const bool isMoved, const bool isDeleted, const bool willBecomeNonTerminal) { NodeFlags flags = originalFlags; + flags = willBecomeNonTerminal ? + ((flags & (~MASK_MOVED)) | FLAG_WILL_BECOME_NON_TERMINAL) : flags; flags = isMoved ? ((flags & (~MASK_MOVED)) | FLAG_IS_MOVED) : flags; flags = isDeleted ? ((flags & (~MASK_MOVED)) | FLAG_IS_DELETED) : flags; - flags = (!isMoved && !isDeleted) ? ((flags & (~MASK_MOVED)) | FLAG_IS_NOT_MOVED) : flags; + flags = (!isMoved && !isDeleted && !willBecomeNonTerminal) ? + ((flags & (~MASK_MOVED)) | FLAG_IS_NOT_MOVED) : flags; return flags; } private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieReadingUtils); + DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtReadingUtils); static const NodeFlags MASK_MOVED; static const NodeFlags FLAG_IS_NOT_MOVED; static const NodeFlags FLAG_IS_MOVED; static const NodeFlags FLAG_IS_DELETED; + static const NodeFlags FLAG_WILL_BECOME_NON_TERMINAL; }; } // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_READING_UTILS_H */ +#endif /* LATINIME_DYNAMIC_PT_READING_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp new file mode 100644 index 000000000..e02dd5550 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +const int DynamicPtUpdatingHelper::CHILDREN_POSITION_FIELD_SIZE = 3; + +bool DynamicPtUpdatingHelper::addUnigramWord( + DynamicPtReadingHelper *const readingHelper, + const int *const wordCodePoints, const int codePointCount, const int probability, + const bool isNotAWord, const bool isBlacklisted, const int timestamp, + bool *const outAddedNewUnigram) { + int parentPos = NOT_A_DICT_POS; + while (!readingHelper->isEnd()) { + const PtNodeParams ptNodeParams(readingHelper->getPtNodeParams()); + if (!ptNodeParams.isValid()) { + break; + } + const int matchedCodePointCount = readingHelper->getPrevTotalCodePointCount(); + if (!readingHelper->isMatchedCodePoint(ptNodeParams, 0 /* index */, + wordCodePoints[matchedCodePointCount])) { + // The first code point is different from target code point. Skip this node and read + // the next sibling node. + readingHelper->readNextSiblingNode(ptNodeParams); + continue; + } + // Check following merged node code points. + const int nodeCodePointCount = ptNodeParams.getCodePointCount(); + for (int j = 1; j < nodeCodePointCount; ++j) { + const int nextIndex = matchedCodePointCount + j; + if (nextIndex >= codePointCount || !readingHelper->isMatchedCodePoint(ptNodeParams, j, + wordCodePoints[matchedCodePointCount + j])) { + *outAddedNewUnigram = true; + return reallocatePtNodeAndAddNewPtNodes(&ptNodeParams, j, isNotAWord, isBlacklisted, + probability, timestamp, wordCodePoints + matchedCodePointCount, + codePointCount - matchedCodePointCount); + } + } + // All characters are matched. + if (codePointCount == readingHelper->getTotalCodePointCount(ptNodeParams)) { + return setPtNodeProbability(&ptNodeParams, isNotAWord, isBlacklisted, probability, + timestamp, outAddedNewUnigram); + } + if (!ptNodeParams.hasChildren()) { + *outAddedNewUnigram = true; + return createChildrenPtNodeArrayAndAChildPtNode(&ptNodeParams, + isNotAWord, isBlacklisted, probability, timestamp, + wordCodePoints + readingHelper->getTotalCodePointCount(ptNodeParams), + codePointCount - readingHelper->getTotalCodePointCount(ptNodeParams)); + } + // Advance to the children nodes. + parentPos = ptNodeParams.getHeadPos(); + readingHelper->readChildNode(ptNodeParams); + } + if (readingHelper->isError()) { + // The dictionary is invalid. + return false; + } + int pos = readingHelper->getPosOfLastForwardLinkField(); + *outAddedNewUnigram = true; + return createAndInsertNodeIntoPtNodeArray(parentPos, + wordCodePoints + readingHelper->getPrevTotalCodePointCount(), + codePointCount - readingHelper->getPrevTotalCodePointCount(), + isNotAWord, isBlacklisted, probability, timestamp, &pos); +} + +bool DynamicPtUpdatingHelper::addBigramWords(const int word0Pos, const int word1Pos, + const int probability, const int timestamp, bool *const outAddedNewBigram) { + const PtNodeParams sourcePtNodeParams( + mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word0Pos)); + const PtNodeParams targetPtNodeParams( + mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word1Pos)); + return mPtNodeWriter->addNewBigramEntry(&sourcePtNodeParams, &targetPtNodeParams, probability, + timestamp, outAddedNewBigram); +} + +// Remove a bigram relation from word0Pos to word1Pos. +bool DynamicPtUpdatingHelper::removeBigramWords(const int word0Pos, const int word1Pos) { + const PtNodeParams sourcePtNodeParams( + mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word0Pos)); + const PtNodeParams targetPtNodeParams( + mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(word1Pos)); + return mPtNodeWriter->removeBigramEntry(&sourcePtNodeParams, &targetPtNodeParams); +} + +bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability) { + const PtNodeParams ptNodeParams(mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(wordPos)); + return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints, targetCodePointCount, + shortcutProbability); +} + +bool DynamicPtUpdatingHelper::createAndInsertNodeIntoPtNodeArray(const int parentPos, + const int *const nodeCodePoints, const int nodeCodePointCount, + const bool isNotAWord, const bool isBlacklisted, const int probability, + const int timestamp, int *const forwardLinkFieldPos) { + const int newPtNodeArrayPos = mBuffer->getTailPosition(); + if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, + newPtNodeArrayPos, forwardLinkFieldPos)) { + return false; + } + return createNewPtNodeArrayWithAChildPtNode(parentPos, nodeCodePoints, nodeCodePointCount, + isNotAWord, isBlacklisted, probability, timestamp); +} + +bool DynamicPtUpdatingHelper::setPtNodeProbability( + const PtNodeParams *const originalPtNodeParams, const bool isNotAWord, + const bool isBlacklisted, const int probability, const int timestamp, + bool *const outAddedNewUnigram) { + if (originalPtNodeParams->isTerminal()) { + // Overwrites the probability. + *outAddedNewUnigram = false; + return mPtNodeWriter->updatePtNodeProbability(originalPtNodeParams, probability, timestamp); + } else { + // Make the node terminal and write the probability. + *outAddedNewUnigram = true; + const int movedPos = mBuffer->getTailPosition(); + int writingPos = movedPos; + const PtNodeParams ptNodeParamsToWrite(getUpdatedPtNodeParams(originalPtNodeParams, + isNotAWord, isBlacklisted, true /* isTerminal */, + originalPtNodeParams->getParentPos(), originalPtNodeParams->getCodePointCount(), + originalPtNodeParams->getCodePoints(), probability)); + if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite, + timestamp, &writingPos)) { + return false; + } + if (!mPtNodeWriter->markPtNodeAsMoved(originalPtNodeParams, movedPos, movedPos)) { + return false; + } + } + return true; +} + +bool DynamicPtUpdatingHelper::createChildrenPtNodeArrayAndAChildPtNode( + const PtNodeParams *const parentPtNodeParams, const bool isNotAWord, + const bool isBlacklisted, const int probability, const int timestamp, + const int *const codePoints, const int codePointCount) { + const int newPtNodeArrayPos = mBuffer->getTailPosition(); + if (!mPtNodeWriter->updateChildrenPosition(parentPtNodeParams, newPtNodeArrayPos)) { + return false; + } + return createNewPtNodeArrayWithAChildPtNode(parentPtNodeParams->getHeadPos(), codePoints, + codePointCount, isNotAWord, isBlacklisted, probability, timestamp); +} + +bool DynamicPtUpdatingHelper::createNewPtNodeArrayWithAChildPtNode( + const int parentPtNodePos, const int *const nodeCodePoints, const int nodeCodePointCount, + const bool isNotAWord, const bool isBlacklisted, const int probability, + const int timestamp) { + int writingPos = mBuffer->getTailPosition(); + if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer, + 1 /* arraySize */, &writingPos)) { + return false; + } + const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode( + isNotAWord, isBlacklisted, true /* isTerminal */, + parentPtNodePos, nodeCodePointCount, nodeCodePoints, probability)); + if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite, timestamp, + &writingPos)) { + return false; + } + if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, + NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { + return false; + } + return true; +} + +// Returns whether the dictionary updating was succeeded or not. +bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes( + const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount, + const bool isNotAWord, const bool isBlacklisted, const int probabilityOfNewPtNode, + const int timestamp, const int *const newNodeCodePoints, const int newNodeCodePointCount) { + // When addsExtraChild is true, split the reallocating PtNode and add new child. + // Reallocating PtNode: abcde, newNode: abcxy. + // abc (1st, not terminal) __ de (2nd) + // \_ xy (extra child, terminal) + // Otherwise, this method makes 1st part terminal and write probabilityOfNewPtNode. + // Reallocating PtNode: abcde, newNode: abc. + // abc (1st, terminal) __ de (2nd) + const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount; + const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition(); + int writingPos = firstPartOfReallocatedPtNodePos; + // Write the 1st part of the reallocating node. The children position will be updated later + // with actual children position. + if (addsExtraChild) { + const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode( + false /* isNotAWord */, false /* isBlacklisted */, false /* isTerminal */, + reallocatingPtNodeParams->getParentPos(), overlappingCodePointCount, + reallocatingPtNodeParams->getCodePoints(), NOT_A_PROBABILITY)); + if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&ptNodeParamsToWrite, &writingPos)) { + return false; + } + } else { + const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode( + isNotAWord, isBlacklisted, true /* isTerminal */, + reallocatingPtNodeParams->getParentPos(), overlappingCodePointCount, + reallocatingPtNodeParams->getCodePoints(), probabilityOfNewPtNode)); + if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite, + timestamp, &writingPos)) { + return false; + } + } + const int actualChildrenPos = writingPos; + // Create new children PtNode array. + const size_t newPtNodeCount = addsExtraChild ? 2 : 1; + if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer, + newPtNodeCount, &writingPos)) { + return false; + } + // Write the 2nd part of the reallocating node. + const int secondPartOfReallocatedPtNodePos = writingPos; + const PtNodeParams childPartPtNodeParams(getUpdatedPtNodeParams(reallocatingPtNodeParams, + reallocatingPtNodeParams->isNotAWord(), reallocatingPtNodeParams->isBlacklisted(), + reallocatingPtNodeParams->isTerminal(), firstPartOfReallocatedPtNodePos, + reallocatingPtNodeParams->getCodePointCount() - overlappingCodePointCount, + reallocatingPtNodeParams->getCodePoints() + overlappingCodePointCount, + reallocatingPtNodeParams->getProbability())); + if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&childPartPtNodeParams, &writingPos)) { + return false; + } + if (addsExtraChild) { + const PtNodeParams extraChildPtNodeParams(getPtNodeParamsForNewPtNode( + isNotAWord, isBlacklisted, true /* isTerminal */, + firstPartOfReallocatedPtNodePos, newNodeCodePointCount - overlappingCodePointCount, + newNodeCodePoints + overlappingCodePointCount, probabilityOfNewPtNode)); + if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&extraChildPtNodeParams, + timestamp, &writingPos)) { + return false; + } + } + if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer, + NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) { + return false; + } + // Update original reallocating PtNode as moved. + if (!mPtNodeWriter->markPtNodeAsMoved(reallocatingPtNodeParams, firstPartOfReallocatedPtNodePos, + secondPartOfReallocatedPtNodePos)) { + return false; + } + // Load node info. Information of the 1st part will be fetched. + const PtNodeParams ptNodeParams( + mPtNodeReader->fetchNodeInfoInBufferFromPtNodePos(firstPartOfReallocatedPtNodePos)); + // Update children position. + return mPtNodeWriter->updateChildrenPosition(&ptNodeParams, actualChildrenPos); +} + +const PtNodeParams DynamicPtUpdatingHelper::getUpdatedPtNodeParams( + const PtNodeParams *const originalPtNodeParams, const bool isNotAWord, + const bool isBlacklisted, const bool isTerminal, const int parentPos, + const int codePointCount, const int *const codePoints, const int probability) const { + const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags( + isBlacklisted, isNotAWord, isTerminal, originalPtNodeParams->hasShortcutTargets(), + originalPtNodeParams->hasBigrams(), codePointCount > 1 /* hasMultipleChars */, + CHILDREN_POSITION_FIELD_SIZE); + return PtNodeParams(originalPtNodeParams, flags, parentPos, codePointCount, codePoints, + probability); +} + +const PtNodeParams DynamicPtUpdatingHelper::getPtNodeParamsForNewPtNode( + const bool isNotAWord, const bool isBlacklisted, const bool isTerminal, + const int parentPos, const int codePointCount, const int *const codePoints, + const int probability) const { + const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags( + isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */, + false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */, + CHILDREN_POSITION_FIELD_SIZE); + return PtNodeParams(flags, parentPos, codePointCount, codePoints, probability); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h new file mode 100644 index 000000000..9b2815263 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2013, 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_DYNAMIC_PT_UPDATING_HELPER_H +#define LATINIME_DYNAMIC_PT_UPDATING_HELPER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" + +namespace latinime { + +class BufferWithExtendableBuffer; +class DynamicPtReadingHelper; +class PtNodeReader; +class PtNodeWriter; + +class DynamicPtUpdatingHelper { + public: + DynamicPtUpdatingHelper(BufferWithExtendableBuffer *const buffer, + const PtNodeReader *const ptNodeReader, PtNodeWriter *const ptNodeWriter) + : mBuffer(buffer), mPtNodeReader(ptNodeReader), mPtNodeWriter(ptNodeWriter) {} + + ~DynamicPtUpdatingHelper() {} + + // Add a word to the dictionary. If the word already exists, update the probability. + bool addUnigramWord(DynamicPtReadingHelper *const readingHelper, + const int *const wordCodePoints, const int codePointCount, const int probability, + const bool isNotAWord, const bool isBlacklisted, const int timestamp, + bool *const outAddedNewUnigram); + + // Add a bigram relation from word0Pos to word1Pos. + bool addBigramWords(const int word0Pos, const int word1Pos, const int probability, + const int timestamp, bool *const outAddedNewBigram); + + // Remove a bigram relation from word0Pos to word1Pos. + bool removeBigramWords(const int word0Pos, const int word1Pos); + + // Add a shortcut target. + bool addShortcutTarget(const int wordPos, const int *const targetCodePoints, + const int targetCodePointCount, const int shortcutProbability); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtUpdatingHelper); + + static const int CHILDREN_POSITION_FIELD_SIZE; + + BufferWithExtendableBuffer *const mBuffer; + const PtNodeReader *const mPtNodeReader; + PtNodeWriter *const mPtNodeWriter; + + bool createAndInsertNodeIntoPtNodeArray(const int parentPos, const int *const nodeCodePoints, + const int nodeCodePointCount, const bool isNotAWord, const bool isBlacklisted, + const int probability, const int timestamp, int *const forwardLinkFieldPos); + + bool setPtNodeProbability(const PtNodeParams *const originalPtNodeParams, const bool isNotAWord, + const bool isBlacklisted, const int probability, const int timestamp, + bool *const outAddedNewUnigram); + + bool createChildrenPtNodeArrayAndAChildPtNode(const PtNodeParams *const parentPtNodeParams, + const bool isNotAWord, const bool isBlacklisted, const int probability, + const int timestamp, const int *const codePoints, const int codePointCount); + + bool createNewPtNodeArrayWithAChildPtNode(const int parentPos, const int *const nodeCodePoints, + const int nodeCodePointCount, const bool isNotAWord, const bool isBlacklisted, + const int probability, const int timestamp); + + bool reallocatePtNodeAndAddNewPtNodes( + const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount, + const bool isNotAWord, const bool isBlacklisted, const int probabilityOfNewPtNode, + const int timestamp, const int *const newNodeCodePoints, + const int newNodeCodePointCount); + + const PtNodeParams getUpdatedPtNodeParams(const PtNodeParams *const originalPtNodeParams, + const bool isNotAWord, const bool isBlacklisted, const bool isTerminal, + const int parentPos, const int codePointCount, + const int *const codePoints, const int probability) const; + + const PtNodeParams getPtNodeParamsForNewPtNode(const bool isNotAWord, const bool isBlacklisted, + const bool isTerminal, const int parentPos, + const int codePointCount, const int *const codePoints, const int probability) const; +}; +} // namespace latinime +#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_UPDATING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.cpp index 30ff10cd6..664aeebbb 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.cpp @@ -14,29 +14,28 @@ * limitations under the License. */ -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" #include <cstddef> +#include <cstdint> #include <cstdlib> -#include <stdint.h> #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" namespace latinime { -const size_t DynamicPatriciaTrieWritingUtils::MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD = 0x7F; -const size_t DynamicPatriciaTrieWritingUtils::MAX_PTNODE_ARRAY_SIZE = 0x7FFF; -const int DynamicPatriciaTrieWritingUtils::SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE = 1; -const int DynamicPatriciaTrieWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE = 2; -const int DynamicPatriciaTrieWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG = 0x8000; -const int DynamicPatriciaTrieWritingUtils::DICT_OFFSET_FIELD_SIZE = 3; -const int DynamicPatriciaTrieWritingUtils::MAX_DICT_OFFSET_VALUE = 0x7FFFFF; -const int DynamicPatriciaTrieWritingUtils::MIN_DICT_OFFSET_VALUE = -0x7FFFFF; -const int DynamicPatriciaTrieWritingUtils::DICT_OFFSET_NEGATIVE_FLAG = 0x800000; -const int DynamicPatriciaTrieWritingUtils::PROBABILITY_FIELD_SIZE = 1; -const int DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE = 1; +const size_t DynamicPtWritingUtils::MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD = 0x7F; +const size_t DynamicPtWritingUtils::MAX_PTNODE_ARRAY_SIZE = 0x7FFF; +const int DynamicPtWritingUtils::SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE = 1; +const int DynamicPtWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE = 2; +const int DynamicPtWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG = 0x8000; +const int DynamicPtWritingUtils::DICT_OFFSET_FIELD_SIZE = 3; +const int DynamicPtWritingUtils::MAX_DICT_OFFSET_VALUE = 0x7FFFFF; +const int DynamicPtWritingUtils::MIN_DICT_OFFSET_VALUE = -0x7FFFFF; +const int DynamicPtWritingUtils::DICT_OFFSET_NEGATIVE_FLAG = 0x800000; +const int DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE = 1; -/* static */ bool DynamicPatriciaTrieWritingUtils::writeEmptyDictionary( +/* static */ bool DynamicPtWritingUtils::writeEmptyDictionary( BufferWithExtendableBuffer *const buffer, const int rootPos) { int writingPos = rootPos; if (!writePtNodeArraySizeAndAdvancePosition(buffer, 0 /* arraySize */, &writingPos)) { @@ -46,13 +45,13 @@ const int DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE = 1; &writingPos); } -/* static */ bool DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition( BufferWithExtendableBuffer *const buffer, const int forwardLinkPos, int *const forwardLinkFieldPos) { return writeDictOffset(buffer, forwardLinkPos, (*forwardLinkFieldPos), forwardLinkFieldPos); } -/* static */ bool DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition( BufferWithExtendableBuffer *const buffer, const size_t arraySize, int *const arraySizeFieldPos) { // Currently, all array size field to be created has LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE to @@ -74,20 +73,20 @@ const int DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE = 1; } } -/* static */ bool DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writeFlagsAndAdvancePosition( BufferWithExtendableBuffer *const buffer, - const DynamicPatriciaTrieReadingUtils::NodeFlags nodeFlags, int *const nodeFlagsFieldPos) { + const DynamicPtReadingUtils::NodeFlags nodeFlags, int *const nodeFlagsFieldPos) { return buffer->writeUintAndAdvancePosition(nodeFlags, NODE_FLAG_FIELD_SIZE, nodeFlagsFieldPos); } // Note that parentOffset is offset from node's head position. -/* static */ bool DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( BufferWithExtendableBuffer *const buffer, const int parentPos, const int basePos, int *const parentPosFieldPos) { return writeDictOffset(buffer, parentPos, basePos, parentPosFieldPos); } -/* static */ bool DynamicPatriciaTrieWritingUtils::writeCodePointsAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writeCodePointsAndAdvancePosition( BufferWithExtendableBuffer *const buffer, const int *const codePoints, const int codePointCount, int *const codePointFieldPos) { if (codePointCount <= 0) { @@ -101,34 +100,20 @@ const int DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE = 1; hasMultipleCodePoints, codePointFieldPos); } -/* static */ bool DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition( - BufferWithExtendableBuffer *const buffer, const int probability, - int *const probabilityFieldPos) { - if (probability < 0 || probability > MAX_PROBABILITY) { - AKLOGI("probability cannot be written because the probability is invalid: %d", - probability); - ASSERT(false); - return false; - } - return buffer->writeUintAndAdvancePosition(probability, PROBABILITY_FIELD_SIZE, - probabilityFieldPos); -} - -/* static */ bool DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition( +/* static */ bool DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition( BufferWithExtendableBuffer *const buffer, const int childrenPosition, int *const childrenPositionFieldPos) { return writeDictOffset(buffer, childrenPosition, (*childrenPositionFieldPos), childrenPositionFieldPos); } -/* static */ bool DynamicPatriciaTrieWritingUtils::writeDictOffset( - BufferWithExtendableBuffer *const buffer, const int targetPos, const int basePos, - int *const offsetFieldPos) { +/* static */ bool DynamicPtWritingUtils::writeDictOffset(BufferWithExtendableBuffer *const buffer, + const int targetPos, const int basePos, int *const offsetFieldPos) { int offset = targetPos - basePos; if (targetPos == NOT_A_DICT_POS) { - offset = DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID; + offset = DynamicPtReadingUtils::DICT_OFFSET_INVALID; } else if (offset == 0) { - offset = DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET; + offset = DynamicPtReadingUtils::DICT_OFFSET_ZERO_OFFSET; } if (offset > MAX_DICT_OFFSET_VALUE || offset < MIN_DICT_OFFSET_VALUE) { AKLOGI("offset cannot be written because the offset is too large or too small: %d", diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h index af76bc6b5..362fbd1cc 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H -#define LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H +#ifndef LATINIME_DYNAMIC_PT_WRITING_UTILS_H +#define LATINIME_DYNAMIC_PT_WRITING_UTILS_H #include <cstddef> #include "defines.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" namespace latinime { class BufferWithExtendableBuffer; -class DynamicPatriciaTrieWritingUtils { +class DynamicPtWritingUtils { public: static const int NODE_FLAG_FIELD_SIZE; @@ -39,8 +39,15 @@ class DynamicPatriciaTrieWritingUtils { static bool writePtNodeArraySizeAndAdvancePosition(BufferWithExtendableBuffer *const buffer, const size_t arraySize, int *const arraySizeFieldPos); + static bool writeFlags(BufferWithExtendableBuffer *const buffer, + const DynamicPtReadingUtils::NodeFlags nodeFlags, + const int nodeFlagsFieldPos) { + int writingPos = nodeFlagsFieldPos; + return writeFlagsAndAdvancePosition(buffer, nodeFlags, &writingPos); + } + static bool writeFlagsAndAdvancePosition(BufferWithExtendableBuffer *const buffer, - const DynamicPatriciaTrieReadingUtils::NodeFlags nodeFlags, + const DynamicPtReadingUtils::NodeFlags nodeFlags, int *const nodeFlagsFieldPos); static bool writeParentPosOffsetAndAdvancePosition(BufferWithExtendableBuffer *const buffer, @@ -49,14 +56,11 @@ class DynamicPatriciaTrieWritingUtils { static bool writeCodePointsAndAdvancePosition(BufferWithExtendableBuffer *const buffer, const int *const codePoints, const int codePointCount, int *const codePointFieldPos); - static bool writeProbabilityAndAdvancePosition(BufferWithExtendableBuffer *const buffer, - const int probability, int *const probabilityFieldPos); - static bool writeChildrenPositionAndAdvancePosition(BufferWithExtendableBuffer *const buffer, const int childrenPosition, int *const childrenPositionFieldPos); private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieWritingUtils); + DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtWritingUtils); static const size_t MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD; static const size_t MAX_PTNODE_ARRAY_SIZE; @@ -67,10 +71,9 @@ class DynamicPatriciaTrieWritingUtils { static const int MAX_DICT_OFFSET_VALUE; static const int MIN_DICT_OFFSET_VALUE; static const int DICT_OFFSET_NEGATIVE_FLAG; - static const int PROBABILITY_FIELD_SIZE; static bool writeDictOffset(BufferWithExtendableBuffer *const buffer, const int targetPos, const int basePos, int *const offsetFieldPos); }; } // namespace latinime -#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H */ +#endif /* LATINIME_DYNAMIC_PT_WRITING_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp index 7df55815f..e64a13cc4 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" #include "defines.h" +#include "suggest/core/policy/dictionary_bigrams_structure_policy.h" +#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" #include "suggest/policyimpl/dictionary/utils/byte_array_utils.h" namespace latinime { @@ -130,4 +132,32 @@ const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_BLACKLISTED = 0x01; return base + offset; } +/* static */ void PtReadingUtils::readPtNodeInfo(const uint8_t *const dictBuf, const int ptNodePos, + const DictionaryShortcutsStructurePolicy *const shortcutPolicy, + const DictionaryBigramsStructurePolicy *const bigramPolicy, + NodeFlags *const outFlags, int *const outCodePointCount, int *const outCodePoint, + int *const outProbability, int *const outChildrenPos, int *const outShortcutPos, + int *const outBigramPos, int *const outSiblingPos) { + int readingPos = ptNodePos; + const NodeFlags flags = getFlagsAndAdvancePosition(dictBuf, &readingPos); + *outFlags = flags; + *outCodePointCount = getCharsAndAdvancePosition( + dictBuf, flags, MAX_WORD_LENGTH, outCodePoint, &readingPos); + *outProbability = isTerminal(flags) ? + readProbabilityAndAdvancePosition(dictBuf, &readingPos) : NOT_A_PROBABILITY; + *outChildrenPos = hasChildrenInFlags(flags) ? + readChildrenPositionAndAdvancePosition(dictBuf, flags, &readingPos) : NOT_A_DICT_POS; + *outShortcutPos = NOT_A_DICT_POS; + if (hasShortcutTargets(flags)) { + *outShortcutPos = readingPos; + shortcutPolicy->skipAllShortcuts(&readingPos); + } + *outBigramPos = NOT_A_DICT_POS; + if (hasBigrams(flags)) { + *outBigramPos = readingPos; + bigramPolicy->skipAllBigrams(&readingPos); + } + *outSiblingPos = readingPos; +} + } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h index 8420ee95a..c3f09c3b1 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h @@ -17,12 +17,15 @@ #ifndef LATINIME_PATRICIA_TRIE_READING_UTILS_H #define LATINIME_PATRICIA_TRIE_READING_UTILS_H -#include <stdint.h> +#include <cstdint> #include "defines.h" namespace latinime { +class DictionaryShortcutsStructurePolicy; +class DictionaryBigramsStructurePolicy; + class PatriciaTrieReadingUtils { public: typedef uint8_t NodeFlags; @@ -100,6 +103,13 @@ class PatriciaTrieReadingUtils { return nodeFlags; } + static void readPtNodeInfo(const uint8_t *const dictBuf, const int ptNodePos, + const DictionaryShortcutsStructurePolicy *const shortcutPolicy, + const DictionaryBigramsStructurePolicy *const bigramPolicy, + NodeFlags *const outFlags, int *const outCodePointCount, int *const outCodePoint, + int *const outProbability, int *const outChildrenPos, int *const outShortcutPos, + int *const outBigramPos, int *const outSiblingPos); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTrieReadingUtils); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h new file mode 100644 index 000000000..6078d8285 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014, 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_PT_NODE_ARRAY_READER_H +#define LATINIME_PT_NODE_ARRAY_READER_H + +#include "defines.h" + +namespace latinime { + +// Interface class used to read PtNode array information. +class PtNodeArrayReader { + public: + virtual ~PtNodeArrayReader() {} + + // Returns if the position is valid or not. + virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const = 0; + + // Returns if the position is valid or not. NOT_A_DICT_POS is set to outNextPtNodeArrayPos when + // the next array doesn't exist. + virtual bool readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const = 0; + + protected: + PtNodeArrayReader() {}; + + private: + DISALLOW_COPY_AND_ASSIGN(PtNodeArrayReader); +}; +} // namespace latinime +#endif /* LATINIME_PT_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h new file mode 100644 index 000000000..91192fc57 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2013, 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_PT_NODE_PARAMS_H +#define LATINIME_PT_NODE_PARAMS_H + +#include <cstring> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" + +namespace latinime { + +// This class has information of a PtNode. This class is immutable. +class PtNodeParams { + public: + // Invalid PtNode. + PtNodeParams() : mHeadPos(NOT_A_DICT_POS), mFlags(0), mHasMovedFlag(false), + mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mCodePoints(), + mTerminalIdFieldPos(NOT_A_DICT_POS), mTerminalId(Ver4DictConstants::NOT_A_TERMINAL_ID), + mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(NOT_A_PROBABILITY), + mChildrenPosFieldPos(NOT_A_DICT_POS), mChildrenPos(NOT_A_DICT_POS), + mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS), + mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_DICT_POS) {} + + PtNodeParams(const PtNodeParams& ptNodeParams) + : mHeadPos(ptNodeParams.mHeadPos), mFlags(ptNodeParams.mFlags), + mHasMovedFlag(ptNodeParams.mHasMovedFlag), mParentPos(ptNodeParams.mParentPos), + mCodePointCount(ptNodeParams.mCodePointCount), mCodePoints(), + mTerminalIdFieldPos(ptNodeParams.mTerminalIdFieldPos), + mTerminalId(ptNodeParams.mTerminalId), + mProbabilityFieldPos(ptNodeParams.mProbabilityFieldPos), + mProbability(ptNodeParams.mProbability), + mChildrenPosFieldPos(ptNodeParams.mChildrenPosFieldPos), + mChildrenPos(ptNodeParams.mChildrenPos), + mBigramLinkedNodePos(ptNodeParams.mBigramLinkedNodePos), + mShortcutPos(ptNodeParams.mShortcutPos), mBigramPos(ptNodeParams.mBigramPos), + mSiblingPos(ptNodeParams.mSiblingPos) { + memcpy(mCodePoints, ptNodeParams.getCodePoints(), sizeof(int) * mCodePointCount); + } + + // PtNode read from version 2 dictionary. + PtNodeParams(const int headPos, const PatriciaTrieReadingUtils::NodeFlags flags, + const int codePointCount, const int *const codePoints, const int probability, + const int childrenPos, const int shortcutPos, const int bigramPos, + const int siblingPos) + : mHeadPos(headPos), mFlags(flags), mHasMovedFlag(false), mParentPos(NOT_A_DICT_POS), + mCodePointCount(codePointCount), mCodePoints(), mTerminalIdFieldPos(NOT_A_DICT_POS), + mTerminalId(Ver4DictConstants::NOT_A_TERMINAL_ID), + mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(probability), + mChildrenPosFieldPos(NOT_A_DICT_POS), mChildrenPos(childrenPos), + mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(shortcutPos), + mBigramPos(bigramPos), mSiblingPos(siblingPos) { + memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount); + } + + // PtNode with a terminal id. + PtNodeParams(const int headPos, const PatriciaTrieReadingUtils::NodeFlags flags, + const int parentPos, const int codePointCount, const int *const codePoints, + const int terminalIdFieldPos, const int terminalId, const int probability, + const int childrenPosFieldPos, const int childrenPos, const int siblingPos) + : mHeadPos(headPos), mFlags(flags), mHasMovedFlag(true), mParentPos(parentPos), + mCodePointCount(codePointCount), mCodePoints(), + mTerminalIdFieldPos(terminalIdFieldPos), mTerminalId(terminalId), + mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(probability), + mChildrenPosFieldPos(childrenPosFieldPos), mChildrenPos(childrenPos), + mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(terminalId), + mBigramPos(terminalId), mSiblingPos(siblingPos) { + memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount); + } + + // Construct new params by updating existing PtNode params. + PtNodeParams(const PtNodeParams *const ptNodeParams, + const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos, + const int codePointCount, const int *const codePoints, const int probability) + : mHeadPos(ptNodeParams->getHeadPos()), mFlags(flags), mHasMovedFlag(true), + mParentPos(parentPos), mCodePointCount(codePointCount), mCodePoints(), + mTerminalIdFieldPos(ptNodeParams->getTerminalIdFieldPos()), + mTerminalId(ptNodeParams->getTerminalId()), + mProbabilityFieldPos(ptNodeParams->getProbabilityFieldPos()), + mProbability(probability), + mChildrenPosFieldPos(ptNodeParams->getChildrenPosFieldPos()), + mChildrenPos(ptNodeParams->getChildrenPos()), + mBigramLinkedNodePos(ptNodeParams->getBigramLinkedNodePos()), + mShortcutPos(ptNodeParams->getShortcutPos()), + mBigramPos(ptNodeParams->getBigramsPos()), + mSiblingPos(ptNodeParams->getSiblingNodePos()) { + memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount); + } + + PtNodeParams(const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos, + const int codePointCount, const int *const codePoints, const int probability) + : mHeadPos(NOT_A_DICT_POS), mFlags(flags), mHasMovedFlag(true), mParentPos(parentPos), + mCodePointCount(codePointCount), mCodePoints(), + mTerminalIdFieldPos(NOT_A_DICT_POS), + mTerminalId(Ver4DictConstants::NOT_A_TERMINAL_ID), + mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(probability), + mChildrenPosFieldPos(NOT_A_DICT_POS), mChildrenPos(NOT_A_DICT_POS), + mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS), + mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_DICT_POS) { + memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount); + } + + AK_FORCE_INLINE bool isValid() const { + return mCodePointCount > 0; + } + + // Head position of the PtNode + AK_FORCE_INLINE int getHeadPos() const { + return mHeadPos; + } + + // Flags + AK_FORCE_INLINE bool isDeleted() const { + return mHasMovedFlag && DynamicPtReadingUtils::isDeleted(mFlags); + } + + AK_FORCE_INLINE bool willBecomeNonTerminal() const { + return mHasMovedFlag && DynamicPtReadingUtils::willBecomeNonTerminal(mFlags); + } + + AK_FORCE_INLINE bool hasChildren() const { + return mChildrenPos != NOT_A_DICT_POS; + } + + AK_FORCE_INLINE bool isTerminal() const { + return PatriciaTrieReadingUtils::isTerminal(mFlags); + } + + AK_FORCE_INLINE bool isBlacklisted() const { + return PatriciaTrieReadingUtils::isBlacklisted(mFlags); + } + + AK_FORCE_INLINE bool isNotAWord() const { + return PatriciaTrieReadingUtils::isNotAWord(mFlags); + } + + AK_FORCE_INLINE bool hasBigrams() const { + return PatriciaTrieReadingUtils::hasBigrams(mFlags); + } + + AK_FORCE_INLINE bool hasShortcutTargets() const { + return PatriciaTrieReadingUtils::hasShortcutTargets(mFlags); + } + + // Parent node position + AK_FORCE_INLINE int getParentPos() const { + return mParentPos; + } + + // Number of code points + AK_FORCE_INLINE uint8_t getCodePointCount() const { + return mCodePointCount; + } + + AK_FORCE_INLINE const int *getCodePoints() const { + return mCodePoints; + } + + // Probability + AK_FORCE_INLINE int getTerminalIdFieldPos() const { + return mTerminalIdFieldPos; + } + + AK_FORCE_INLINE int getTerminalId() const { + return mTerminalId; + } + + // Probability + AK_FORCE_INLINE int getProbabilityFieldPos() const { + return mProbabilityFieldPos; + } + + AK_FORCE_INLINE int getProbability() const { + return mProbability; + } + + // Children PtNode array position + AK_FORCE_INLINE int getChildrenPosFieldPos() const { + return mChildrenPosFieldPos; + } + + AK_FORCE_INLINE int getChildrenPos() const { + return mChildrenPos; + } + + // Bigram linked node position. + AK_FORCE_INLINE int getBigramLinkedNodePos() const { + return mBigramLinkedNodePos; + } + + // Shortcutlist position + AK_FORCE_INLINE int getShortcutPos() const { + return mShortcutPos; + } + + // Bigrams position + AK_FORCE_INLINE int getBigramsPos() const { + return mBigramPos; + } + + // Sibling node position + AK_FORCE_INLINE int getSiblingNodePos() const { + return mSiblingPos; + } + + private: + // This class have a public copy constructor to be used as a return value. + DISALLOW_ASSIGNMENT_OPERATOR(PtNodeParams); + + const int mHeadPos; + const PatriciaTrieReadingUtils::NodeFlags mFlags; + const bool mHasMovedFlag; + const int mParentPos; + const uint8_t mCodePointCount; + int mCodePoints[MAX_WORD_LENGTH]; + const int mTerminalIdFieldPos; + const int mTerminalId; + const int mProbabilityFieldPos; + const int mProbability; + const int mChildrenPosFieldPos; + const int mChildrenPos; + const int mBigramLinkedNodePos; + const int mShortcutPos; + const int mBigramPos; + const int mSiblingPos; +}; +} // namespace latinime +#endif /* LATINIME_PT_NODE_PARAMS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h new file mode 100644 index 000000000..c6b2a8bed --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013, 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_PT_NODE_READER_H +#define LATINIME_PT_NODE_READER_H + +#include "defines.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" + +namespace latinime { + +// Interface class used to read PtNode information. +class PtNodeReader { + public: + virtual ~PtNodeReader() {} + virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const = 0; + + protected: + PtNodeReader() {}; + + private: + DISALLOW_COPY_AND_ASSIGN(PtNodeReader); +}; +} // namespace latinime +#endif /* LATINIME_PT_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h new file mode 100644 index 000000000..e843f074a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013, 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_PT_NODE_WRITER_H +#define LATINIME_PT_NODE_WRITER_H + +#include <unordered_map> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" + +namespace latinime { + +// Interface class used to write PtNode information. +class PtNodeWriter { + public: + typedef std::unordered_map<int, int> PtNodeArrayPositionRelocationMap; + typedef std::unordered_map<int, int> PtNodePositionRelocationMap; + struct DictPositionRelocationMap { + public: + DictPositionRelocationMap() + : mPtNodeArrayPositionRelocationMap(), mPtNodePositionRelocationMap() {} + + PtNodeArrayPositionRelocationMap mPtNodeArrayPositionRelocationMap; + PtNodePositionRelocationMap mPtNodePositionRelocationMap; + + private: + DISALLOW_COPY_AND_ASSIGN(DictPositionRelocationMap); + }; + + virtual ~PtNodeWriter() {} + + virtual bool markPtNodeAsDeleted(const PtNodeParams *const toBeUpdatedPtNodeParams) = 0; + + virtual bool markPtNodeAsMoved(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int movedPos, const int bigramLinkedNodePos) = 0; + + virtual bool markPtNodeAsWillBecomeNonTerminal( + const PtNodeParams *const toBeUpdatedPtNodeParams) = 0; + + virtual bool updatePtNodeProbability(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int probability, const int timestamp) = 0; + + virtual bool updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( + const PtNodeParams *const toBeUpdatedPtNodeParams, + bool *const outNeedsToKeepPtNode) = 0; + + virtual bool updateChildrenPosition(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newChildrenPosition) = 0; + + virtual bool writePtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + int *const ptNodeWritingPos) = 0; + + virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + const int timestamp, int *const ptNodeWritingPos) = 0; + + virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam, const int probability, const int timestamp, + bool *const outAddedNewBigram) = 0; + + virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam) = 0; + + virtual bool updateAllBigramEntriesAndDeleteUselessEntries( + const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount) = 0; + + virtual bool updateAllPositionFields(const PtNodeParams *const toBeUpdatedPtNodeParams, + const DictPositionRelocationMap *const dictPositionRelocationMap, + int *const outBigramEntryCount) = 0; + + virtual bool addShortcutTarget(const PtNodeParams *const ptNodeParams, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability) = 0; + + protected: + PtNodeWriter() {}; + + private: + DISALLOW_COPY_AND_ASSIGN(PtNodeWriter); +}; +} // namespace latinime +#endif /* LATINIME_PT_NODE_WRITER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp index 8a84bd261..b3af1f47a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp @@ -15,25 +15,28 @@ */ -#include "suggest/policyimpl/dictionary/patricia_trie_policy.h" +#include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h" #include "defines.h" #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_vector.h" -#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h" +#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" #include "suggest/policyimpl/dictionary/utils/probability_utils.h" namespace latinime { -void PatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode, +void PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const dicNode, DicNodeVector *const childDicNodes) const { if (!dicNode->hasChildren()) { return; } - int nextPos = dicNode->getChildrenPos(); + int nextPos = dicNode->getChildrenPtNodeArrayPos(); if (nextPos < 0 || nextPos >= mDictBufferSize) { AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %d", nextPos, mDictBufferSize); + mIsCorrupted = true; ASSERT(false); return; } @@ -43,6 +46,7 @@ void PatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode, if (nextPos < 0 || nextPos >= mDictBufferSize) { AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %d, childCount: %d / %d", nextPos, mDictBufferSize, i, childCount); + mIsCorrupted = true; ASSERT(false); return; } @@ -52,14 +56,14 @@ void PatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode, // This retrieves code points and the probability of the word by its terminal position. // Due to the fact that words are ordered in the dictionary in a strict breadth-first order, -// it is possible to check for this with advantageous complexity. For each node, we search +// it is possible to check for this with advantageous complexity. For each PtNode array, we search // for PtNodes with children and compare the children position with the position we look for. // When we shoot the position we look for, it means the word we look for is in the children // of the previous PtNode. The only tricky part is the fact that if we arrive at the end of a // PtNode array with the last PtNode's children position still less than what we are searching for, // we must descend the last PtNode's children (for example, if the word we are searching for starts // with a z, it's the last PtNode of the root array, so all children addresses will be smaller -// than the position we look for, and we have to descend the z node). +// than the position we look for, and we have to descend the z PtNode). /* Parameters : * ptNodePos: the byte position of the terminal PtNode of the word we are searching for (this is * what is stored as the "bigram position" in each bigram) @@ -74,18 +78,33 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( int pos = getRootPosition(); int wordPos = 0; // One iteration of the outer loop iterates through PtNode arrays. As stated above, we will - // only traverse nodes that are actually a part of the terminal we are searching, so each time - // we enter this loop we are one depth level further than last time. - // The only reason we count nodes is because we want to reduce the probability of infinite + // only traverse PtNodes that are actually a part of the terminal we are searching, so each + // time we enter this loop we are one depth level further than last time. + // The only reason we count PtNodes is because we want to reduce the probability of infinite // looping in case there is a bug. Since we know there is an upper bound to the depth we are // supposed to traverse, it does not hurt to count iterations. for (int loopCount = maxCodePointCount; loopCount > 0; --loopCount) { int lastCandidatePtNodePos = 0; // Let's loop through PtNodes in this PtNode array searching for either the terminal // or one of its ascendants. + if (pos < 0 || pos >= mDictBufferSize) { + AKLOGE("PtNode array position is invalid. pos: %d, dict size: %d", + pos, mDictBufferSize); + mIsCorrupted = true; + ASSERT(false); + *outUnigramProbability = NOT_A_PROBABILITY; + return 0; + } for (int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition( mDictRoot, &pos); ptNodeCount > 0; --ptNodeCount) { const int startPos = pos; + if (pos < 0 || pos >= mDictBufferSize) { + AKLOGE("PtNode position is invalid. pos: %d, dict size: %d", pos, mDictBufferSize); + mIsCorrupted = true; + ASSERT(false); + *outUnigramProbability = NOT_A_PROBABILITY; + return 0; + } const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); const int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition( @@ -140,8 +159,9 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( found = true; } else if (1 >= ptNodeCount) { // However if we are on the LAST PtNode of this array, and we have NOT shot the - // position we should descend THIS node. So we trick the lastCandidatePtNodePos - // so that we will descend this PtNode, not the previous one. + // position we should descend THIS PtNode. So we trick the + // lastCandidatePtNodePos so that we will descend this PtNode, not the previous + // one. lastCandidatePtNodePos = startPos; found = true; } else { @@ -149,7 +169,7 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( found = false; } } else { - // Even if we don't have children here, we could still be on the last PtNode of / + // Even if we don't have children here, we could still be on the last PtNode of // this array. If this is the case, we should descend the last PtNode that had // children, and their position is already in lastCandidatePtNodePos. found = (1 >= ptNodeCount); @@ -230,93 +250,19 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( return 0; } -// This function gets the position of the terminal node of the exact matching word in the +// This function gets the position of the terminal PtNode of the exact matching word in the // dictionary. If no match is found, it returns NOT_A_DICT_POS. -int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord, +int PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const int *const inWord, const int length, const bool forceLowerCaseSearch) const { - int pos = getRootPosition(); - int wordPos = 0; - - while (true) { - // If we already traversed the tree further than the word is long, there means - // there was no match (or we would have found it). - if (wordPos >= length) return NOT_A_DICT_POS; - int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(mDictRoot, - &pos); - const int wChar = forceLowerCaseSearch - ? CharUtils::toLowerCase(inWord[wordPos]) : inWord[wordPos]; - while (true) { - // If there are no more PtNodes in this array, it means we could not - // find a matching character for this depth, therefore there is no match. - if (0 >= ptNodeCount) return NOT_A_DICT_POS; - const int ptNodePos = pos; - const PatriciaTrieReadingUtils::NodeFlags flags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); - int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(mDictRoot, - &pos); - if (character == wChar) { - // This is the correct PtNode. Only one PtNode may start with the same char within - // a PtNode array, so either we found our match in this array, or there is - // no match and we can return NOT_A_DICT_POS. So we will check all the - // characters in this PtNode indeed does match. - if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) { - character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(mDictRoot, - &pos); - while (NOT_A_CODE_POINT != character) { - ++wordPos; - // If we shoot the length of the word we search for, or if we find a single - // character that does not match, as explained above, it means the word is - // not in the dictionary (by virtue of this PtNode being the only one to - // match the word on the first character, but not matching the whole word). - if (wordPos >= length) return NOT_A_DICT_POS; - if (inWord[wordPos] != character) return NOT_A_DICT_POS; - character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition( - mDictRoot, &pos); - } - } - // If we come here we know that so far, we do match. Either we are on a terminal - // and we match the length, in which case we found it, or we traverse children. - // If we don't match the length AND don't have children, then a word in the - // dictionary fully matches a prefix of the searched word but not the full word. - ++wordPos; - if (PatriciaTrieReadingUtils::isTerminal(flags)) { - if (wordPos == length) { - return ptNodePos; - } - PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos); - } - if (!PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) { - return NOT_A_DICT_POS; - } - // We have children and we are still shorter than the word we are searching for, so - // we need to traverse children. Put the pointer on the children position, and - // break - pos = PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, - flags, &pos); - break; - } else { - // This PtNode does not match, so skip the remaining part and go to the next. - if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) { - PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, - &pos); - } - if (PatriciaTrieReadingUtils::isTerminal(flags)) { - PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos); - } - if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) { - PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, - flags, &pos); - } - if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) { - mShortcutListPolicy.skipAllShortcuts(&pos); - } - if (PatriciaTrieReadingUtils::hasBigrams(flags)) { - mBigramListPolicy.skipAllBigrams(&pos); - } - } - --ptNodeCount; - } + DynamicPtReadingHelper readingHelper(&mPtNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + const int ptNodePos = + readingHelper.getTerminalPtNodePositionOfWord(inWord, length, forceLowerCaseSearch); + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); } + return ptNodePos; } int PatriciaTriePolicy::getProbability(const int unigramProbability, @@ -335,99 +281,137 @@ int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_PROBABILITY; } - int pos = ptNodePos; - const PatriciaTrieReadingUtils::NodeFlags flags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); - if (!PatriciaTrieReadingUtils::isTerminal(flags)) { - return NOT_A_PROBABILITY; - } - if (PatriciaTrieReadingUtils::isNotAWord(flags) - || PatriciaTrieReadingUtils::isBlacklisted(flags)) { + const PtNodeParams ptNodeParams = mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + if (ptNodeParams.isNotAWord() || ptNodeParams.isBlacklisted()) { // If this is not a word, or if it's a blacklisted entry, it should behave as // having no probability outside of the suggestion process (where it should be used // for shortcuts). return NOT_A_PROBABILITY; } - PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos); - return getProbability(PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition( - mDictRoot, &pos), NOT_A_PROBABILITY); + return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); } int PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const { if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - int pos = ptNodePos; - const PatriciaTrieReadingUtils::NodeFlags flags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); - if (!PatriciaTrieReadingUtils::hasShortcutTargets(flags)) { - return NOT_A_DICT_POS; - } - PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos); - if (PatriciaTrieReadingUtils::isTerminal(flags)) { - PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos); - } - if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) { - PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &pos); - } - return pos; + return mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos).getShortcutPos(); } int PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const { if (ptNodePos == NOT_A_DICT_POS) { return NOT_A_DICT_POS; } - int pos = ptNodePos; - const PatriciaTrieReadingUtils::NodeFlags flags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); - if (!PatriciaTrieReadingUtils::hasBigrams(flags)) { - return NOT_A_DICT_POS; - } - PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos); - if (PatriciaTrieReadingUtils::isTerminal(flags)) { - PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos); - } - if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) { - PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &pos); - } - if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) { - mShortcutListPolicy.skipAllShortcuts(&pos);; - } - return pos; + return mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos).getBigramsPos(); } int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNode, const int ptNodePos, DicNodeVector *childDicNodes) const { - int pos = ptNodePos; - const PatriciaTrieReadingUtils::NodeFlags flags = - PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos); + PatriciaTrieReadingUtils::NodeFlags flags; + int mergedNodeCodePointCount = 0; int mergedNodeCodePoints[MAX_WORD_LENGTH]; - const int mergedNodeCodePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition( - mDictRoot, flags, MAX_WORD_LENGTH, mergedNodeCodePoints, &pos); - const int probability = (PatriciaTrieReadingUtils::isTerminal(flags))? - PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos) - : NOT_A_PROBABILITY; - const int childrenPos = PatriciaTrieReadingUtils::hasChildrenInFlags(flags) ? - PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition( - mDictRoot, flags, &pos) : NOT_A_DICT_POS; - if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) { - getShortcutsStructurePolicy()->skipAllShortcuts(&pos); - } - if (PatriciaTrieReadingUtils::hasBigrams(flags)) { - getBigramsStructurePolicy()->skipAllBigrams(&pos); - } - if (mergedNodeCodePointCount <= 0) { - AKLOGE("Empty PtNode is not allowed. Code point count: %d", mergedNodeCodePointCount); - ASSERT(false); - return pos; - } + int probability = NOT_A_PROBABILITY; + int childrenPos = NOT_A_DICT_POS; + int shortcutPos = NOT_A_DICT_POS; + int bigramPos = NOT_A_DICT_POS; + int siblingPos = NOT_A_DICT_POS; + PatriciaTrieReadingUtils::readPtNodeInfo(mDictRoot, ptNodePos, getShortcutsStructurePolicy(), + getBigramsStructurePolicy(), &flags, &mergedNodeCodePointCount, mergedNodeCodePoints, + &probability, &childrenPos, &shortcutPos, &bigramPos, &siblingPos); childDicNodes->pushLeavingChild(dicNode, ptNodePos, childrenPos, probability, PatriciaTrieReadingUtils::isTerminal(flags), PatriciaTrieReadingUtils::hasChildrenInFlags(flags), - PatriciaTrieReadingUtils::isBlacklisted(flags) || - PatriciaTrieReadingUtils::isNotAWord(flags), + PatriciaTrieReadingUtils::isBlacklisted(flags) + || PatriciaTrieReadingUtils::isNotAWord(flags), mergedNodeCodePointCount, mergedNodeCodePoints); - return pos; + return siblingPos; +} + +const WordProperty PatriciaTriePolicy::getWordProperty(const int *const codePoints, + const int codePointCount) const { + const int ptNodePos = getTerminalPtNodePositionOfWord(codePoints, codePointCount, + false /* forceLowerCaseSearch */); + if (ptNodePos == NOT_A_DICT_POS) { + AKLOGE("getWordProperty was called for invalid word."); + return WordProperty(); + } + const PtNodeParams ptNodeParams = mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + std::vector<int> codePointVector(ptNodeParams.getCodePoints(), + ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); + // Fetch bigram information. + std::vector<BigramProperty> bigrams; + const int bigramListPos = getBigramsPositionOfPtNode(ptNodePos); + int bigramWord1CodePoints[MAX_WORD_LENGTH]; + BinaryDictionaryBigramsIterator bigramsIt(getBigramsStructurePolicy(), bigramListPos); + while (bigramsIt.hasNext()) { + // Fetch the next bigram information and forward the iterator. + bigramsIt.next(); + // Skip the entry if the entry has been deleted. This never happens for ver2 dicts. + if (bigramsIt.getBigramPos() != NOT_A_DICT_POS) { + int word1Probability = NOT_A_PROBABILITY; + const int word1CodePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + bigramsIt.getBigramPos(), MAX_WORD_LENGTH, bigramWord1CodePoints, + &word1Probability); + const std::vector<int> word1(bigramWord1CodePoints, + bigramWord1CodePoints + word1CodePointCount); + const int probability = getProbability(word1Probability, bigramsIt.getProbability()); + bigrams.emplace_back(&word1, probability, + NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */); + } + } + // Fetch shortcut information. + std::vector<UnigramProperty::ShortcutProperty> shortcuts; + int shortcutPos = getShortcutPositionOfPtNode(ptNodePos); + if (shortcutPos != NOT_A_DICT_POS) { + int shortcutTargetCodePoints[MAX_WORD_LENGTH]; + ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mDictRoot, &shortcutPos); + bool hasNext = true; + while (hasNext) { + const ShortcutListReadingUtils::ShortcutFlags shortcutFlags = + ShortcutListReadingUtils::getFlagsAndForwardPointer(mDictRoot, &shortcutPos); + hasNext = ShortcutListReadingUtils::hasNext(shortcutFlags); + const int shortcutTargetLength = ShortcutListReadingUtils::readShortcutTarget( + mDictRoot, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos); + const std::vector<int> shortcutTarget(shortcutTargetCodePoints, + shortcutTargetCodePoints + shortcutTargetLength); + const int shortcutProbability = + ShortcutListReadingUtils::getProbabilityFromFlags(shortcutFlags); + shortcuts.emplace_back(&shortcutTarget, shortcutProbability); + } + } + const UnigramProperty unigramProperty(ptNodeParams.isNotAWord(), + ptNodeParams.isBlacklisted(), ptNodeParams.getProbability(), + NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */, &shortcuts); + return WordProperty(&codePointVector, &unigramProperty, &bigrams); +} + +int PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { + if (token == 0) { + // Start iterating the dictionary. + mTerminalPtNodePositionsForIteratingWords.clear(); + DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions traversePolicy( + &mTerminalPtNodePositionsForIteratingWords); + DynamicPtReadingHelper readingHelper(&mPtNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + readingHelper.traverseAllPtNodesInPostorderDepthFirstManner(&traversePolicy); + } + const int terminalPtNodePositionsVectorSize = + static_cast<int>(mTerminalPtNodePositionsForIteratingWords.size()); + if (token < 0 || token >= terminalPtNodePositionsVectorSize) { + AKLOGE("Given token %d is invalid.", token); + return 0; + } + const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; + int unigramProbability = NOT_A_PROBABILITY; + getCodePointsAndProbabilityAndReturnCodePointCount(terminalPtNodePos, MAX_WORD_LENGTH, + outCodePoints, &unigramProbability); + const int nextToken = token + 1; + if (nextToken >= terminalPtNodePositionsVectorSize) { + // All words have been iterated. + mTerminalPtNodePositionsForIteratingWords.clear(); + return 0; + } + return nextToken; } } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h index 0f8662aea..85f46603e 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h @@ -17,13 +17,17 @@ #ifndef LATINIME_PATRICIA_TRIE_POLICY_H #define LATINIME_PATRICIA_TRIE_POLICY_H -#include <stdint.h> +#include <cstdint> +#include <vector> #include "defines.h" #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" #include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h" #include "suggest/policyimpl/dictionary/header/header_policy.h" #include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h" +#include "suggest/policyimpl/dictionary/utils/format_utils.h" #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" namespace latinime { @@ -33,28 +37,28 @@ class DicNodeVector; class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { public: - PatriciaTriePolicy(const MmappedBuffer *const buffer) - : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), buffer->getBufferSize()), - mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()), - mDictBufferSize(mBuffer->getBufferSize() - mHeaderPolicy.getSize()), - mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {} - - ~PatriciaTriePolicy() { - delete mBuffer; - } + PatriciaTriePolicy(MmappedBuffer::MmappedBufferPtr mmappedBuffer) + : mMmappedBuffer(std::move(mmappedBuffer)), + mHeaderPolicy(mMmappedBuffer->getBuffer(), FormatUtils::VERSION_2), + mDictRoot(mMmappedBuffer->getBuffer() + mHeaderPolicy.getSize()), + mDictBufferSize(mMmappedBuffer->getBufferSize() - mHeaderPolicy.getSize()), + mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot), + mPtNodeReader(mDictRoot, mDictBufferSize, &mBigramListPolicy, &mShortcutListPolicy), + mPtNodeArrayReader(mDictRoot, mDictBufferSize), + mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {} AK_FORCE_INLINE int getRootPosition() const { return 0; } - void createAndGetAllChildNodes(const DicNode *const dicNode, + void createAndGetAllChildDicNodes(const DicNode *const dicNode, DicNodeVector *const childDicNodes) const; int getCodePointsAndProbabilityAndReturnCodePointCount( const int terminalNodePos, const int maxCodePointCount, int *const outCodePoints, int *const outUnigramProbability) const; - int getTerminalNodePositionOfWord(const int *const inWord, + int getTerminalPtNodePositionOfWord(const int *const inWord, const int length, const bool forceLowerCaseSearch) const; int getProbability(const int unigramProbability, const int bigramProbability) const; @@ -77,14 +81,15 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { return &mShortcutListPolicy; } - bool addUnigramWord(const int *const word, const int length, const int probability) { + bool addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty) { // This method should not be called for non-updatable dictionary. AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary."); return false; } bool addBigramWords(const int *const word0, const int length0, const int *const word1, - const int length1, const int probability) { + const int length1, const int probability, const int timestamp) { // This method should not be called for non-updatable dictionary. AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); return false; @@ -113,7 +118,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { return false; } - void getProperty(const char *const query, char *const outResult, + void getProperty(const char *const query, const int queryLength, char *const outResult, const int maxResultLength) { // getProperty is not supported for this class. if (maxResultLength > 0) { @@ -121,15 +126,28 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { } } + const WordProperty getWordProperty(const int *const codePoints, + const int codePointCount) const; + + int getNextWordAndNextToken(const int token, int *const outCodePoints); + + bool isCorrupted() const { + return mIsCorrupted; + } + private: DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy); - const MmappedBuffer *const mBuffer; + const MmappedBuffer::MmappedBufferPtr mMmappedBuffer; const HeaderPolicy mHeaderPolicy; const uint8_t *const mDictRoot; const int mDictBufferSize; const BigramListPolicy mBigramListPolicy; const ShortcutListPolicy mShortcutListPolicy; + const Ver2ParticiaTrieNodeReader mPtNodeReader; + const Ver2PtNodeArrayReader mPtNodeArrayReader; + std::vector<int> mTerminalPtNodePositionsForIteratingWords; + mutable bool mIsCorrupted; int createAndGetLeavingChildNode(const DicNode *const dicNode, const int ptNodePos, DicNodeVector *const childDicNodes) const; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp new file mode 100644 index 000000000..0c8de0df2 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" + +namespace latinime { + +const PtNodeParams Ver2ParticiaTrieNodeReader::fetchNodeInfoInBufferFromPtNodePos( + const int ptNodePos) const { + if (ptNodePos < 0 || ptNodePos >= mDictSize) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d", + ptNodePos, mDictSize); + ASSERT(false); + return PtNodeParams(); + } + PatriciaTrieReadingUtils::NodeFlags flags; + int mergedNodeCodePointCount = 0; + int mergedNodeCodePoints[MAX_WORD_LENGTH]; + int probability = NOT_A_PROBABILITY; + int childrenPos = NOT_A_DICT_POS; + int shortcutPos = NOT_A_DICT_POS; + int bigramPos = NOT_A_DICT_POS; + int siblingPos = NOT_A_DICT_POS; + PatriciaTrieReadingUtils::readPtNodeInfo(mDictBuffer, ptNodePos, mShortuctPolicy, + mBigramPolicy, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints, &probability, + &childrenPos, &shortcutPos, &bigramPos, &siblingPos); + if (mergedNodeCodePointCount <= 0) { + AKLOGE("Empty PtNode is not allowed. Code point count: %d", mergedNodeCodePointCount); + ASSERT(false); + return PtNodeParams(); + } + return PtNodeParams(ptNodePos, flags, mergedNodeCodePointCount, mergedNodeCodePoints, + probability, childrenPos, shortcutPos, bigramPos, siblingPos); +} + +} diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h new file mode 100644 index 000000000..86fc89c5e --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014, 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_VER2_PATRICIA_TRIE_NODE_READER_H +#define LATINIME_VER2_PATRICIA_TRIE_NODE_READER_H + +#include <cstdint> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h" + +namespace latinime { + +class DictionaryBigramsStructurePolicy; +class DictionaryShortcutsStructurePolicy; + +class Ver2ParticiaTrieNodeReader : public PtNodeReader { + public: + Ver2ParticiaTrieNodeReader(const uint8_t *const dictBuffer, const int dictSize, + const DictionaryBigramsStructurePolicy *const bigramPolicy, + const DictionaryShortcutsStructurePolicy *const shortcutPolicy) + : mDictBuffer(dictBuffer), mDictSize(dictSize), mBigramPolicy(bigramPolicy), + mShortuctPolicy(shortcutPolicy) {} + + virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver2ParticiaTrieNodeReader); + + const uint8_t *const mDictBuffer; + const int mDictSize; + const DictionaryBigramsStructurePolicy *const mBigramPolicy; + const DictionaryShortcutsStructurePolicy *const mShortuctPolicy; +}; +} // namespace latinime +#endif /* LATINIME_VER2_PATRICIA_TRIE_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp new file mode 100644 index 000000000..b46617d96 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" + +namespace latinime { + +bool Ver2PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const { + if (ptNodeArrayPos < 0 || ptNodeArrayPos >= mDictSize) { + // Reading invalid position because of a bug or a broken dictionary. + AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d", + ptNodeArrayPos, mDictSize); + ASSERT(false); + return false; + } + int readingPos = ptNodeArrayPos; + const int ptNodeCountInArray = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition( + mDictBuffer, &readingPos); + *outPtNodeCount = ptNodeCountInArray; + *outFirstPtNodePos = readingPos; + return true; +} + +bool Ver2PtNodeArrayReader::readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const { + if (forwordLinkPos < 0 || forwordLinkPos >= mDictSize) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d", + forwordLinkPos, mDictSize); + ASSERT(false); + return false; + } + // Ver2 dicts don't have forward links. + *outNextPtNodeArrayPos = NOT_A_DICT_POS; + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h new file mode 100644 index 000000000..548272148 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014, 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_VER2_PT_NODE_ARRAY_READER_H +#define LATINIME_VER2_PT_NODE_ARRAY_READER_H + +#include <cstdint> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h" + +namespace latinime { + +class Ver2PtNodeArrayReader : public PtNodeArrayReader { + public: + Ver2PtNodeArrayReader(const uint8_t *const dictBuffer, const int dictSize) + : mDictBuffer(dictBuffer), mDictSize(dictSize) {}; + + virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const; + virtual bool readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Ver2PtNodeArrayReader); + + const uint8_t *const mDictBuffer; + const int mDictSize; +}; +} // namespace latinime +#endif /* LATINIME_VER2_PT_NODE_ARRAY_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp new file mode 100644 index 000000000..279f5b33a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h" + +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +const BigramEntry BigramDictContent::getBigramEntryAndAdvancePosition( + int *const bigramEntryPos) const { + const BufferWithExtendableBuffer *const bigramListBuffer = getContentBuffer(); + if (*bigramEntryPos < 0 || *bigramEntryPos >= bigramListBuffer->getTailPosition()) { + AKLOGE("Invalid bigram entry position. bigramEntryPos: %d, bufSize: %d", + *bigramEntryPos, bigramListBuffer->getTailPosition()); + ASSERT(false); + return BigramEntry(false /* hasNext */, NOT_A_PROBABILITY, + Ver4DictConstants::NOT_A_TERMINAL_ID); + } + const int bigramFlags = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE, bigramEntryPos); + const bool hasNext = (bigramFlags & Ver4DictConstants::BIGRAM_HAS_NEXT_MASK) != 0; + int probability = NOT_A_PROBABILITY; + int timestamp = NOT_A_TIMESTAMP; + int level = 0; + int count = 0; + if (mHasHistoricalInfo) { + probability = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::PROBABILITY_SIZE, bigramEntryPos); + timestamp = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, bigramEntryPos); + level = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, bigramEntryPos); + count = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, bigramEntryPos); + } else { + probability = bigramFlags & Ver4DictConstants::BIGRAM_PROBABILITY_MASK; + } + const int encodedTargetTerminalId = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE, bigramEntryPos); + const int targetTerminalId = + (encodedTargetTerminalId == Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID) ? + Ver4DictConstants::NOT_A_TERMINAL_ID : encodedTargetTerminalId; + if (mHasHistoricalInfo) { + const HistoricalInfo historicalInfo(timestamp, level, count); + return BigramEntry(hasNext, probability, &historicalInfo, targetTerminalId); + } else { + return BigramEntry(hasNext, probability, targetTerminalId); + } +} + +bool BigramDictContent::writeBigramEntryAndAdvancePosition( + const BigramEntry *const bigramEntryToWrite, int *const entryWritingPos) { + BufferWithExtendableBuffer *const bigramListBuffer = getWritableContentBuffer(); + const int bigramFlags = createAndGetBigramFlags( + mHasHistoricalInfo ? 0 : bigramEntryToWrite->getProbability(), + bigramEntryToWrite->hasNext()); + if (!bigramListBuffer->writeUintAndAdvancePosition(bigramFlags, + Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram flags. pos: %d, flags: %x", *entryWritingPos, bigramFlags); + return false; + } + if (mHasHistoricalInfo) { + if (!bigramListBuffer->writeUintAndAdvancePosition(bigramEntryToWrite->getProbability(), + Ver4DictConstants::PROBABILITY_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram probability. pos: %d, probability: %d", *entryWritingPos, + bigramEntryToWrite->getProbability()); + return false; + } + const HistoricalInfo *const historicalInfo = bigramEntryToWrite->getHistoricalInfo(); + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(), + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram timestamps. pos: %d, timestamp: %d", *entryWritingPos, + historicalInfo->getTimeStamp()); + return false; + } + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getLevel(), + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram level. pos: %d, level: %d", *entryWritingPos, + historicalInfo->getLevel()); + return false; + } + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getCount(), + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram count. pos: %d, count: %d", *entryWritingPos, + historicalInfo->getCount()); + return false; + } + } + const int targetTerminalIdToWrite = + (bigramEntryToWrite->getTargetTerminalId() == Ver4DictConstants::NOT_A_TERMINAL_ID) ? + Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID : + bigramEntryToWrite->getTargetTerminalId(); + if (!bigramListBuffer->writeUintAndAdvancePosition(targetTerminalIdToWrite, + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram target terminal id. pos: %d, target terminal id: %d", + *entryWritingPos, bigramEntryToWrite->getTargetTerminalId()); + return false; + } + return true; +} + +bool BigramDictContent::copyBigramList(const int bigramListPos, const int toPos) { + int readingPos = bigramListPos; + int writingPos = toPos; + bool hasNext = true; + while (hasNext) { + const BigramEntry bigramEntry = getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!writeBigramEntryAndAdvancePosition(&bigramEntry, &writingPos)) { + AKLOGE("Cannot write bigram entry to copy. pos: %d", writingPos); + return false; + } + } + return true; +} + +bool BigramDictContent::runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const BigramDictContent *const originalBigramDictContent, + int *const outBigramEntryCount) { + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const int originalBigramListPos = + originalBigramDictContent->getBigramListHeadPos(it->first); + if (originalBigramListPos == NOT_A_DICT_POS) { + // This terminal does not have a bigram list. + continue; + } + const int bigramListPos = getContentBuffer()->getTailPosition(); + int bigramEntryCount = 0; + // Copy bigram list with GC from original content. + if (!runGCBigramList(originalBigramListPos, originalBigramDictContent, bigramListPos, + terminalIdMap, &bigramEntryCount)) { + AKLOGE("Cannot complete GC for the bigram list. original pos: %d, pos: %d", + originalBigramListPos, bigramListPos); + return false; + } + if (bigramEntryCount == 0) { + // All bigram entries are useless. This terminal does not have a bigram list. + continue; + } + *outBigramEntryCount += bigramEntryCount; + // Set bigram list position to the lookup table. + if (!getUpdatableAddressLookupTable()->set(it->second, bigramListPos)) { + AKLOGE("Cannot set bigram list position. terminal id: %d, pos: %d", + it->second, bigramListPos); + return false; + } + } + return true; +} + +// Returns whether GC for the bigram list was succeeded or not. +bool BigramDictContent::runGCBigramList(const int bigramListPos, + const BigramDictContent *const sourceBigramDictContent, const int toPos, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + int *const outEntrycount) { + bool hasNext = true; + int readingPos = bigramListPos; + int writingPos = toPos; + int lastEntryPos = NOT_A_DICT_POS; + while (hasNext) { + const BigramEntry originalBigramEntry = + sourceBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = originalBigramEntry.hasNext(); + if (originalBigramEntry.getTargetTerminalId() == Ver4DictConstants::NOT_A_TERMINAL_ID) { + continue; + } + TerminalPositionLookupTable::TerminalIdMap::const_iterator it = + terminalIdMap->find(originalBigramEntry.getTargetTerminalId()); + if (it == terminalIdMap->end()) { + // Target word has been removed. + continue; + } + lastEntryPos = hasNext ? writingPos : NOT_A_DICT_POS; + const BigramEntry updatedBigramEntry = + originalBigramEntry.updateTargetTerminalIdAndGetEntry(it->second); + if (!writeBigramEntryAndAdvancePosition(&updatedBigramEntry, &writingPos)) { + AKLOGE("Cannot write bigram entry to run GC. pos: %d", writingPos); + return false; + } + *outEntrycount += 1; + } + if (lastEntryPos != NOT_A_DICT_POS) { + // Update has next flag in the last written entry. + const BigramEntry bigramEntry = getBigramEntry(lastEntryPos).updateHasNextAndGetEntry( + false /* hasNext */); + if (!writeBigramEntry(&bigramEntry, lastEntryPos)) { + AKLOGE("Cannot write bigram entry to set hasNext flag after GC. pos: %d", writingPos); + return false; + } + } + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h new file mode 100644 index 000000000..ba2a05209 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013, 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_BIGRAM_DICT_CONTENT_H +#define LATINIME_BIGRAM_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" + +namespace latinime { + +class BigramDictContent : public SparseTableDictContent { + public: + BigramDictContent(const char *const dictPath, const bool hasHistoricalInfo, + const bool isUpdatable) + : SparseTableDictContent(dictPath, + Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_FILE_EXTENSION, isUpdatable, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE), + mHasHistoricalInfo(hasHistoricalInfo) {} + + BigramDictContent(const bool hasHistoricalInfo) + : SparseTableDictContent(Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE), + mHasHistoricalInfo(hasHistoricalInfo) {} + + const BigramEntry getBigramEntry(const int bigramEntryPos) const { + int readingPos = bigramEntryPos; + return getBigramEntryAndAdvancePosition(&readingPos); + } + + const BigramEntry getBigramEntryAndAdvancePosition(int *const bigramEntryPos) const; + + // Returns head position of bigram list for a PtNode specified by terminalId. + int getBigramListHeadPos(const int terminalId) const { + const SparseTable *const addressLookupTable = getAddressLookupTable(); + if (!addressLookupTable->contains(terminalId)) { + return NOT_A_DICT_POS; + } + return addressLookupTable->get(terminalId); + } + + bool writeBigramEntry(const BigramEntry *const bigramEntryToWrite, const int entryWritingPos) { + int writingPos = entryWritingPos; + return writeBigramEntryAndAdvancePosition(bigramEntryToWrite, &writingPos); + } + + bool writeBigramEntryAndAdvancePosition(const BigramEntry *const bigramEntryToWrite, + int *const entryWritingPos); + + bool createNewBigramList(const int terminalId) { + const int bigramListPos = getContentBuffer()->getTailPosition(); + return getUpdatableAddressLookupTable()->set(terminalId, bigramListPos); + } + + bool copyBigramList(const int bigramListPos, const int toPos); + + bool flushToFile(const char *const dictPath) const { + return flush(dictPath, Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_FILE_EXTENSION); + } + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const BigramDictContent *const originalBigramDictContent, + int *const outBigramEntryCount); + + private: + DISALLOW_COPY_AND_ASSIGN(BigramDictContent); + + int createAndGetBigramFlags(const int probability, const bool hasNext) const { + return (probability & Ver4DictConstants::BIGRAM_PROBABILITY_MASK) + | (hasNext ? Ver4DictConstants::BIGRAM_HAS_NEXT_MASK : 0); + } + + bool runGCBigramList(const int bigramListPos, + const BigramDictContent *const sourceBigramDictContent, const int toPos, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + int *const outEntryCount); + + bool mHasHistoricalInfo; +}; +} // namespace latinime +#endif /* LATINIME_BIGRAM_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h new file mode 100644 index 000000000..2b0cbd93b --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013, 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_BIGRAM_ENTRY_H +#define LATINIME_BIGRAM_ENTRY_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/historical_info.h" + +namespace latinime { + +class BigramEntry { + public: + BigramEntry(const BigramEntry& bigramEntry) + : mHasNext(bigramEntry.mHasNext), mProbability(bigramEntry.mProbability), + mHistoricalInfo(), mTargetTerminalId(bigramEntry.mTargetTerminalId) {} + + // Entry with historical information. + BigramEntry(const bool hasNext, const int probability, const int targetTerminalId) + : mHasNext(hasNext), mProbability(probability), mHistoricalInfo(), + mTargetTerminalId(targetTerminalId) {} + + // Entry with historical information. + BigramEntry(const bool hasNext, const int probability, + const HistoricalInfo *const historicalInfo, const int targetTerminalId) + : mHasNext(hasNext), mProbability(probability), mHistoricalInfo(*historicalInfo), + mTargetTerminalId(targetTerminalId) {} + + const BigramEntry getInvalidatedEntry() const { + return updateTargetTerminalIdAndGetEntry(Ver4DictConstants::NOT_A_TERMINAL_ID); + } + + const BigramEntry updateHasNextAndGetEntry(const bool hasNext) const { + return BigramEntry(hasNext, mProbability, &mHistoricalInfo, mTargetTerminalId); + } + + const BigramEntry updateTargetTerminalIdAndGetEntry(const int newTargetTerminalId) const { + return BigramEntry(mHasNext, mProbability, &mHistoricalInfo, newTargetTerminalId); + } + + const BigramEntry updateProbabilityAndGetEntry(const int probability) const { + return BigramEntry(mHasNext, probability, &mHistoricalInfo, mTargetTerminalId); + } + + const BigramEntry updateHistoricalInfoAndGetEntry( + const HistoricalInfo *const historicalInfo) const { + return BigramEntry(mHasNext, mProbability, historicalInfo, mTargetTerminalId); + } + + bool isValid() const { + return mTargetTerminalId != Ver4DictConstants::NOT_A_TERMINAL_ID; + } + + bool hasNext() const { + return mHasNext; + } + + int getProbability() const { + return mProbability; + } + + bool hasHistoricalInfo() const { + return mHistoricalInfo.isValid(); + } + + const HistoricalInfo *getHistoricalInfo() const { + return &mHistoricalInfo; + } + + int getTargetTerminalId() const { + return mTargetTerminalId; + } + + private: + // Copy constructor is public to use this class as a type of return value. + DISALLOW_DEFAULT_CONSTRUCTOR(BigramEntry); + DISALLOW_ASSIGNMENT_OPERATOR(BigramEntry); + + const bool mHasNext; + const int mProbability; + const HistoricalInfo mHistoricalInfo; + const int mTargetTerminalId; +}; +} // namespace latinime +#endif /* LATINIME_BIGRAM_ENTRY_H */ diff --git a/native/jni/src/suggest/core/dictionary/bloom_filter.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/dict_content.h index 4ae474e0c..0c2f47073 100644 --- a/native/jni/src/suggest/core/dictionary/bloom_filter.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/dict_content.h @@ -14,12 +14,23 @@ * limitations under the License. */ -#include "suggest/core/dictionary/bloom_filter.h" +#ifndef LATINIME_DICT_CONTENT_H +#define LATINIME_DICT_CONTENT_H + +#include "defines.h" namespace latinime { -// Must be smaller than BIGRAM_FILTER_BYTE_SIZE * 8, and preferably prime. 1021 is the largest -// prime under 128 * 8. -const int BloomFilter::BIGRAM_FILTER_MODULO = 1021; +class DictContent { + public: + virtual ~DictContent() {} + virtual bool isValid() const = 0; + + protected: + DictContent() {} + private: + DISALLOW_COPY_AND_ASSIGN(DictContent); +}; } // namespace latinime +#endif /* LATINIME_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp new file mode 100644 index 000000000..3b7c70efd --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h" + +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +const ProbabilityEntry ProbabilityDictContent::getProbabilityEntry(const int terminalId) const { + if (terminalId < 0 || terminalId >= mSize) { + // This method can be called with invalid terminal id during GC. + return ProbabilityEntry(0 /* flags */, NOT_A_PROBABILITY); + } + const BufferWithExtendableBuffer *const buffer = getBuffer(); + int entryPos = getEntryPos(terminalId); + const int flags = buffer->readUintAndAdvancePosition( + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &entryPos); + const int probability = buffer->readUintAndAdvancePosition( + Ver4DictConstants::PROBABILITY_SIZE, &entryPos); + if (mHasHistoricalInfo) { + const int timestamp = buffer->readUintAndAdvancePosition( + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &entryPos); + const int level = buffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &entryPos); + const int count = buffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &entryPos); + const HistoricalInfo historicalInfo(timestamp, level, count); + return ProbabilityEntry(flags, probability, &historicalInfo); + } else { + return ProbabilityEntry(flags, probability); + } +} + +bool ProbabilityDictContent::setProbabilityEntry(const int terminalId, + const ProbabilityEntry *const probabilityEntry) { + if (terminalId < 0) { + return false; + } + const int entryPos = getEntryPos(terminalId); + if (terminalId >= mSize) { + ProbabilityEntry dummyEntry; + // Write new entry. + int writingPos = getBuffer()->getTailPosition(); + while (writingPos <= entryPos) { + // Fulfilling with dummy entries until writingPos. + if (!writeEntry(&dummyEntry, writingPos)) { + AKLOGE("Cannot write dummy entry. pos: %d, mSize: %d", writingPos, mSize); + return false; + } + writingPos += getEntrySize(); + mSize++; + } + } + return writeEntry(probabilityEntry, entryPos); +} + +bool ProbabilityDictContent::flushToFile(const char *const dictPath) const { + if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { + ProbabilityDictContent probabilityDictContentToWrite(mHasHistoricalInfo); + for (int i = 0; i < mSize; ++i) { + const ProbabilityEntry probabilityEntry = getProbabilityEntry(i); + if (!probabilityDictContentToWrite.setProbabilityEntry(i, &probabilityEntry)) { + AKLOGE("Cannot set probability entry in flushToFile. terminalId: %d", i); + return false; + } + } + return probabilityDictContentToWrite.flush(dictPath, + Ver4DictConstants::FREQ_FILE_EXTENSION); + } else { + return flush(dictPath, Ver4DictConstants::FREQ_FILE_EXTENSION); + } +} + +bool ProbabilityDictContent::runGC( + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ProbabilityDictContent *const originalProbabilityDictContent) { + mSize = 0; + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const ProbabilityEntry probabilityEntry = + originalProbabilityDictContent->getProbabilityEntry(it->first); + if (!setProbabilityEntry(it->second, &probabilityEntry)) { + AKLOGE("Cannot set probability entry in runGC. terminalId: %d", it->second); + return false; + } + mSize++; + } + return true; +} + +int ProbabilityDictContent::getEntrySize() const { + if (mHasHistoricalInfo) { + return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE + + Ver4DictConstants::PROBABILITY_SIZE + + Ver4DictConstants::TIME_STAMP_FIELD_SIZE + + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE + + Ver4DictConstants::WORD_COUNT_FIELD_SIZE; + } else { + return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE + + Ver4DictConstants::PROBABILITY_SIZE; + } +} + +int ProbabilityDictContent::getEntryPos(const int terminalId) const { + return terminalId * getEntrySize(); +} + +bool ProbabilityDictContent::writeEntry(const ProbabilityEntry *const probabilityEntry, + const int entryPos) { + BufferWithExtendableBuffer *const bufferToWrite = getWritableBuffer(); + int writingPos = entryPos; + if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getFlags(), + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &writingPos)) { + AKLOGE("Cannot write flags in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getProbability(), + Ver4DictConstants::PROBABILITY_SIZE, &writingPos)) { + AKLOGE("Cannot write probability in probability dict content. pos: %d", writingPos); + return false; + } + if (mHasHistoricalInfo) { + const HistoricalInfo *const historicalInfo = probabilityEntry->getHistoricalInfo(); + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(), + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write timestamp in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getLevel(), + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write level in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getCount(), + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write count in probability dict content. pos: %d", writingPos); + return false; + } + } + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h new file mode 100644 index 000000000..b065bc954 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013, 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_PROBABILITY_DICT_CONTENT_H +#define LATINIME_PROBABILITY_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +class ProbabilityEntry; + +class ProbabilityDictContent : public SingleDictContent { + public: + ProbabilityDictContent(const char *const dictPath, const bool hasHistoricalInfo, + const bool isUpdatable) + : SingleDictContent(dictPath, Ver4DictConstants::FREQ_FILE_EXTENSION, isUpdatable), + mHasHistoricalInfo(hasHistoricalInfo), + mSize(getBuffer()->getTailPosition() / getEntrySize()) {} + + ProbabilityDictContent(const bool hasHistoricalInfo) + : mHasHistoricalInfo(hasHistoricalInfo), mSize(0) {} + + const ProbabilityEntry getProbabilityEntry(const int terminalId) const; + + bool setProbabilityEntry(const int terminalId, const ProbabilityEntry *const probabilityEntry); + + bool flushToFile(const char *const dictPath) const; + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ProbabilityDictContent *const originalProbabilityDictContent); + + private: + DISALLOW_COPY_AND_ASSIGN(ProbabilityDictContent); + + int getEntrySize() const; + + int getEntryPos(const int terminalId) const; + + bool writeEntry(const ProbabilityEntry *const probabilityEntry, const int entryPos); + + bool mHasHistoricalInfo; + int mSize; +}; +} // namespace latinime +#endif /* LATINIME_PROBABILITY_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h new file mode 100644 index 000000000..36ba82be1 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013, 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_PROBABILITY_ENTRY_H +#define LATINIME_PROBABILITY_ENTRY_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/historical_info.h" + +namespace latinime { + +class ProbabilityEntry { + public: + ProbabilityEntry(const ProbabilityEntry &probabilityEntry) + : mFlags(probabilityEntry.mFlags), mProbability(probabilityEntry.mProbability), + mHistoricalInfo(probabilityEntry.mHistoricalInfo) {} + + // Dummy entry + ProbabilityEntry() + : mFlags(0), mProbability(NOT_A_PROBABILITY), mHistoricalInfo() {} + + // Entry without historical information + ProbabilityEntry(const int flags, const int probability) + : mFlags(flags), mProbability(probability), mHistoricalInfo() {} + + // Entry with historical information. + ProbabilityEntry(const int flags, const int probability, + const HistoricalInfo *const historicalInfo) + : mFlags(flags), mProbability(probability), mHistoricalInfo(*historicalInfo) {} + + const ProbabilityEntry createEntryWithUpdatedProbability(const int probability) const { + return ProbabilityEntry(mFlags, probability, &mHistoricalInfo); + } + + const ProbabilityEntry createEntryWithUpdatedHistoricalInfo( + const HistoricalInfo *const historicalInfo) const { + return ProbabilityEntry(mFlags, mProbability, historicalInfo); + } + + bool hasHistoricalInfo() const { + return mHistoricalInfo.isValid(); + } + + int getFlags() const { + return mFlags; + } + + int getProbability() const { + return mProbability; + } + + const HistoricalInfo *getHistoricalInfo() const { + return &mHistoricalInfo; + } + + private: + // Copy constructor is public to use this class as a type of return value. + DISALLOW_ASSIGNMENT_OPERATOR(ProbabilityEntry); + + const int mFlags; + const int mProbability; + const HistoricalInfo mHistoricalInfo; +}; +} // namespace latinime +#endif /* LATINIME_PROBABILITY_ENTRY_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp new file mode 100644 index 000000000..64d7bc0a5 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h" + +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +void ShortcutDictContent::getShortcutEntryAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoint, int *const outCodePointCount, int *const outProbability, + bool *const outhasNext, int *const shortcutEntryPos) const { + const BufferWithExtendableBuffer *const shortcutListBuffer = getContentBuffer(); + if (*shortcutEntryPos < 0 || *shortcutEntryPos >= shortcutListBuffer->getTailPosition()) { + AKLOGE("Invalid shortcut entry position. shortcutEntryPos: %d, bufSize: %d", + *shortcutEntryPos, shortcutListBuffer->getTailPosition()); + ASSERT(false); + if (outhasNext) { + *outhasNext = false; + } + if (outCodePointCount) { + *outCodePointCount = 0; + } + return; + } + + const int shortcutFlags = shortcutListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); + if (outProbability) { + *outProbability = shortcutFlags & Ver4DictConstants::SHORTCUT_PROBABILITY_MASK; + } + if (outhasNext) { + *outhasNext = shortcutFlags & Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK; + } + if (outCodePoint && outCodePointCount) { + shortcutListBuffer->readCodePointsAndAdvancePosition( + maxCodePointCount, outCodePoint, outCodePointCount, shortcutEntryPos); + } +} + +int ShortcutDictContent::getShortcutListHeadPos(const int terminalId) const { + const SparseTable *const addressLookupTable = getAddressLookupTable(); + if (!addressLookupTable->contains(terminalId)) { + return NOT_A_DICT_POS; + } + return addressLookupTable->get(terminalId); +} + +bool ShortcutDictContent::flushToFile(const char *const dictPath) const { + return flush(dictPath, Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_FILE_EXTENSION); +} + +bool ShortcutDictContent::runGC( + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ShortcutDictContent *const originalShortcutDictContent) { + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const int originalShortcutListPos = + originalShortcutDictContent->getShortcutListHeadPos(it->first); + if (originalShortcutListPos == NOT_A_DICT_POS) { + continue; + } + const int shortcutListPos = getContentBuffer()->getTailPosition(); + // Copy shortcut list from original content. + if (!copyShortcutListFromDictContent(originalShortcutListPos, originalShortcutDictContent, + shortcutListPos)) { + AKLOGE("Cannot copy shortcut list during GC. original pos: %d, pos: %d", + originalShortcutListPos, shortcutListPos); + return false; + } + // Set shortcut list position to the lookup table. + if (!getUpdatableAddressLookupTable()->set(it->second, shortcutListPos)) { + AKLOGE("Cannot set shortcut list position. terminal id: %d, pos: %d", + it->second, shortcutListPos); + return false; + } + } + return true; +} + +bool ShortcutDictContent::createNewShortcutList(const int terminalId) { + const int shortcutListListPos = getContentBuffer()->getTailPosition(); + return getUpdatableAddressLookupTable()->set(terminalId, shortcutListListPos); +} + +bool ShortcutDictContent::copyShortcutList(const int shortcutListPos, const int toPos) { + return copyShortcutListFromDictContent(shortcutListPos, this, toPos); +} + +bool ShortcutDictContent::copyShortcutListFromDictContent(const int shortcutListPos, + const ShortcutDictContent *const sourceShortcutDictContent, const int toPos) { + bool hasNext = true; + int readingPos = shortcutListPos; + int writingPos = toPos; + int codePoints[MAX_WORD_LENGTH]; + while (hasNext) { + int probability = 0; + int codePointCount = 0; + sourceShortcutDictContent->getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, + codePoints, &codePointCount, &probability, &hasNext, &readingPos); + if (!writeShortcutEntryAndAdvancePosition(codePoints, codePointCount, probability, + hasNext, &writingPos)) { + AKLOGE("Cannot write shortcut entry to copy. pos: %d", writingPos); + return false; + } + } + return true; +} + +bool ShortcutDictContent::setProbability(const int probability, const int shortcutEntryPos) { + BufferWithExtendableBuffer *const shortcutListBuffer = getWritableContentBuffer(); + const int shortcutFlags = shortcutListBuffer->readUint( + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); + const bool hasNext = shortcutFlags & Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK; + const int shortcutFlagsToWrite = createAndGetShortcutFlags(probability, hasNext); + return shortcutListBuffer->writeUint(shortcutFlagsToWrite, + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); +} + +bool ShortcutDictContent::writeShortcutEntryAndAdvancePosition(const int *const codePoint, + const int codePointCount, const int probability, const bool hasNext, + int *const shortcutEntryPos) { + BufferWithExtendableBuffer *const shortcutListBuffer = getWritableContentBuffer(); + const int shortcutFlags = createAndGetShortcutFlags(probability, hasNext); + if (!shortcutListBuffer->writeUintAndAdvancePosition(shortcutFlags, + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos)) { + AKLOGE("Cannot write shortcut flags. flags; %x, pos: %d", shortcutFlags, *shortcutEntryPos); + return false; + } + if (!shortcutListBuffer->writeCodePointsAndAdvancePosition(codePoint, codePointCount, + true /* writesTerminator */, shortcutEntryPos)) { + AKLOGE("Cannot write shortcut target code points. pos: %d", *shortcutEntryPos); + return false; + } + return true; +} + +// Find a shortcut entry that has specified target and return its position. +int ShortcutDictContent::findShortcutEntryAndGetPos(const int shortcutListPos, + const int *const targetCodePointsToFind, const int codePointCount) const { + bool hasNext = true; + int readingPos = shortcutListPos; + int targetCodePoints[MAX_WORD_LENGTH]; + while (hasNext) { + const int entryPos = readingPos; + int probability = 0; + int targetCodePointCount = 0; + getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, targetCodePoints, &targetCodePointCount, + &probability, &hasNext, &readingPos); + if (targetCodePointCount != codePointCount) { + continue; + } + bool matched = true; + for (int i = 0; i < codePointCount; ++i) { + if (targetCodePointsToFind[i] != targetCodePoints[i]) { + matched = false; + break; + } + } + if (matched) { + return entryPos; + } + } + return NOT_A_DICT_POS; +} + +int ShortcutDictContent::createAndGetShortcutFlags(const int probability, + const bool hasNext) const { + return (probability & Ver4DictConstants::SHORTCUT_PROBABILITY_MASK) + | (hasNext ? Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK : 0); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h new file mode 100644 index 000000000..eaafc27bc --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013, 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_SHORTCUT_DICT_CONTENT_H +#define LATINIME_SHORTCUT_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" + +namespace latinime { + +class ShortcutDictContent : public SparseTableDictContent { + public: + ShortcutDictContent(const char *const dictPath, const bool isUpdatable) + : SparseTableDictContent(dictPath, + Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_FILE_EXTENSION, isUpdatable, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE) {} + + ShortcutDictContent() + : SparseTableDictContent(Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE) {} + + void getShortcutEntry(const int maxCodePointCount, int *const outCodePoint, + int *const outCodePointCount, int *const outProbability, bool *const outhasNext, + const int shortcutEntryPos) { + int readingPos = shortcutEntryPos; + return getShortcutEntryAndAdvancePosition(maxCodePointCount, outCodePoint, + outCodePointCount, outProbability, outhasNext, &readingPos); + } + + void getShortcutEntryAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoint, int *const outCodePointCount, int *const outProbability, + bool *const outhasNext, int *const shortcutEntryPos) const; + + // Returns head position of shortcut list for a PtNode specified by terminalId. + int getShortcutListHeadPos(const int terminalId) const; + + bool flushToFile(const char *const dictPath) const; + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ShortcutDictContent *const originalShortcutDictContent); + + bool createNewShortcutList(const int terminalId); + + bool copyShortcutList(const int shortcutListPos, const int toPos); + + bool setProbability(const int probability, const int shortcutEntryPos); + + bool writeShortcutEntry(const int *const codePoint, const int codePointCount, + const int probability, const bool hasNext, const int shortcutEntryPos) { + int writingPos = shortcutEntryPos; + return writeShortcutEntryAndAdvancePosition(codePoint, codePointCount, probability, + hasNext, &writingPos); + } + + bool writeShortcutEntryAndAdvancePosition(const int *const codePoint, + const int codePointCount, const int probability, const bool hasNext, + int *const shortcutEntryPos); + + int findShortcutEntryAndGetPos(const int shortcutListPos, + const int *const targetCodePointsToFind, const int codePointCount) const; + + private: + DISALLOW_COPY_AND_ASSIGN(ShortcutDictContent); + + bool copyShortcutListFromDictContent(const int shortcutListPos, + const ShortcutDictContent *const sourceShortcutDictContent, const int toPos); + + int createAndGetShortcutFlags(const int probability, const bool hasNext) const; +}; +} // namespace latinime +#endif /* LATINIME_SHORTCUT_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h new file mode 100644 index 000000000..215642234 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013, 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_SINGLE_DICT_CONTENT_H +#define LATINIME_SINGLE_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +namespace latinime { + +class SingleDictContent : public DictContent { + public: + SingleDictContent(const char *const dictPath, const char *const contentFileName, + const bool isUpdatable) + : mMmappedBuffer(MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)), + mExpandableContentBuffer(mMmappedBuffer ? mMmappedBuffer->getBuffer() : nullptr, + mMmappedBuffer ? mMmappedBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mIsValid(mMmappedBuffer) {} + + SingleDictContent() + : mMmappedBuffer(nullptr), + mExpandableContentBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), mIsValid(true) {} + + virtual ~SingleDictContent() {} + + virtual bool isValid() const { + return mIsValid; + } + + bool isNearSizeLimit() const { + return mExpandableContentBuffer.isNearSizeLimit(); + } + + protected: + BufferWithExtendableBuffer *getWritableBuffer() { + return &mExpandableContentBuffer; + } + + const BufferWithExtendableBuffer *getBuffer() const { + return &mExpandableContentBuffer; + } + + bool flush(const char *const dictPath, const char *const contentFileNameSuffix) const { + return DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + contentFileNameSuffix, &mExpandableContentBuffer); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SingleDictContent); + + const MmappedBuffer::MmappedBufferPtr mMmappedBuffer; + BufferWithExtendableBuffer mExpandableContentBuffer; + const bool mIsValid; +}; +} // namespace latinime +#endif /* LATINIME_SINGLE_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp new file mode 100644 index 000000000..63c6ea3a4 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h" + +namespace latinime { + +bool SparseTableDictContent::flush(const char *const dictPath, + const char *const lookupTableFileNameSuffix, const char *const addressTableFileNameSuffix, + const char *const contentFileNameSuffix) const { + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, lookupTableFileNameSuffix, + &mExpandableLookupTableBuffer)){ + return false; + } + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, addressTableFileNameSuffix, + &mExpandableAddressTableBuffer)) { + return false; + } + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, contentFileNameSuffix, + &mExpandableContentBuffer)) { + return false; + } + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h new file mode 100644 index 000000000..fb6c88eef --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013, 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_SPARSE_TABLE_DICT_CONTENT_H +#define LATINIME_SPARSE_TABLE_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" +#include "suggest/policyimpl/dictionary/utils/sparse_table.h" + +namespace latinime { + +// TODO: Support multiple contents. +class SparseTableDictContent : public DictContent { + public: + AK_FORCE_INLINE SparseTableDictContent(const char *const dictPath, + const char *const lookupTableFileName, const char *const addressTableFileName, + const char *const contentFileName, const bool isUpdatable, + const int sparseTableBlockSize, const int sparseTableDataSize) + : mLookupTableBuffer( + MmappedBuffer::openBuffer(dictPath, lookupTableFileName, isUpdatable)), + mAddressTableBuffer( + MmappedBuffer::openBuffer(dictPath, addressTableFileName, isUpdatable)), + mContentBuffer( + MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)), + mExpandableLookupTableBuffer( + mLookupTableBuffer ? mLookupTableBuffer->getBuffer() : nullptr, + mLookupTableBuffer ? mLookupTableBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableAddressTableBuffer( + mAddressTableBuffer ? mAddressTableBuffer->getBuffer() : nullptr, + mAddressTableBuffer ? mAddressTableBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableContentBuffer(mContentBuffer ? mContentBuffer->getBuffer() : nullptr, + mContentBuffer ? mContentBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer, + sparseTableBlockSize, sparseTableDataSize), + mIsValid(mLookupTableBuffer && mAddressTableBuffer && mContentBuffer) {} + + SparseTableDictContent(const int sparseTableBlockSize, const int sparseTableDataSize) + : mLookupTableBuffer(), mAddressTableBuffer(), mContentBuffer(), + mExpandableLookupTableBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableAddressTableBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableContentBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer, + sparseTableBlockSize, sparseTableDataSize), mIsValid(true) {} + + virtual ~SparseTableDictContent() {} + + virtual bool isValid() const { + return mIsValid; + } + + bool isNearSizeLimit() const { + return mExpandableLookupTableBuffer.isNearSizeLimit() + || mExpandableAddressTableBuffer.isNearSizeLimit() + || mExpandableContentBuffer.isNearSizeLimit(); + } + + protected: + SparseTable *getUpdatableAddressLookupTable() { + return &mAddressLookupTable; + } + + const SparseTable *getAddressLookupTable() const { + return &mAddressLookupTable; + } + + BufferWithExtendableBuffer *getWritableContentBuffer() { + return &mExpandableContentBuffer; + } + + const BufferWithExtendableBuffer *getContentBuffer() const { + return &mExpandableContentBuffer; + } + + bool flush(const char *const dictDirPath, const char *const lookupTableFileName, + const char *const addressTableFileName, const char *const contentFileName) const; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SparseTableDictContent); + + const MmappedBuffer::MmappedBufferPtr mLookupTableBuffer; + const MmappedBuffer::MmappedBufferPtr mAddressTableBuffer; + const MmappedBuffer::MmappedBufferPtr mContentBuffer; + BufferWithExtendableBuffer mExpandableLookupTableBuffer; + BufferWithExtendableBuffer mExpandableAddressTableBuffer; + BufferWithExtendableBuffer mExpandableContentBuffer; + SparseTable mAddressLookupTable; + const bool mIsValid; +}; +} // namespace latinime +#endif /* LATINIME_SPARSE_TABLE_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp new file mode 100644 index 000000000..0b17a009d --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +int TerminalPositionLookupTable::getTerminalPtNodePosition(const int terminalId) const { + if (terminalId < 0 || terminalId >= mSize) { + return NOT_A_DICT_POS; + } + const int terminalPos = getBuffer()->readUint( + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId)); + return (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) ? + NOT_A_DICT_POS : terminalPos; +} + +bool TerminalPositionLookupTable::setTerminalPtNodePosition( + const int terminalId, const int terminalPtNodePos) { + if (terminalId < 0) { + return NOT_A_DICT_POS; + } + while (terminalId >= mSize) { + // Write new entry. + if (!getWritableBuffer()->writeUint(Ver4DictConstants::NOT_A_TERMINAL_ADDRESS, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(mSize))) { + return false; + } + mSize++; + } + const int terminalPos = (terminalPtNodePos != NOT_A_DICT_POS) ? + terminalPtNodePos : Ver4DictConstants::NOT_A_TERMINAL_ADDRESS; + return getWritableBuffer()->writeUint(terminalPos, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId)); +} + +bool TerminalPositionLookupTable::flushToFile(const char *const dictPath) const { + // If the used buffer size is smaller than the actual buffer size, regenerate the lookup + // table and write the new table to the file. + if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { + TerminalPositionLookupTable lookupTableToWrite; + for (int i = 0; i < mSize; ++i) { + const int terminalPtNodePosition = getTerminalPtNodePosition(i); + if (!lookupTableToWrite.setTerminalPtNodePosition(i, terminalPtNodePosition)) { + AKLOGE("Cannot set terminal position to lookupTableToWrite." + " terminalId: %d, position: %d", i, terminalPtNodePosition); + return false; + } + } + return lookupTableToWrite.flush(dictPath, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); + } else { + // We can simply use this lookup table because the buffer size has not been + // changed. + return flush(dictPath, Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); + } +} + +bool TerminalPositionLookupTable::runGCTerminalIds(TerminalIdMap *const terminalIdMap) { + int removedEntryCount = 0; + int nextNewTerminalId = 0; + for (int i = 0; i < mSize; ++i) { + const int terminalPos = getBuffer()->readUint( + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(i)); + if (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) { + // This entry is a garbage. + removedEntryCount++; + } else { + // Give a new terminal id to the entry. + if (!getWritableBuffer()->writeUint(terminalPos, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, + getEntryPos(nextNewTerminalId))) { + return false; + } + // Memorize the mapping to the old terminal id to the new terminal id. + terminalIdMap->insert(TerminalIdMap::value_type(i, nextNewTerminalId)); + nextNewTerminalId++; + } + } + mSize = nextNewTerminalId; + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h new file mode 100644 index 000000000..816059560 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 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_POSITION_LOOKUP_TABLE_H +#define LATINIME_TERMINAL_POSITION_LOOKUP_TABLE_H + +#include <unordered_map> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" + +namespace latinime { + +class TerminalPositionLookupTable : public SingleDictContent { + public: + typedef std::unordered_map<int, int> TerminalIdMap; + + TerminalPositionLookupTable(const char *const dictPath, const bool isUpdatable) + : SingleDictContent(dictPath, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION, isUpdatable), + mSize(getBuffer()->getTailPosition() + / Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE) {} + + TerminalPositionLookupTable() : mSize(0) {} + + int getTerminalPtNodePosition(const int terminalId) const; + + bool setTerminalPtNodePosition(const int terminalId, const int terminalPtNodePos); + + int getNextTerminalId() const { + return mSize; + } + + bool flushToFile(const char *const dictPath) const; + + bool runGCTerminalIds(TerminalIdMap *const terminalIdMap); + + private: + DISALLOW_COPY_AND_ASSIGN(TerminalPositionLookupTable); + + int getEntryPos(const int terminalId) const { + return terminalId * Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE; + } + + int mSize; +}; +} // namespace latinime +#endif // LATINIME_TERMINAL_POSITION_LOOKUP_TABLE_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp new file mode 100644 index 000000000..95f654498 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2013 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" + +#include <cerrno> +#include <cstring> +#include <sys/stat.h> +#include <sys/types.h> + +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" + +namespace latinime { + +/* static */ Ver4DictBuffers::Ver4DictBuffersPtr Ver4DictBuffers::openVer4DictBuffers( + const char *const dictPath, MmappedBuffer::MmappedBufferPtr headerBuffer) { + if (!headerBuffer) { + ASSERT(false); + AKLOGE("The header buffer must be valid to open ver4 dict buffers."); + return Ver4DictBuffersPtr(nullptr); + } + // TODO: take only dictDirPath, and open both header and trie files in the constructor below + const bool isUpdatable = headerBuffer->isUpdatable(); + return Ver4DictBuffersPtr(new Ver4DictBuffers(dictPath, std::move(headerBuffer), isUpdatable)); +} + +bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath, + const BufferWithExtendableBuffer *const headerBuffer) const { + // Create temporary directory. + const int tmpDirPathBufSize = FileUtils::getFilePathWithSuffixBufSize(dictDirPath, + DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); + char tmpDirPath[tmpDirPathBufSize]; + FileUtils::getFilePathWithSuffix(dictDirPath, + DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE, tmpDirPathBufSize, + tmpDirPath); + if (FileUtils::existsDir(tmpDirPath)) { + if (!FileUtils::removeDirAndFiles(tmpDirPath)) { + AKLOGE("Existing directory %s cannot be removed.", tmpDirPath); + ASSERT(false); + return false; + } + } + if (mkdir(tmpDirPath, S_IRWXU) == -1) { + AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno); + return false; + } + // Get dictionary base path. + const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; + char dictName[dictNameBufSize]; + FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); + const int dictPathBufSize = FileUtils::getFilePathBufSize(tmpDirPath, dictName); + char dictPath[dictPathBufSize]; + FileUtils::getFilePath(tmpDirPath, dictName, dictPathBufSize, dictPath); + + // Write header file. + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + Ver4DictConstants::HEADER_FILE_EXTENSION, headerBuffer)) { + AKLOGE("Dictionary header file %s%s cannot be written.", tmpDirPath, + Ver4DictConstants::HEADER_FILE_EXTENSION); + return false; + } + // Write trie file. + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + Ver4DictConstants::TRIE_FILE_EXTENSION, &mExpandableTrieBuffer)) { + AKLOGE("Dictionary trie file %s%s cannot be written.", tmpDirPath, + Ver4DictConstants::TRIE_FILE_EXTENSION); + return false; + } + // Write dictionary contents. + if (!mTerminalPositionLookupTable.flushToFile(dictPath)) { + AKLOGE("Terminal position lookup table cannot be written. %s", tmpDirPath); + return false; + } + if (!mProbabilityDictContent.flushToFile(dictPath)) { + AKLOGE("Probability dict content cannot be written. %s", tmpDirPath); + return false; + } + if (!mBigramDictContent.flushToFile(dictPath)) { + AKLOGE("Bigram dict content cannot be written. %s", tmpDirPath); + return false; + } + if (!mShortcutDictContent.flushToFile(dictPath)) { + AKLOGE("Shortcut dict content cannot be written. %s", tmpDirPath); + return false; + } + // Remove existing dictionary. + if (!FileUtils::removeDirAndFiles(dictDirPath)) { + AKLOGE("Existing directory %s cannot be removed.", dictDirPath); + ASSERT(false); + return false; + } + // Rename temporary directory. + if (rename(tmpDirPath, dictDirPath) != 0) { + AKLOGE("%s cannot be renamed to %s", tmpDirPath, dictDirPath); + ASSERT(false); + return false; + } + return true; +} + +Ver4DictBuffers::Ver4DictBuffers(const char *const dictPath, + MmappedBuffer::MmappedBufferPtr headerBuffer, const bool isUpdatable) + : mHeaderBuffer(std::move(headerBuffer)), + mDictBuffer(MmappedBuffer::openBuffer(dictPath, + Ver4DictConstants::TRIE_FILE_EXTENSION, isUpdatable)), + mHeaderPolicy(mHeaderBuffer->getBuffer(), FormatUtils::VERSION_4), + mExpandableHeaderBuffer(mHeaderBuffer ? mHeaderBuffer->getBuffer() : nullptr, + mHeaderPolicy.getSize(), + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableTrieBuffer(mDictBuffer ? mDictBuffer->getBuffer() : nullptr, + mDictBuffer ? mDictBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mTerminalPositionLookupTable(dictPath, isUpdatable), + mProbabilityDictContent(dictPath, mHeaderPolicy.hasHistoricalInfoOfWords(), isUpdatable), + mBigramDictContent(dictPath, mHeaderPolicy.hasHistoricalInfoOfWords(), isUpdatable), + mShortcutDictContent(dictPath, isUpdatable), + mIsUpdatable(isUpdatable) {} + +Ver4DictBuffers::Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const int maxTrieSize) + : mHeaderBuffer(nullptr), mDictBuffer(nullptr), mHeaderPolicy(headerPolicy), + mExpandableHeaderBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableTrieBuffer(maxTrieSize), mTerminalPositionLookupTable(), + mProbabilityDictContent(headerPolicy->hasHistoricalInfoOfWords()), + mBigramDictContent(headerPolicy->hasHistoricalInfoOfWords()), mShortcutDictContent(), + mIsUpdatable(true) {} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h new file mode 100644 index 000000000..fc41432f4 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2013, 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_VER4_DICT_BUFFER_H +#define LATINIME_VER4_DICT_BUFFER_H + +#include <memory> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +namespace latinime { + +class Ver4DictBuffers { + public: + typedef std::unique_ptr<Ver4DictBuffers> Ver4DictBuffersPtr; + + static Ver4DictBuffersPtr openVer4DictBuffers(const char *const dictDirPath, + MmappedBuffer::MmappedBufferPtr headerBuffer); + + static AK_FORCE_INLINE Ver4DictBuffersPtr createVer4DictBuffers( + const HeaderPolicy *const headerPolicy, const int maxTrieSize) { + return Ver4DictBuffersPtr(new Ver4DictBuffers(headerPolicy, maxTrieSize)); + } + + AK_FORCE_INLINE bool isValid() const { + return mHeaderBuffer && mDictBuffer && mHeaderPolicy.isValid() + && mProbabilityDictContent.isValid() && mTerminalPositionLookupTable.isValid() + && mBigramDictContent.isValid() && mShortcutDictContent.isValid(); + } + + AK_FORCE_INLINE bool isNearSizeLimit() const { + return mExpandableTrieBuffer.isNearSizeLimit() + || mTerminalPositionLookupTable.isNearSizeLimit() + || mProbabilityDictContent.isNearSizeLimit() + || mBigramDictContent.isNearSizeLimit() + || mShortcutDictContent.isNearSizeLimit(); + } + + AK_FORCE_INLINE const HeaderPolicy *getHeaderPolicy() const { + return &mHeaderPolicy; + } + + AK_FORCE_INLINE BufferWithExtendableBuffer *getWritableHeaderBuffer() { + return &mExpandableHeaderBuffer; + } + + AK_FORCE_INLINE BufferWithExtendableBuffer *getWritableTrieBuffer() { + return &mExpandableTrieBuffer; + } + + AK_FORCE_INLINE const BufferWithExtendableBuffer *getTrieBuffer() const { + return &mExpandableTrieBuffer; + } + + AK_FORCE_INLINE TerminalPositionLookupTable *getMutableTerminalPositionLookupTable() { + return &mTerminalPositionLookupTable; + } + + AK_FORCE_INLINE const TerminalPositionLookupTable *getTerminalPositionLookupTable() const { + return &mTerminalPositionLookupTable; + } + + AK_FORCE_INLINE ProbabilityDictContent *getMutableProbabilityDictContent() { + return &mProbabilityDictContent; + } + + AK_FORCE_INLINE const ProbabilityDictContent *getProbabilityDictContent() const { + return &mProbabilityDictContent; + } + + AK_FORCE_INLINE BigramDictContent *getMutableBigramDictContent() { + return &mBigramDictContent; + } + + AK_FORCE_INLINE const BigramDictContent *getBigramDictContent() const { + return &mBigramDictContent; + } + + AK_FORCE_INLINE ShortcutDictContent *getMutableShortcutDictContent() { + return &mShortcutDictContent; + } + + AK_FORCE_INLINE const ShortcutDictContent *getShortcutDictContent() const { + return &mShortcutDictContent; + } + + AK_FORCE_INLINE bool isUpdatable() const { + return mIsUpdatable; + } + + bool flush(const char *const dictDirPath) const { + return flushHeaderAndDictBuffers(dictDirPath, &mExpandableHeaderBuffer); + } + + bool flushHeaderAndDictBuffers(const char *const dictDirPath, + const BufferWithExtendableBuffer *const headerBuffer) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4DictBuffers); + + Ver4DictBuffers(const char *const dictDirPath, + const MmappedBuffer::MmappedBufferPtr headerBuffer, const bool isUpdatable); + + Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const int maxTrieSize); + + const MmappedBuffer::MmappedBufferPtr mHeaderBuffer; + const MmappedBuffer::MmappedBufferPtr mDictBuffer; + const HeaderPolicy mHeaderPolicy; + BufferWithExtendableBuffer mExpandableHeaderBuffer; + BufferWithExtendableBuffer mExpandableTrieBuffer; + TerminalPositionLookupTable mTerminalPositionLookupTable; + ProbabilityDictContent mProbabilityDictContent; + BigramDictContent mBigramDictContent; + ShortcutDictContent mShortcutDictContent; + const int mIsUpdatable; +}; +} // namespace latinime +#endif /* LATINIME_VER4_DICT_BUFFER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp new file mode 100644 index 000000000..deed010cd --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" + +namespace latinime { + +// These values MUST match the definitions in FormatSpec.java. +const char *const Ver4DictConstants::TRIE_FILE_EXTENSION = ".trie"; +const char *const Ver4DictConstants::HEADER_FILE_EXTENSION = ".header"; +const char *const Ver4DictConstants::FREQ_FILE_EXTENSION = ".freq"; +// tat = Terminal Address Table +const char *const Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat"; +const char *const Ver4DictConstants::BIGRAM_FILE_EXTENSION = ".bigram_freq"; +const char *const Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION = ".bigram_lookup"; +const char *const Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION = ".bigram_index_freq"; +const char *const Ver4DictConstants::SHORTCUT_FILE_EXTENSION = ".shortcut_shortcut"; +const char *const Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION = ".shortcut_lookup"; +const char *const Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION = + ".shortcut_index_shortcut"; + +// Version 4 dictionary size is implicitly limited to 8MB due to 3-byte offsets. +const int Ver4DictConstants::MAX_DICTIONARY_SIZE = 8 * 1024 * 1024; +// Extended region size, which is not GCed region size in dict file + additional buffer size, is +// limited to 1MB to prevent from inefficient traversing. +const int Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE = 1 * 1024 * 1024; + +const int Ver4DictConstants::NOT_A_TERMINAL_ID = -1; +const int Ver4DictConstants::PROBABILITY_SIZE = 1; +const int Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE = 1; +const int Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3; +const int Ver4DictConstants::NOT_A_TERMINAL_ADDRESS = 0; +const int Ver4DictConstants::TERMINAL_ID_FIELD_SIZE = 4; +const int Ver4DictConstants::TIME_STAMP_FIELD_SIZE = 4; +const int Ver4DictConstants::WORD_LEVEL_FIELD_SIZE = 1; +const int Ver4DictConstants::WORD_COUNT_FIELD_SIZE = 1; + +const int Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 16; +const int Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE = 4; +const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64; +const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE = 4; + +const int Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE = 3; +// Unsigned int max value of BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE-byte is used for representing +// invalid terminal ID in bigram lists. +const int Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID = + (1 << (BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE * 8)) - 1; +const int Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE = 1; +const int Ver4DictConstants::BIGRAM_PROBABILITY_MASK = 0x0F; +const int Ver4DictConstants::BIGRAM_HAS_NEXT_MASK = 0x80; +const int Ver4DictConstants::BIGRAM_LARGE_PROBABILITY_FIELD_SIZE = 1; + +const int Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE = 1; +const int Ver4DictConstants::SHORTCUT_PROBABILITY_MASK = 0x0F; +const int Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK = 0x80; + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h new file mode 100644 index 000000000..d6d22c5c1 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013, 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_VER4_DICT_CONSTANTS_H +#define LATINIME_VER4_DICT_CONSTANTS_H + +#include "defines.h" + +namespace latinime { + +// TODO: Create PtConstants under the pt_common and move some constant values there. +// Note that there are corresponding definitions in FormatSpec.java. +class Ver4DictConstants { + public: + static const char *const TRIE_FILE_EXTENSION; + static const char *const HEADER_FILE_EXTENSION; + static const char *const FREQ_FILE_EXTENSION; + static const char *const TERMINAL_ADDRESS_TABLE_FILE_EXTENSION; + static const char *const BIGRAM_FILE_EXTENSION; + static const char *const BIGRAM_LOOKUP_TABLE_FILE_EXTENSION; + static const char *const BIGRAM_CONTENT_TABLE_FILE_EXTENSION; + static const char *const SHORTCUT_FILE_EXTENSION; + static const char *const SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION; + static const char *const SHORTCUT_CONTENT_TABLE_FILE_EXTENSION; + + static const int MAX_DICTIONARY_SIZE; + static const int MAX_DICT_EXTENDED_REGION_SIZE; + + static const int NOT_A_TERMINAL_ID; + static const int PROBABILITY_SIZE; + static const int FLAGS_IN_PROBABILITY_FILE_SIZE; + static const int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE; + static const int NOT_A_TERMINAL_ADDRESS; + static const int TERMINAL_ID_FIELD_SIZE; + static const int TIME_STAMP_FIELD_SIZE; + static const int WORD_LEVEL_FIELD_SIZE; + static const int WORD_COUNT_FIELD_SIZE; + + static const int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE; + static const int BIGRAM_ADDRESS_TABLE_DATA_SIZE; + static const int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE; + static const int SHORTCUT_ADDRESS_TABLE_DATA_SIZE; + + static const int BIGRAM_FLAGS_FIELD_SIZE; + static const int BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE; + static const int INVALID_BIGRAM_TARGET_TERMINAL_ID; + static const int BIGRAM_PROBABILITY_MASK; + static const int BIGRAM_HAS_NEXT_MASK; + // Used when bigram list has time stamp. + static const int BIGRAM_LARGE_PROBABILITY_FIELD_SIZE; + + static const int SHORTCUT_FLAGS_FIELD_SIZE; + static const int SHORTCUT_PROBABILITY_MASK; + static const int SHORTCUT_HAS_NEXT_MASK; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4DictConstants); +}; +} // namespace latinime +#endif /* LATINIME_VER4_DICT_CONSTANTS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp new file mode 100644 index 000000000..67420a252 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { + +const PtNodeParams Ver4PatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProcessMovedPtNode( + const int ptNodePos, const int siblingNodePos) const { + if (ptNodePos < 0 || ptNodePos >= mBuffer->getTailPosition()) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d", + ptNodePos, mBuffer->getTailPosition()); + ASSERT(false); + return PtNodeParams(); + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodePos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int pos = ptNodePos; + const int headPos = ptNodePos; + if (usesAdditionalBuffer) { + pos -= mBuffer->getOriginalBufferSize(); + } + const PatriciaTrieReadingUtils::NodeFlags flags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const int parentPosOffset = + DynamicPtReadingUtils::getParentPtNodePosOffsetAndAdvancePosition( + dictBuf, &pos); + const int parentPos = + DynamicPtReadingUtils::getParentPtNodePos(parentPosOffset, headPos); + int codePoints[MAX_WORD_LENGTH]; + const int codePonitCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition( + dictBuf, flags, MAX_WORD_LENGTH, codePoints, &pos); + int terminalIdFieldPos = NOT_A_DICT_POS; + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + int probability = NOT_A_PROBABILITY; + if (PatriciaTrieReadingUtils::isTerminal(flags)) { + terminalIdFieldPos = pos; + if (usesAdditionalBuffer) { + terminalIdFieldPos += mBuffer->getOriginalBufferSize(); + } + terminalId = Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition(dictBuf, &pos); + const ProbabilityEntry probabilityEntry = + mProbabilityDictContent->getProbabilityEntry(terminalId); + if (probabilityEntry.hasHistoricalInfo()) { + probability = ForgettingCurveUtils::decodeProbability( + probabilityEntry.getHistoricalInfo(), mHeaderPolicy); + } else { + probability = probabilityEntry.getProbability(); + } + } + int childrenPosFieldPos = pos; + if (usesAdditionalBuffer) { + childrenPosFieldPos += mBuffer->getOriginalBufferSize(); + } + int childrenPos = DynamicPtReadingUtils::readChildrenPositionAndAdvancePosition( + dictBuf, &pos); + if (usesAdditionalBuffer && childrenPos != NOT_A_DICT_POS) { + childrenPos += mBuffer->getOriginalBufferSize(); + } + if (usesAdditionalBuffer) { + pos += mBuffer->getOriginalBufferSize(); + } + // Sibling position is the tail position of original PtNode. + int newSiblingNodePos = (siblingNodePos == NOT_A_DICT_POS) ? pos : siblingNodePos; + // Read destination node if the read node is a moved node. + if (DynamicPtReadingUtils::isMoved(flags)) { + // The destination position is stored at the same place as the parent position. + return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(parentPos, newSiblingNodePos); + } else { + return PtNodeParams(headPos, flags, parentPos, codePonitCount, codePoints, + terminalIdFieldPos, terminalId, probability, childrenPosFieldPos, childrenPos, + newSiblingNodePos); + } +} + +} diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h new file mode 100644 index 000000000..f24307e7b --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_NODE_READER_H +#define LATINIME_VER4_PATRICIA_TRIE_NODE_READER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h" + +namespace latinime { + +class BufferWithExtendableBuffer; +class HeaderPolicy; +class ProbabilityDictContent; + +/* + * This class is used for helping to read nodes of ver4 patricia trie. This class handles moved + * node and reads node attributes including probability form probabilityBuffer. + */ +class Ver4PatriciaTrieNodeReader : public PtNodeReader { + public: + Ver4PatriciaTrieNodeReader(const BufferWithExtendableBuffer *const buffer, + const ProbabilityDictContent *const probabilityDictContent, + const HeaderPolicy *const headerPolicy) + : mBuffer(buffer), mProbabilityDictContent(probabilityDictContent), + mHeaderPolicy(headerPolicy) {} + + ~Ver4PatriciaTrieNodeReader() {} + + virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const { + return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, + NOT_A_DICT_POS /* siblingNodePos */); + } + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeReader); + + const BufferWithExtendableBuffer *const mBuffer; + const ProbabilityDictContent *const mProbabilityDictContent; + const HeaderPolicy *const mHeaderPolicy; + + const PtNodeParams fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos, + const int siblingNodePos) const; +}; +} // namespace latinime +#endif /* LATINIME_VER4_PATRICIA_TRIE_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp new file mode 100644 index 000000000..38ff42fee --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h" + +#include "suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { + +const int Ver4PatriciaTrieNodeWriter::CHILDREN_POSITION_FIELD_SIZE = 3; + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsDeleted( + const PtNodeParams *const toBeUpdatedPtNodeParams) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */, + true /* isDeleted */, false /* willBecomeNonTerminal */); + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + // Update flags. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos)) { + return false; + } + if (toBeUpdatedPtNodeParams->isTerminal()) { + // The PtNode is a terminal. Delete entry from the terminal position lookup table. + return mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + toBeUpdatedPtNodeParams->getTerminalId(), NOT_A_DICT_POS /* ptNodePos */); + } else { + return true; + } +} + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsMoved( + const PtNodeParams *const toBeUpdatedPtNodeParams, + const int movedPos, const int bigramLinkedNodePos) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, true /* isMoved */, + false /* isDeleted */, false /* willBecomeNonTerminal */); + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + // Update flags. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos)) { + return false; + } + // Update moved position, which is stored in the parent offset field. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( + mTrieBuffer, movedPos, toBeUpdatedPtNodeParams->getHeadPos(), &writingPos)) { + return false; + } + if (toBeUpdatedPtNodeParams->hasChildren()) { + // Update children's parent position. + mReadingHelper.initWithPtNodeArrayPos(toBeUpdatedPtNodeParams->getChildrenPos()); + while (!mReadingHelper.isEnd()) { + const PtNodeParams childPtNodeParams(mReadingHelper.getPtNodeParams()); + int parentOffsetFieldPos = childPtNodeParams.getHeadPos() + + DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE; + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( + mTrieBuffer, bigramLinkedNodePos, childPtNodeParams.getHeadPos(), + &parentOffsetFieldPos)) { + // Parent offset cannot be written because of a bug or a broken dictionary; thus, + // we give up to update dictionary. + return false; + } + mReadingHelper.readNextSiblingNode(childPtNodeParams); + } + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsWillBecomeNonTerminal( + const PtNodeParams *const toBeUpdatedPtNodeParams) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */, + false /* isDeleted */, true /* willBecomeNonTerminal */); + if (!mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + toBeUpdatedPtNodeParams->getTerminalId(), NOT_A_DICT_POS /* ptNodePos */)) { + AKLOGE("Cannot update terminal position lookup table. terminal id: %d", + toBeUpdatedPtNodeParams->getTerminalId()); + return false; + } + // Update flags. + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + return DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos); +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbability( + const PtNodeParams *const toBeUpdatedPtNodeParams, const int newProbability, + const int timestamp) { + if (!toBeUpdatedPtNodeParams->isTerminal()) { + return false; + } + const ProbabilityEntry originalProbabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId()); + const ProbabilityEntry probabilityEntry = createUpdatedEntryFrom(&originalProbabilityEntry, + newProbability, timestamp); + return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry); +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( + const PtNodeParams *const toBeUpdatedPtNodeParams, bool *const outNeedsToKeepPtNode) { + if (!toBeUpdatedPtNodeParams->isTerminal()) { + AKLOGE("updatePtNodeProbabilityAndGetNeedsToSaveForGC is called for non-terminal PtNode."); + return false; + } + const ProbabilityEntry originalProbabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId()); + if (originalProbabilityEntry.hasHistoricalInfo()) { + const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave( + originalProbabilityEntry.getHistoricalInfo(), mHeaderPolicy); + const ProbabilityEntry probabilityEntry = + originalProbabilityEntry.createEntryWithUpdatedHistoricalInfo(&historicalInfo); + if (!mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry)) { + AKLOGE("Cannot write updated probability entry. terminalId: %d", + toBeUpdatedPtNodeParams->getTerminalId()); + return false; + } + const bool isValid = ForgettingCurveUtils::needsToKeep(&historicalInfo, mHeaderPolicy); + if (!isValid) { + if (!markPtNodeAsWillBecomeNonTerminal(toBeUpdatedPtNodeParams)) { + AKLOGE("Cannot mark PtNode as willBecomeNonTerminal."); + return false; + } + } + *outNeedsToKeepPtNode = isValid; + } else { + // No need to update probability. + *outNeedsToKeepPtNode = true; + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::updateChildrenPosition( + const PtNodeParams *const toBeUpdatedPtNodeParams, const int newChildrenPosition) { + int childrenPosFieldPos = toBeUpdatedPtNodeParams->getChildrenPosFieldPos(); + return DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition(mTrieBuffer, + newChildrenPosition, &childrenPosFieldPos); +} + +bool Ver4PatriciaTrieNodeWriter::updateTerminalId(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newTerminalId) { + return mTrieBuffer->writeUint(newTerminalId, Ver4DictConstants::TERMINAL_ID_FIELD_SIZE, + toBeUpdatedPtNodeParams->getTerminalIdFieldPos()); +} + +bool Ver4PatriciaTrieNodeWriter::writePtNodeAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const ptNodeWritingPos) { + return writePtNodeAndGetTerminalIdAndAdvancePosition(ptNodeParams, 0 /* outTerminalId */, + ptNodeWritingPos); +} + + +bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition( + const PtNodeParams *const ptNodeParams, const int timestamp, int *const ptNodeWritingPos) { + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + if (!writePtNodeAndGetTerminalIdAndAdvancePosition(ptNodeParams, &terminalId, + ptNodeWritingPos)) { + return false; + } + // Write probability. + ProbabilityEntry newProbabilityEntry; + const ProbabilityEntry probabilityEntryToWrite = createUpdatedEntryFrom( + &newProbabilityEntry, ptNodeParams->getProbability(), timestamp); + return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry(terminalId, + &probabilityEntryToWrite); +} + +bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry( + const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam, const int probability, const int timestamp, + bool *const outAddedNewBigram) { + if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(), + targetPtNodeParam->getTerminalId(), probability, timestamp, outAddedNewBigram)) { + AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d", + sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId()); + return false; + } + if (!sourcePtNodeParams->hasBigrams()) { + // Update has bigrams flag. + return updatePtNodeFlags(sourcePtNodeParams->getHeadPos(), + sourcePtNodeParams->isBlacklisted(), sourcePtNodeParams->isNotAWord(), + sourcePtNodeParams->isTerminal(), sourcePtNodeParams->hasShortcutTargets(), + true /* hasBigrams */, + sourcePtNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::removeBigramEntry( + const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) { + return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(), + targetPtNodeParam->getTerminalId()); +} + +bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries( + const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount) { + return mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries( + sourcePtNodeParams->getTerminalId(), outBigramEntryCount); +} + +bool Ver4PatriciaTrieNodeWriter::updateAllPositionFields( + const PtNodeParams *const toBeUpdatedPtNodeParams, + const DictPositionRelocationMap *const dictPositionRelocationMap, + int *const outBigramEntryCount) { + int parentPos = toBeUpdatedPtNodeParams->getParentPos(); + if (parentPos != NOT_A_DICT_POS) { + PtNodeWriter::PtNodePositionRelocationMap::const_iterator it = + dictPositionRelocationMap->mPtNodePositionRelocationMap.find(parentPos); + if (it != dictPositionRelocationMap->mPtNodePositionRelocationMap.end()) { + parentPos = it->second; + } + } + int writingPos = toBeUpdatedPtNodeParams->getHeadPos() + + DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE; + // Write updated parent offset. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition(mTrieBuffer, + parentPos, toBeUpdatedPtNodeParams->getHeadPos(), &writingPos)) { + return false; + } + + // Updates children position. + int childrenPos = toBeUpdatedPtNodeParams->getChildrenPos(); + if (childrenPos != NOT_A_DICT_POS) { + PtNodeWriter::PtNodeArrayPositionRelocationMap::const_iterator it = + dictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.find(childrenPos); + if (it != dictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.end()) { + childrenPos = it->second; + } + } + if (!updateChildrenPosition(toBeUpdatedPtNodeParams, childrenPos)) { + return false; + } + + // Counts bigram entries. + if (outBigramEntryCount) { + *outBigramEntryCount = mBigramPolicy->getBigramEntryConut( + toBeUpdatedPtNodeParams->getTerminalId()); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::addShortcutTarget(const PtNodeParams *const ptNodeParams, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability) { + if (!mShortcutPolicy->addNewShortcut(ptNodeParams->getTerminalId(), + targetCodePoints, targetCodePointCount, shortcutProbability)) { + AKLOGE("Cannot add new shortuct entry. terminalId: %d", ptNodeParams->getTerminalId()); + return false; + } + if (!ptNodeParams->hasShortcutTargets()) { + // Update has shortcut targets flag. + return updatePtNodeFlags(ptNodeParams->getHeadPos(), + ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), + ptNodeParams->isTerminal(), true /* hasShortcutTargets */, + ptNodeParams->hasBigrams(), + ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeHasBigramsAndShortcutTargetsFlags( + const PtNodeParams *const ptNodeParams) { + const bool hasBigrams = mBuffers->getBigramDictContent()->getBigramListHeadPos( + ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; + const bool hasShortcutTargets = mBuffers->getShortcutDictContent()->getShortcutListHeadPos( + ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; + return updatePtNodeFlags(ptNodeParams->getHeadPos(), ptNodeParams->isBlacklisted(), + ptNodeParams->isNotAWord(), ptNodeParams->isTerminal(), hasShortcutTargets, + hasBigrams, ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); +} + +bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const outTerminalId, + int *const ptNodeWritingPos) { + const int nodePos = *ptNodeWritingPos; + // Write dummy flags. The Node flags are updated with appropriate flags at the last step of the + // PtNode writing. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, + 0 /* nodeFlags */, ptNodeWritingPos)) { + return false; + } + // Calculate a parent offset and write the offset. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition(mTrieBuffer, + ptNodeParams->getParentPos(), nodePos, ptNodeWritingPos)) { + return false; + } + // Write code points + if (!DynamicPtWritingUtils::writeCodePointsAndAdvancePosition(mTrieBuffer, + ptNodeParams->getCodePoints(), ptNodeParams->getCodePointCount(), ptNodeWritingPos)) { + return false; + } + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + if (!ptNodeParams->willBecomeNonTerminal()) { + if (ptNodeParams->getTerminalId() != Ver4DictConstants::NOT_A_TERMINAL_ID) { + terminalId = ptNodeParams->getTerminalId(); + } else if (ptNodeParams->isTerminal()) { + // Write terminal information using a new terminal id. + // Get a new unused terminal id. + terminalId = mBuffers->getTerminalPositionLookupTable()->getNextTerminalId(); + } + } + const int isTerminal = terminalId != Ver4DictConstants::NOT_A_TERMINAL_ID; + if (isTerminal) { + // Update the lookup table. + if (!mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + terminalId, nodePos)) { + return false; + } + // Write terminal Id. + if (!mTrieBuffer->writeUintAndAdvancePosition(terminalId, + Ver4DictConstants::TERMINAL_ID_FIELD_SIZE, ptNodeWritingPos)) { + return false; + } + if (outTerminalId) { + *outTerminalId = terminalId; + } + } + // Write children position + if (!DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition(mTrieBuffer, + ptNodeParams->getChildrenPos(), ptNodeWritingPos)) { + return false; + } + return updatePtNodeFlags(nodePos, ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), + isTerminal, ptNodeParams->hasShortcutTargets(), ptNodeParams->hasBigrams(), + ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); +} + +const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom( + const ProbabilityEntry *const originalProbabilityEntry, const int newProbability, + const int timestamp) const { + // TODO: Consolidate historical info and probability. + if (mHeaderPolicy->hasHistoricalInfoOfWords()) { + const HistoricalInfo updatedHistoricalInfo = + ForgettingCurveUtils::createUpdatedHistoricalInfo( + originalProbabilityEntry->getHistoricalInfo(), newProbability, timestamp, + mHeaderPolicy); + return originalProbabilityEntry->createEntryWithUpdatedHistoricalInfo( + &updatedHistoricalInfo); + } else { + return originalProbabilityEntry->createEntryWithUpdatedProbability(newProbability); + } +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeFlags(const int ptNodePos, + const bool isBlacklisted, const bool isNotAWord, const bool isTerminal, + const bool hasShortcutTargets, const bool hasBigrams, const bool hasMultipleChars) { + // Create node flags and write them. + PatriciaTrieReadingUtils::NodeFlags nodeFlags = + PatriciaTrieReadingUtils::createAndGetFlags(isBlacklisted, isNotAWord, isTerminal, + hasShortcutTargets, hasBigrams, hasMultipleChars, + CHILDREN_POSITION_FIELD_SIZE); + if (!DynamicPtWritingUtils::writeFlags(mTrieBuffer, nodeFlags, ptNodePos)) { + AKLOGE("Cannot write PtNode flags. flags: %x, pos: %d", nodeFlags, ptNodePos); + return false; + } + return true; +} + +} diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h new file mode 100644 index 000000000..b2b0504a1 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_NODE_WRITER_H +#define LATINIME_VER4_PATRICIA_TRIE_NODE_WRITER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h" + +namespace latinime { + +class BufferWithExtendableBuffer; +class HeaderPolicy; +class Ver4BigramListPolicy; +class Ver4DictBuffers; +class Ver4PatriciaTrieNodeReader; +class Ver4PtNodeArrayReader; +class Ver4ShortcutListPolicy; + +/* + * This class is used for helping to writes nodes of ver4 patricia trie. + */ +class Ver4PatriciaTrieNodeWriter : public PtNodeWriter { + public: + Ver4PatriciaTrieNodeWriter(BufferWithExtendableBuffer *const trieBuffer, + Ver4DictBuffers *const buffers, const HeaderPolicy *const headerPolicy, + const PtNodeReader *const ptNodeReader, + const PtNodeArrayReader *const ptNodeArrayReader, + Ver4BigramListPolicy *const bigramPolicy, Ver4ShortcutListPolicy *const shortcutPolicy) + : mTrieBuffer(trieBuffer), mBuffers(buffers), mHeaderPolicy(headerPolicy), + mReadingHelper(ptNodeReader, ptNodeArrayReader), mBigramPolicy(bigramPolicy), + mShortcutPolicy(shortcutPolicy) {} + + virtual ~Ver4PatriciaTrieNodeWriter() {} + + virtual bool markPtNodeAsDeleted(const PtNodeParams *const toBeUpdatedPtNodeParams); + + virtual bool markPtNodeAsMoved(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int movedPos, const int bigramLinkedNodePos); + + virtual bool markPtNodeAsWillBecomeNonTerminal( + const PtNodeParams *const toBeUpdatedPtNodeParams); + + virtual bool updatePtNodeProbability(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newProbability, const int timestamp); + + virtual bool updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( + const PtNodeParams *const toBeUpdatedPtNodeParams, bool *const outNeedsToKeepPtNode); + + virtual bool updateChildrenPosition(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newChildrenPosition); + + bool updateTerminalId(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newTerminalId); + + virtual bool writePtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + int *const ptNodeWritingPos); + + virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + const int timestamp, int *const ptNodeWritingPos); + + virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam, const int probability, const int timestamp, + bool *const outAddedNewBigram); + + virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam); + + virtual bool updateAllBigramEntriesAndDeleteUselessEntries( + const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount); + + virtual bool updateAllPositionFields(const PtNodeParams *const toBeUpdatedPtNodeParams, + const DictPositionRelocationMap *const dictPositionRelocationMap, + int *const outBigramEntryCount); + + virtual bool addShortcutTarget(const PtNodeParams *const ptNodeParams, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability); + + bool updatePtNodeHasBigramsAndShortcutTargetsFlags(const PtNodeParams *const ptNodeParams); + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeWriter); + + bool writePtNodeAndGetTerminalIdAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const outTerminalId, + int *const ptNodeWritingPos); + + // Create updated probability entry using given probability and timestamp. In addition to the + // probability, this method updates historical information if needed. + const ProbabilityEntry createUpdatedEntryFrom( + const ProbabilityEntry *const originalProbabilityEntry, const int newProbability, + const int timestamp) const; + + bool updatePtNodeFlags(const int ptNodePos, const bool isBlacklisted, const bool isNotAWord, + const bool isTerminal, const bool hasShortcutTargets, const bool hasBigrams, + const bool hasMultipleChars); + + static const int CHILDREN_POSITION_FIELD_SIZE; + + BufferWithExtendableBuffer *const mTrieBuffer; + Ver4DictBuffers *const mBuffers; + const HeaderPolicy *const mHeaderPolicy; + DynamicPtReadingHelper mReadingHelper; + Ver4BigramListPolicy *const mBigramPolicy; + Ver4ShortcutListPolicy *const mShortcutPolicy; +}; +} // namespace latinime +#endif /* LATINIME_VER4_PATRICIA_TRIE_NODE_WRITER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp new file mode 100644 index 000000000..bbfd22e59 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h" + +#include <vector> + +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_vector.h" +#include "suggest/core/dictionary/property/bigram_property.h" +#include "suggest/core/dictionary/property/unigram_property.h" +#include "suggest/core/dictionary/property/word_property.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" +#include "suggest/policyimpl/dictionary/utils/probability_utils.h" + +namespace latinime { + +// Note that there are corresponding definitions in Java side in BinaryDictionaryTests and +// BinaryDictionaryDecayingTests. +const char *const Ver4PatriciaTriePolicy::UNIGRAM_COUNT_QUERY = "UNIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::BIGRAM_COUNT_QUERY = "BIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::MAX_UNIGRAM_COUNT_QUERY = "MAX_UNIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; +const int Ver4PatriciaTriePolicy::MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS = 1024; +const int Ver4PatriciaTriePolicy::MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS = + Ver4DictConstants::MAX_DICTIONARY_SIZE - MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS; + +void Ver4PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const dicNode, + DicNodeVector *const childDicNodes) const { + if (!dicNode->hasChildren()) { + return; + } + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(dicNode->getChildrenPtNodeArrayPos()); + while (!readingHelper.isEnd()) { + const PtNodeParams ptNodeParams = readingHelper.getPtNodeParams(); + if (!ptNodeParams.isValid()) { + break; + } + bool isTerminal = ptNodeParams.isTerminal() && !ptNodeParams.isDeleted(); + if (isTerminal && mHeaderPolicy->isDecayingDict()) { + // A DecayingDict may have a terminal PtNode that has a terminal DicNode whose + // probability is NOT_A_PROBABILITY. In such case, we don't want to treat it as a + // valid terminal DicNode. + isTerminal = ptNodeParams.getProbability() != NOT_A_PROBABILITY; + } + childDicNodes->pushLeavingChild(dicNode, ptNodeParams.getHeadPos(), + ptNodeParams.getChildrenPos(), ptNodeParams.getProbability(), isTerminal, + ptNodeParams.hasChildren(), + ptNodeParams.isBlacklisted() + || ptNodeParams.isNotAWord() /* isBlacklistedOrNotAWord */, + ptNodeParams.getCodePointCount(), ptNodeParams.getCodePoints()); + readingHelper.readNextSiblingNode(ptNodeParams); + } + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + } +} + +int Ver4PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( + const int ptNodePos, const int maxCodePointCount, int *const outCodePoints, + int *const outUnigramProbability) const { + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodePos(ptNodePos); + const int codePointCount = readingHelper.getCodePointsAndProbabilityAndReturnCodePointCount( + maxCodePointCount, outCodePoints, outUnigramProbability); + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in getCodePointsAndProbabilityAndReturnCodePointCount()."); + } + return codePointCount; +} + +int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const int *const inWord, + const int length, const bool forceLowerCaseSearch) const { + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + const int ptNodePos = + readingHelper.getTerminalPtNodePositionOfWord(inWord, length, forceLowerCaseSearch); + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + } + return ptNodePos; +} + +int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, + const int bigramProbability) const { + if (mHeaderPolicy->isDecayingDict()) { + // Both probabilities are encoded. Decode them and get probability. + return ForgettingCurveUtils::getProbability(unigramProbability, bigramProbability); + } else { + if (unigramProbability == NOT_A_PROBABILITY) { + return NOT_A_PROBABILITY; + } else if (bigramProbability == NOT_A_PROBABILITY) { + return ProbabilityUtils::backoff(unigramProbability); + } else { + // bigramProbability is a bigram probability delta. + return ProbabilityUtils::computeProbabilityForBigram(unigramProbability, + bigramProbability); + } + } +} + +int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_PROBABILITY; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { + return NOT_A_PROBABILITY; + } + return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); +} + +int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_DICT_POS; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted()) { + return NOT_A_DICT_POS; + } + return mBuffers->getShortcutDictContent()->getShortcutListHeadPos( + ptNodeParams.getTerminalId()); +} + +int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_DICT_POS; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted()) { + return NOT_A_DICT_POS; + } + return mBuffers->getBigramDictContent()->getBigramListHeadPos( + ptNodeParams.getTerminalId()); +} + +bool Ver4PatriciaTriePolicy::addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length > MAX_WORD_LENGTH) { + AKLOGE("The word is too long to insert to the dictionary, length: %d", length); + return false; + } + for (const auto &shortcut : unigramProperty->getShortcuts()) { + if (shortcut.getTargetCodePoints()->size() > MAX_WORD_LENGTH) { + AKLOGE("One of shortcut targets is too long to insert to the dictionary, length: %d", + shortcut.getTargetCodePoints()->size()); + return false; + } + } + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + bool addedNewUnigram = false; + if (mUpdatingHelper.addUnigramWord(&readingHelper, word, length, + unigramProperty->getProbability(), unigramProperty->isNotAWord(), + unigramProperty->isBlacklisted(), unigramProperty->getTimestamp(), + &addedNewUnigram)) { + if (addedNewUnigram) { + mUnigramCount++; + } + if (unigramProperty->getShortcuts().size() > 0) { + // Add shortcut target. + const int wordPos = getTerminalPtNodePositionOfWord(word, length, + false /* forceLowerCaseSearch */); + if (wordPos == NOT_A_DICT_POS) { + AKLOGE("Cannot find terminal PtNode position to add shortcut target."); + return false; + } + for (const auto &shortcut : unigramProperty->getShortcuts()) { + if (!mUpdatingHelper.addShortcutTarget(wordPos, + shortcut.getTargetCodePoints()->data(), + shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) { + AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %d, " + "probability: %d", wordPos, shortcut.getTargetCodePoints()->size(), + shortcut.getProbability()); + return false; + } + } + } + return true; + } else { + return false; + } +} + +bool Ver4PatriciaTriePolicy::addBigramWords(const int *const word0, const int length0, + const int *const word1, const int length1, const int probability, + const int timestamp) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length0 > MAX_WORD_LENGTH || length1 > MAX_WORD_LENGTH) { + AKLOGE("Either src word or target word is too long to insert the bigram to the dictionary. " + "length0: %d, length1: %d", length0, length1); + return false; + } + const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0, + false /* forceLowerCaseSearch */); + if (word0Pos == NOT_A_DICT_POS) { + return false; + } + const int word1Pos = getTerminalPtNodePositionOfWord(word1, length1, + false /* forceLowerCaseSearch */); + if (word1Pos == NOT_A_DICT_POS) { + return false; + } + bool addedNewBigram = false; + if (mUpdatingHelper.addBigramWords(word0Pos, word1Pos, probability, timestamp, + &addedNewBigram)) { + if (addedNewBigram) { + mBigramCount++; + } + return true; + } else { + return false; + } +} + +bool Ver4PatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0, + const int *const word1, const int length1) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length0 > MAX_WORD_LENGTH || length1 > MAX_WORD_LENGTH) { + AKLOGE("Either src word or target word is too long to remove the bigram to from the " + "dictionary. length0: %d, length1: %d", length0, length1); + return false; + } + const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0, + false /* forceLowerCaseSearch */); + if (word0Pos == NOT_A_DICT_POS) { + return false; + } + const int word1Pos = getTerminalPtNodePositionOfWord(word1, length1, + false /* forceLowerCaseSearch */); + if (word1Pos == NOT_A_DICT_POS) { + return false; + } + if (mUpdatingHelper.removeBigramWords(word0Pos, word1Pos)) { + mBigramCount--; + return true; + } else { + return false; + } +} + +void Ver4PatriciaTriePolicy::flush(const char *const filePath) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: flush() is called for non-updatable dictionary. filePath: %s", filePath); + return; + } + if (!mWritingHelper.writeToDictFile(filePath, mUnigramCount, mBigramCount)) { + AKLOGE("Cannot flush the dictionary to file."); + mIsCorrupted = true; + } +} + +void Ver4PatriciaTriePolicy::flushWithGC(const char *const filePath) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary."); + return; + } + if (!mWritingHelper.writeToDictFileWithGC(getRootPosition(), filePath)) { + AKLOGE("Cannot flush the dictionary to file with GC."); + mIsCorrupted = true; + } +} + +bool Ver4PatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary."); + return false; + } + if (mBuffers->isNearSizeLimit()) { + // Additional buffer size is near the limit. + return true; + } else if (mHeaderPolicy->getExtendedRegionSize() + mDictBuffer->getUsedAdditionalBufferSize() + > Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE) { + // Total extended region size of the trie exceeds the limit. + return true; + } else if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS + && mDictBuffer->getUsedAdditionalBufferSize() > 0) { + // Needs to reduce dictionary size. + return true; + } else if (mHeaderPolicy->isDecayingDict()) { + return ForgettingCurveUtils::needsToDecay(mindsBlockByGC, mUnigramCount, mBigramCount, + mHeaderPolicy); + } + return false; +} + +void Ver4PatriciaTriePolicy::getProperty(const char *const query, const int queryLength, + char *const outResult, const int maxResultLength) { + const int compareLength = queryLength + 1 /* terminator */; + if (strncmp(query, UNIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", mUnigramCount); + } else if (strncmp(query, BIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", mBigramCount); + } else if (strncmp(query, MAX_UNIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", + mHeaderPolicy->isDecayingDict() ? + ForgettingCurveUtils::getUnigramCountHardLimit( + mHeaderPolicy->getMaxUnigramCount()) : + static_cast<int>(Ver4DictConstants::MAX_DICTIONARY_SIZE)); + } else if (strncmp(query, MAX_BIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", + mHeaderPolicy->isDecayingDict() ? + ForgettingCurveUtils::getBigramCountHardLimit( + mHeaderPolicy->getMaxBigramCount()) : + static_cast<int>(Ver4DictConstants::MAX_DICTIONARY_SIZE)); + } +} + +const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const codePoints, + const int codePointCount) const { + const int ptNodePos = getTerminalPtNodePositionOfWord(codePoints, codePointCount, + false /* forceLowerCaseSearch */); + if (ptNodePos == NOT_A_DICT_POS) { + AKLOGE("getWordProperty is called for invalid word."); + return WordProperty(); + } + const PtNodeParams ptNodeParams = mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + std::vector<int> codePointVector(ptNodeParams.getCodePoints(), + ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); + const ProbabilityEntry probabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + ptNodeParams.getTerminalId()); + const HistoricalInfo *const historicalInfo = probabilityEntry.getHistoricalInfo(); + // Fetch bigram information. + std::vector<BigramProperty> bigrams; + const int bigramListPos = getBigramsPositionOfPtNode(ptNodePos); + if (bigramListPos != NOT_A_DICT_POS) { + int bigramWord1CodePoints[MAX_WORD_LENGTH]; + const BigramDictContent *const bigramDictContent = mBuffers->getBigramDictContent(); + const TerminalPositionLookupTable *const terminalPositionLookupTable = + mBuffers->getTerminalPositionLookupTable(); + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const BigramEntry bigramEntry = + bigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + const int word1TerminalId = bigramEntry.getTargetTerminalId(); + const int word1TerminalPtNodePos = + terminalPositionLookupTable->getTerminalPtNodePosition(word1TerminalId); + if (word1TerminalPtNodePos == NOT_A_DICT_POS) { + continue; + } + // Word (unigram) probability + int word1Probability = NOT_A_PROBABILITY; + const int codePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + word1TerminalPtNodePos, MAX_WORD_LENGTH, bigramWord1CodePoints, + &word1Probability); + const std::vector<int> word1(bigramWord1CodePoints, + bigramWord1CodePoints + codePointCount); + const HistoricalInfo *const historicalInfo = bigramEntry.getHistoricalInfo(); + const int probability = bigramEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + bigramEntry.getHistoricalInfo(), mHeaderPolicy) : + getProbability(word1Probability, bigramEntry.getProbability()); + bigrams.emplace_back(&word1, probability, + historicalInfo->getTimeStamp(), historicalInfo->getLevel(), + historicalInfo->getCount()); + } + } + // Fetch shortcut information. + std::vector<UnigramProperty::ShortcutProperty> shortcuts; + int shortcutPos = getShortcutPositionOfPtNode(ptNodePos); + if (shortcutPos != NOT_A_DICT_POS) { + int shortcutTarget[MAX_WORD_LENGTH]; + const ShortcutDictContent *const shortcutDictContent = + mBuffers->getShortcutDictContent(); + bool hasNext = true; + while (hasNext) { + int shortcutTargetLength = 0; + int shortcutProbability = NOT_A_PROBABILITY; + shortcutDictContent->getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, shortcutTarget, + &shortcutTargetLength, &shortcutProbability, &hasNext, &shortcutPos); + const std::vector<int> target(shortcutTarget, shortcutTarget + shortcutTargetLength); + shortcuts.emplace_back(&target, shortcutProbability); + } + } + const UnigramProperty unigramProperty(ptNodeParams.isNotAWord(), + ptNodeParams.isBlacklisted(), ptNodeParams.getProbability(), + historicalInfo->getTimeStamp(), historicalInfo->getLevel(), + historicalInfo->getCount(), &shortcuts); + return WordProperty(&codePointVector, &unigramProperty, &bigrams); +} + +int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { + if (token == 0) { + mTerminalPtNodePositionsForIteratingWords.clear(); + DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions traversePolicy( + &mTerminalPtNodePositionsForIteratingWords); + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + readingHelper.traverseAllPtNodesInPostorderDepthFirstManner(&traversePolicy); + } + const int terminalPtNodePositionsVectorSize = + static_cast<int>(mTerminalPtNodePositionsForIteratingWords.size()); + if (token < 0 || token >= terminalPtNodePositionsVectorSize) { + AKLOGE("Given token %d is invalid.", token); + return 0; + } + const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; + int unigramProbability = NOT_A_PROBABILITY; + getCodePointsAndProbabilityAndReturnCodePointCount(terminalPtNodePos, MAX_WORD_LENGTH, + outCodePoints, &unigramProbability); + const int nextToken = token + 1; + if (nextToken >= terminalPtNodePositionsVectorSize) { + // All words have been iterated. + mTerminalPtNodePositionsForIteratingWords.clear(); + return 0; + } + return nextToken; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h new file mode 100644 index 000000000..8f981def5 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_POLICY_H +#define LATINIME_VER4_PATRICIA_TRIE_POLICY_H + +#include <vector> + +#include "defines.h" +#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +class DicNode; +class DicNodeVector; + +class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { + public: + Ver4PatriciaTriePolicy(Ver4DictBuffers::Ver4DictBuffersPtr buffers) + : mBuffers(std::move(buffers)), mHeaderPolicy(mBuffers->getHeaderPolicy()), + mDictBuffer(mBuffers->getWritableTrieBuffer()), + mBigramPolicy(mBuffers->getMutableBigramDictContent(), + mBuffers->getTerminalPositionLookupTable(), mHeaderPolicy), + mShortcutPolicy(mBuffers->getMutableShortcutDictContent(), + mBuffers->getTerminalPositionLookupTable()), + mNodeReader(mDictBuffer, mBuffers->getProbabilityDictContent(), mHeaderPolicy), + mPtNodeArrayReader(mDictBuffer), + mNodeWriter(mDictBuffer, mBuffers.get(), mHeaderPolicy, &mNodeReader, + &mPtNodeArrayReader, &mBigramPolicy, &mShortcutPolicy), + mUpdatingHelper(mDictBuffer, &mNodeReader, &mNodeWriter), + mWritingHelper(mBuffers.get()), + mUnigramCount(mHeaderPolicy->getUnigramCount()), + mBigramCount(mHeaderPolicy->getBigramCount()), + mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {}; + + AK_FORCE_INLINE int getRootPosition() const { + return 0; + } + + void createAndGetAllChildDicNodes(const DicNode *const dicNode, + DicNodeVector *const childDicNodes) const; + + int getCodePointsAndProbabilityAndReturnCodePointCount( + const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints, + int *const outUnigramProbability) const; + + int getTerminalPtNodePositionOfWord(const int *const inWord, + const int length, const bool forceLowerCaseSearch) const; + + int getProbability(const int unigramProbability, const int bigramProbability) const; + + int getUnigramProbabilityOfPtNode(const int ptNodePos) const; + + int getShortcutPositionOfPtNode(const int ptNodePos) const; + + int getBigramsPositionOfPtNode(const int ptNodePos) const; + + const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const { + return mHeaderPolicy; + } + + const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const { + return &mBigramPolicy; + } + + const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const { + return &mShortcutPolicy; + } + + bool addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty); + + bool addBigramWords(const int *const word0, const int length0, const int *const word1, + const int length1, const int probability, const int timestamp); + + bool removeBigramWords(const int *const word0, const int length0, const int *const word1, + const int length1); + + void flush(const char *const filePath); + + void flushWithGC(const char *const filePath); + + bool needsToRunGC(const bool mindsBlockByGC) const; + + void getProperty(const char *const query, const int queryLength, char *const outResult, + const int maxResultLength); + + const WordProperty getWordProperty(const int *const codePoints, + const int codePointCount) const; + + int getNextWordAndNextToken(const int token, int *const outCodePoints); + + bool isCorrupted() const { + return mIsCorrupted; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTriePolicy); + + static const char *const UNIGRAM_COUNT_QUERY; + static const char *const BIGRAM_COUNT_QUERY; + static const char *const MAX_UNIGRAM_COUNT_QUERY; + static const char *const MAX_BIGRAM_COUNT_QUERY; + // When the dictionary size is near the maximum size, we have to refuse dynamic operations to + // prevent the dictionary from overflowing. + static const int MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS; + static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS; + + const Ver4DictBuffers::Ver4DictBuffersPtr mBuffers; + const HeaderPolicy *const mHeaderPolicy; + BufferWithExtendableBuffer *const mDictBuffer; + Ver4BigramListPolicy mBigramPolicy; + Ver4ShortcutListPolicy mShortcutPolicy; + Ver4PatriciaTrieNodeReader mNodeReader; + Ver4PtNodeArrayReader mPtNodeArrayReader; + Ver4PatriciaTrieNodeWriter mNodeWriter; + DynamicPtUpdatingHelper mUpdatingHelper; + Ver4PatriciaTrieWritingHelper mWritingHelper; + int mUnigramCount; + int mBigramCount; + std::vector<int> mTerminalPtNodePositionsForIteratingWords; + mutable bool mIsCorrupted; +}; +} // namespace latinime +#endif // LATINIME_VER4_PATRICIA_TRIE_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp new file mode 100644 index 000000000..254022db4 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h" + +#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h" + +namespace latinime { + +/* static */ int Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition( + const uint8_t *const buffer, int *pos) { + return ByteArrayUtils::readUint32AndAdvancePosition(buffer, pos); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h new file mode 100644 index 000000000..466ff55d5 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_READING_UTILS_H +#define LATINIME_VER4_PATRICIA_TRIE_READING_UTILS_H + +#include <cstdint> + +#include "defines.h" + +namespace latinime { + +class BufferWithExtendableBuffer; + +class Ver4PatriciaTrieReadingUtils { + public: + static int getTerminalIdAndAdvancePosition(const uint8_t *const buffer, + int *const pos); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieReadingUtils); +}; +} // namespace latinime +#endif /* LATINIME_VER4_PATRICIA_TRIE_READING_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp new file mode 100644 index 000000000..12298d967 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h" + +#include <cstring> +#include <queue> + +#include "suggest/policyimpl/dictionary/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { + +bool Ver4PatriciaTrieWritingHelper::writeToDictFile(const char *const dictDirPath, + const int unigramCount, const int bigramCount) const { + const HeaderPolicy *const headerPolicy = mBuffers->getHeaderPolicy(); + BufferWithExtendableBuffer headerBuffer( + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); + const int extendedRegionSize = headerPolicy->getExtendedRegionSize() + + mBuffers->getTrieBuffer()->getUsedAdditionalBufferSize(); + if (!headerPolicy->fillInAndWriteHeaderToBuffer(false /* updatesLastDecayedTime */, + unigramCount, bigramCount, extendedRegionSize, &headerBuffer)) { + AKLOGE("Cannot write header structure to buffer. " + "updatesLastDecayedTime: %d, unigramCount: %d, bigramCount: %d, " + "extendedRegionSize: %d", false, unigramCount, bigramCount, + extendedRegionSize); + return false; + } + return mBuffers->flushHeaderAndDictBuffers(dictDirPath, &headerBuffer); +} + +bool Ver4PatriciaTrieWritingHelper::writeToDictFileWithGC(const int rootPtNodeArrayPos, + const char *const dictDirPath) { + const HeaderPolicy *const headerPolicy = mBuffers->getHeaderPolicy(); + Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers( + Ver4DictBuffers::createVer4DictBuffers(headerPolicy, + Ver4DictConstants::MAX_DICTIONARY_SIZE)); + int unigramCount = 0; + int bigramCount = 0; + if (!runGC(rootPtNodeArrayPos, headerPolicy, dictBuffers.get(), &unigramCount, &bigramCount)) { + return false; + } + BufferWithExtendableBuffer headerBuffer( + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); + if (!headerPolicy->fillInAndWriteHeaderToBuffer(true /* updatesLastDecayedTime */, + unigramCount, bigramCount, 0 /* extendedRegionSize */, &headerBuffer)) { + return false; + } + return dictBuffers->flushHeaderAndDictBuffers(dictDirPath, &headerBuffer); +} + +bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos, + const HeaderPolicy *const headerPolicy, Ver4DictBuffers *const buffersToWrite, + int *const outUnigramCount, int *const outBigramCount) { + Ver4PatriciaTrieNodeReader ptNodeReader(mBuffers->getTrieBuffer(), + mBuffers->getProbabilityDictContent(), headerPolicy); + Ver4PtNodeArrayReader ptNodeArrayReader(mBuffers->getTrieBuffer()); + Ver4BigramListPolicy bigramPolicy(mBuffers->getMutableBigramDictContent(), + mBuffers->getTerminalPositionLookupTable(), headerPolicy); + Ver4ShortcutListPolicy shortcutPolicy(mBuffers->getMutableShortcutDictContent(), + mBuffers->getTerminalPositionLookupTable()); + Ver4PatriciaTrieNodeWriter ptNodeWriter(mBuffers->getWritableTrieBuffer(), + mBuffers, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &bigramPolicy, + &shortcutPolicy); + + DynamicPtReadingHelper readingHelper(&ptNodeReader, &ptNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners + ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted + traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted( + &ptNodeWriter); + if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted)) { + return false; + } + const int unigramCount = traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted + .getValidUnigramCount(); + const int maxUnigramCount = headerPolicy->getMaxUnigramCount(); + if (headerPolicy->isDecayingDict() && unigramCount > maxUnigramCount) { + if (!truncateUnigrams(&ptNodeReader, &ptNodeWriter, maxUnigramCount)) { + AKLOGE("Cannot remove unigrams. current: %d, max: %d", unigramCount, + maxUnigramCount); + return false; + } + } + + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners::TraversePolicyToUpdateBigramProbability + traversePolicyToUpdateBigramProbability(&ptNodeWriter); + if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateBigramProbability)) { + return false; + } + const int bigramCount = traversePolicyToUpdateBigramProbability.getValidBigramEntryCount(); + const int maxBigramCount = headerPolicy->getMaxBigramCount(); + if (headerPolicy->isDecayingDict() && bigramCount > maxBigramCount) { + if (!truncateBigrams(maxBigramCount)) { + AKLOGE("Cannot remove bigrams. current: %d, max: %d", bigramCount, maxBigramCount); + return false; + } + } + + // Mapping from positions in mBuffer to positions in bufferToWrite. + PtNodeWriter::DictPositionRelocationMap dictPositionRelocationMap; + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + Ver4PatriciaTrieNodeWriter ptNodeWriterForNewBuffers(buffersToWrite->getWritableTrieBuffer(), + buffersToWrite, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &bigramPolicy, + &shortcutPolicy); + DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer + traversePolicyToPlaceAndWriteValidPtNodesToBuffer(&ptNodeWriterForNewBuffers, + buffersToWrite->getWritableTrieBuffer(), &dictPositionRelocationMap); + if (!readingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + &traversePolicyToPlaceAndWriteValidPtNodesToBuffer)) { + return false; + } + + // Create policy instances for the GCed dictionary. + Ver4PatriciaTrieNodeReader newPtNodeReader(buffersToWrite->getTrieBuffer(), + buffersToWrite->getProbabilityDictContent(), headerPolicy); + Ver4PtNodeArrayReader newPtNodeArrayreader(buffersToWrite->getTrieBuffer()); + Ver4BigramListPolicy newBigramPolicy(buffersToWrite->getMutableBigramDictContent(), + buffersToWrite->getTerminalPositionLookupTable(), headerPolicy); + Ver4ShortcutListPolicy newShortcutPolicy(buffersToWrite->getMutableShortcutDictContent(), + buffersToWrite->getTerminalPositionLookupTable()); + Ver4PatriciaTrieNodeWriter newPtNodeWriter(buffersToWrite->getWritableTrieBuffer(), + buffersToWrite, headerPolicy, &newPtNodeReader, &newPtNodeArrayreader, &newBigramPolicy, + &newShortcutPolicy); + // Re-assign terminal IDs for valid terminal PtNodes. + TerminalPositionLookupTable::TerminalIdMap terminalIdMap; + if(!buffersToWrite->getMutableTerminalPositionLookupTable()->runGCTerminalIds( + &terminalIdMap)) { + return false; + } + // Run GC for probability dict content. + if (!buffersToWrite->getMutableProbabilityDictContent()->runGC(&terminalIdMap, + mBuffers->getProbabilityDictContent())) { + return false; + } + // Run GC for bigram dict content. + if(!buffersToWrite->getMutableBigramDictContent()->runGC(&terminalIdMap, + mBuffers->getBigramDictContent(), outBigramCount)) { + return false; + } + // Run GC for shortcut dict content. + if(!buffersToWrite->getMutableShortcutDictContent()->runGC(&terminalIdMap, + mBuffers->getShortcutDictContent())) { + return false; + } + DynamicPtReadingHelper newDictReadingHelper(&newPtNodeReader, &newPtNodeArrayreader); + newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners::TraversePolicyToUpdateAllPositionFields + traversePolicyToUpdateAllPositionFields(&newPtNodeWriter, &dictPositionRelocationMap); + if (!newDictReadingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + &traversePolicyToUpdateAllPositionFields)) { + return false; + } + newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + traversePolicyToUpdateAllPtNodeFlagsAndTerminalIds(&newPtNodeWriter, &terminalIdMap); + if (!newDictReadingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateAllPtNodeFlagsAndTerminalIds)) { + return false; + } + *outUnigramCount = traversePolicyToUpdateAllPositionFields.getUnigramCount(); + return true; +} + +bool Ver4PatriciaTrieWritingHelper::truncateUnigrams( + const Ver4PatriciaTrieNodeReader *const ptNodeReader, + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, const int maxUnigramCount) { + const TerminalPositionLookupTable *const terminalPosLookupTable = + mBuffers->getTerminalPositionLookupTable(); + const int nextTerminalId = terminalPosLookupTable->getNextTerminalId(); + std::priority_queue<DictProbability, std::vector<DictProbability>, DictProbabilityComparator> + priorityQueue; + for (int i = 0; i < nextTerminalId; ++i) { + const int terminalPos = terminalPosLookupTable->getTerminalPtNodePosition(i); + if (terminalPos == NOT_A_DICT_POS) { + continue; + } + const ProbabilityEntry probabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry(i); + const int probability = probabilityEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + probabilityEntry.getHistoricalInfo(), mBuffers->getHeaderPolicy()) : + probabilityEntry.getProbability(); + priorityQueue.push(DictProbability(terminalPos, probability, + probabilityEntry.getHistoricalInfo()->getTimeStamp())); + } + + // Delete unigrams. + while (static_cast<int>(priorityQueue.size()) > maxUnigramCount) { + const int ptNodePos = priorityQueue.top().getDictPos(); + const PtNodeParams ptNodeParams = + ptNodeReader->fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + if (!ptNodeWriter->markPtNodeAsWillBecomeNonTerminal(&ptNodeParams)) { + AKLOGE("Cannot mark PtNode as willBecomeNonterminal. PtNode pos: %d", ptNodePos); + return false; + } + priorityQueue.pop(); + } + return true; +} + +bool Ver4PatriciaTrieWritingHelper::truncateBigrams(const int maxBigramCount) { + const TerminalPositionLookupTable *const terminalPosLookupTable = + mBuffers->getTerminalPositionLookupTable(); + const int nextTerminalId = terminalPosLookupTable->getNextTerminalId(); + std::priority_queue<DictProbability, std::vector<DictProbability>, DictProbabilityComparator> + priorityQueue; + BigramDictContent *const bigramDictContent = mBuffers->getMutableBigramDictContent(); + for (int i = 0; i < nextTerminalId; ++i) { + const int bigramListPos = bigramDictContent->getBigramListHeadPos(i); + if (bigramListPos == NOT_A_DICT_POS) { + continue; + } + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + bigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!bigramEntry.isValid()) { + continue; + } + const int probability = bigramEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + bigramEntry.getHistoricalInfo(), mBuffers->getHeaderPolicy()) : + bigramEntry.getProbability(); + priorityQueue.push(DictProbability(entryPos, probability, + bigramEntry.getHistoricalInfo()->getTimeStamp())); + } + } + + // Delete bigrams. + while (static_cast<int>(priorityQueue.size()) > maxBigramCount) { + const int entryPos = priorityQueue.top().getDictPos(); + const BigramEntry bigramEntry = bigramDictContent->getBigramEntry(entryPos); + const BigramEntry invalidatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!bigramDictContent->writeBigramEntry(&invalidatedBigramEntry, entryPos)) { + AKLOGE("Cannot write bigram entry to remove. pos: %d", entryPos); + return false; + } + priorityQueue.pop(); + } + return true; +} + +bool Ver4PatriciaTrieWritingHelper::TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + if (!ptNodeParams->isTerminal()) { + return true; + } + TerminalPositionLookupTable::TerminalIdMap::const_iterator it = + mTerminalIdMap->find(ptNodeParams->getTerminalId()); + if (it == mTerminalIdMap->end()) { + AKLOGE("terminal Id %d is not in the terminal position map. map size: %zd", + ptNodeParams->getTerminalId(), mTerminalIdMap->size()); + return false; + } + if (!mPtNodeWriter->updateTerminalId(ptNodeParams, it->second)) { + AKLOGE("Cannot update terminal id. %d -> %d", it->first, it->second); + } + return mPtNodeWriter->updatePtNodeHasBigramsAndShortcutTargetsFlags(ptNodeParams); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h new file mode 100644 index 000000000..bb464ad28 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013, 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_VER4_PATRICIA_TRIE_WRITING_HELPER_H +#define LATINIME_VER4_PATRICIA_TRIE_WRITING_HELPER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h" +#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h" + +namespace latinime { + +class HeaderPolicy; +class Ver4DictBuffers; +class Ver4PatriciaTrieNodeReader; +class Ver4PatriciaTrieNodeWriter; + +class Ver4PatriciaTrieWritingHelper { + public: + Ver4PatriciaTrieWritingHelper(Ver4DictBuffers *const buffers) + : mBuffers(buffers) {} + + bool writeToDictFile(const char *const dictDirPath, const int unigramCount, + const int bigramCount) const; + + // This method cannot be const because the original dictionary buffer will be updated to detect + // useless PtNodes during GC. + bool writeToDictFileWithGC(const int rootPtNodeArrayPos, const char *const dictDirPath); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieWritingHelper); + + class TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + : public DynamicPtReadingHelper::TraversingEventListener { + public: + TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds( + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap) + : mPtNodeWriter(ptNodeWriter), mTerminalIdMap(terminalIdMap) {} + + bool onAscend() { return true; } + + bool onDescend(const int ptNodeArrayPos) { return true; } + + bool onReadingPtNodeArrayTail() { return true; } + + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds); + + Ver4PatriciaTrieNodeWriter *const mPtNodeWriter; + const TerminalPositionLookupTable::TerminalIdMap *const mTerminalIdMap; + }; + + // For truncateUnigrams() and truncateBigrams(). + class DictProbability { + public: + DictProbability(const int dictPos, const int probability, const int timestamp) + : mDictPos(dictPos), mProbability(probability), mTimestamp(timestamp) {} + + int getDictPos() const { + return mDictPos; + } + + int getProbability() const { + return mProbability; + } + + int getTimestamp() const { + return mTimestamp; + } + + private: + DISALLOW_DEFAULT_CONSTRUCTOR(DictProbability); + + int mDictPos; + int mProbability; + int mTimestamp; + }; + + // For truncateUnigrams() and truncateBigrams(). + class DictProbabilityComparator { + public: + bool operator()(const DictProbability &left, const DictProbability &right) { + if (left.getProbability() != right.getProbability()) { + return left.getProbability() > right.getProbability(); + } + if (left.getTimestamp() != right.getTimestamp()) { + return left.getTimestamp() < right.getTimestamp(); + } + return left.getDictPos() > right.getDictPos(); + } + + private: + DISALLOW_ASSIGNMENT_OPERATOR(DictProbabilityComparator); + }; + + bool runGC(const int rootPtNodeArrayPos, const HeaderPolicy *const headerPolicy, + Ver4DictBuffers *const buffersToWrite, int *const outUnigramCount, + int *const outBigramCount); + + bool truncateUnigrams(const Ver4PatriciaTrieNodeReader *const ptNodeReader, + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, const int maxUnigramCount); + + bool truncateBigrams(const int maxBigramCount); + + Ver4DictBuffers *const mBuffers; +}; +} // namespace latinime + +#endif /* LATINIME_VER4_PATRICIA_TRIE_WRITING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.cpp new file mode 100644 index 000000000..b014c523d --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014, 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. + */ + +#include "suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +bool Ver4PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const { + if (ptNodeArrayPos < 0 || ptNodeArrayPos >= mBuffer->getTailPosition()) { + // Reading invalid position because of a bug or a broken dictionary. + AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d", + ptNodeArrayPos, mBuffer->getTailPosition()); + ASSERT(false); + return false; + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodeArrayPos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int readingPos = ptNodeArrayPos; + if (usesAdditionalBuffer) { + readingPos -= mBuffer->getOriginalBufferSize(); + } + const int ptNodeCountInArray = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition( + dictBuf, &readingPos); + if (usesAdditionalBuffer) { + readingPos += mBuffer->getOriginalBufferSize(); + } + if (ptNodeCountInArray < 0) { + AKLOGE("Invalid PtNode count in an array: %d.", ptNodeCountInArray); + return false; + } + *outPtNodeCount = ptNodeCountInArray; + *outFirstPtNodePos = readingPos; + return true; +} + +bool Ver4PtNodeArrayReader::readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const { + if (forwordLinkPos < 0 || forwordLinkPos >= mBuffer->getTailPosition()) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d", + forwordLinkPos, mBuffer->getTailPosition()); + ASSERT(false); + return false; + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(forwordLinkPos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int readingPos = forwordLinkPos; + if (usesAdditionalBuffer) { + readingPos -= mBuffer->getOriginalBufferSize(); + } + const int nextPtNodeArrayOffset = + DynamicPtReadingUtils::getForwardLinkPosition(dictBuf, readingPos); + if (DynamicPtReadingUtils::isValidForwardLinkPosition(nextPtNodeArrayOffset)) { + *outNextPtNodeArrayPos = forwordLinkPos + nextPtNodeArrayOffset; + } else { + *outNextPtNodeArrayPos = NOT_A_DICT_POS; + } + return true; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h new file mode 100644 index 000000000..d81808efc --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014, 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_VER4_PT_NODE_ARRAY_READER_H +#define LATINIME_VER4_PT_NODE_ARRAY_READER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h" + +namespace latinime { + +class BufferWithExtendableBuffer; + +class Ver4PtNodeArrayReader : public PtNodeArrayReader { + public: + Ver4PtNodeArrayReader(const BufferWithExtendableBuffer *const buffer) : mBuffer(buffer) {}; + + virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const; + virtual bool readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PtNodeArrayReader); + + const BufferWithExtendableBuffer *const mBuffer; +}; +} // namespace latinime +#endif /* LATINIME_VER4_PT_NODE_ARRAY_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp index f692882f2..259dae4c6 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp @@ -18,11 +18,42 @@ namespace latinime { -const size_t BufferWithExtendableBuffer::MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024; +const size_t BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024; const int BufferWithExtendableBuffer::NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE = 90; // TODO: Needs to allocate larger memory corresponding to the current vector size. const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024; +uint32_t BufferWithExtendableBuffer::readUint(const int size, const int pos) const { + const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(pos); + const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBufferSize : pos; + return ByteArrayUtils::readUint(getBuffer(readingPosIsInAdditionalBuffer), size, posInBuffer); +} + +uint32_t BufferWithExtendableBuffer::readUintAndAdvancePosition(const int size, + int *const pos) const { + const int value = readUint(size, *pos); + *pos += size; + return value; +} + +void BufferWithExtendableBuffer::readCodePointsAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoints, int *outCodePointCount, int *const pos) const { + const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(*pos); + if (readingPosIsInAdditionalBuffer) { + *pos -= mOriginalBufferSize; + } + *outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition( + getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos); + if (readingPosIsInAdditionalBuffer) { + *pos += mOriginalBufferSize; + } +} + +bool BufferWithExtendableBuffer::writeUint(const uint32_t data, const int size, const int pos) { + int writingPos = pos; + return writeUintAndAdvancePosition(data, size, &writingPos); +} + bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size, int *const pos) { if (!(size >= 1 && size <= 4)) { @@ -46,7 +77,7 @@ bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data } bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *const codePoints, - const int codePointCount, const bool writesTerminator ,int *const pos) { + const int codePointCount, const bool writesTerminator, int *const pos) { const size_t size = ByteArrayUtils::calculateRequiredByteCountToStoreCodePoints( codePoints, codePointCount, writesTerminator); if (!checkAndPrepareWriting(*pos, size)) { @@ -100,4 +131,21 @@ bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int return true; } +bool BufferWithExtendableBuffer::copy(const BufferWithExtendableBuffer *const sourceBuffer) { + int copyingPos = 0; + const int tailPos = sourceBuffer->getTailPosition(); + const int maxDataChunkSize = sizeof(uint32_t); + while (copyingPos < tailPos) { + const int remainingSize = tailPos - copyingPos; + const int copyingSize = (remainingSize >= maxDataChunkSize) ? + maxDataChunkSize : remainingSize; + const uint32_t data = sourceBuffer->readUint(copyingSize, copyingPos); + if (!writeUint(data, copyingSize, copyingPos)) { + return false; + } + copyingPos += copyingSize; + } + return true; +} + } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h index 9dc34823c..23cbe3aa3 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h @@ -18,7 +18,7 @@ #define LATINIME_BUFFER_WITH_EXTENDABLE_BUFFER_H #include <cstddef> -#include <stdint.h> +#include <cstdint> #include <vector> #include "defines.h" @@ -32,12 +32,20 @@ namespace latinime { // raw pointer but provides several methods that handle boundary checking for writing data. class BufferWithExtendableBuffer { public: + static const size_t DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE; + BufferWithExtendableBuffer(uint8_t *const originalBuffer, const int originalBufferSize, - const int maxAdditionalBufferSize = MAX_ADDITIONAL_BUFFER_SIZE) + const int maxAdditionalBufferSize) : mOriginalBuffer(originalBuffer), mOriginalBufferSize(originalBufferSize), mAdditionalBuffer(EXTEND_ADDITIONAL_BUFFER_SIZE_STEP), mUsedAdditionalBufferSize(0), mMaxAdditionalBufferSize(maxAdditionalBufferSize) {} + // Without original buffer. + BufferWithExtendableBuffer(const int maxAdditionalBufferSize) + : mOriginalBuffer(0), mOriginalBufferSize(0), + mAdditionalBuffer(EXTEND_ADDITIONAL_BUFFER_SIZE_STEP), mUsedAdditionalBufferSize(0), + mMaxAdditionalBufferSize(maxAdditionalBufferSize) {} + AK_FORCE_INLINE int getTailPosition() const { return mOriginalBufferSize + mUsedAdditionalBufferSize; } @@ -63,6 +71,13 @@ class BufferWithExtendableBuffer { } } + uint32_t readUint(const int size, const int pos) const; + + uint32_t readUintAndAdvancePosition(const int size, int *const pos) const; + + void readCodePointsAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoints, int *outCodePointCount, int *const pos) const; + AK_FORCE_INLINE int getOriginalBufferSize() const { return mOriginalBufferSize; } @@ -78,15 +93,18 @@ class BufferWithExtendableBuffer { * Writing is allowed for original buffer, already written region of additional buffer and the * tail of additional buffer. */ + bool writeUint(const uint32_t data, const int size, const int pos); + bool writeUintAndAdvancePosition(const uint32_t data, const int size, int *const pos); bool writeCodePointsAndAdvancePosition(const int *const codePoints, const int codePointCount, const bool writesTerminator, int *const pos); + bool copy(const BufferWithExtendableBuffer *const sourceBuffer); + private: DISALLOW_COPY_AND_ASSIGN(BufferWithExtendableBuffer); - static const size_t MAX_ADDITIONAL_BUFFER_SIZE; static const int NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE; static const size_t EXTEND_ADDITIONAL_BUFFER_SIZE_STEP; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h index 0c1576818..c0a9fcb1d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h @@ -17,7 +17,7 @@ #ifndef LATINIME_BYTE_ARRAY_UTILS_H #define LATINIME_BYTE_ARRAY_UTILS_H -#include <stdint.h> +#include <cstdint> #include "defines.h" @@ -114,6 +114,24 @@ class ByteArrayUtils { return buffer[(*pos)++]; } + static AK_FORCE_INLINE int readUint(const uint8_t *const buffer, + const int size, const int pos) { + // size must be in 1 to 4. + ASSERT(size >= 1 && size <= 4); + switch (size) { + case 1: + return ByteArrayUtils::readUint8(buffer, pos); + case 2: + return ByteArrayUtils::readUint16(buffer, pos); + case 3: + return ByteArrayUtils::readUint24(buffer, pos); + case 4: + return ByteArrayUtils::readUint32(buffer, pos); + default: + return 0; + } + } + /** * Code Point Reading * diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp index 994826fa8..87fa5994c 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp @@ -17,73 +17,99 @@ #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" #include <cstdio> -#include <cstring> #include "suggest/policyimpl/dictionary/header/header_policy.h" -#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h" #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" #include "suggest/policyimpl/dictionary/utils/format_utils.h" +#include "utils/time_keeper.h" namespace latinime { const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = ".tmp"; /* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath, - const int dictVersion, const HeaderReadWriteUtils::AttributeMap *const attributeMap) { + const int dictVersion, const std::vector<int> localeAsCodePointVector, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { + TimeKeeper::setCurrentTime(); switch (dictVersion) { - case 3: - return createEmptyV3DictFile(filePath, attributeMap); + case FormatUtils::VERSION_4: + return createEmptyV4DictFile(filePath, localeAsCodePointVector, attributeMap); default: - // Only version 3 dictionary is supported for now. + AKLOGE("Cannot create dictionary %s because format version %d is not supported.", + filePath, dictVersion); return false; } } -/* static */ bool DictFileWritingUtils::createEmptyV3DictFile(const char *const filePath, - const HeaderReadWriteUtils::AttributeMap *const attributeMap) { - BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); - HeaderPolicy headerPolicy(FormatUtils::VERSION_3, attributeMap); - headerPolicy.writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */, - true /* updatesLastDecayedTime */, 0 /* unigramCount */, 0 /* bigramCount */, - 0 /* extendedRegionSize */); - BufferWithExtendableBuffer bodyBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */); - if (!DynamicPatriciaTrieWritingUtils::writeEmptyDictionary(&bodyBuffer, 0 /* rootPos */)) { +/* static */ bool DictFileWritingUtils::createEmptyV4DictFile(const char *const dirPath, + const std::vector<int> localeAsCodePointVector, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) { + HeaderPolicy headerPolicy(FormatUtils::VERSION_4, localeAsCodePointVector, attributeMap); + Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers( + Ver4DictBuffers::createVer4DictBuffers(&headerPolicy, + Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE)); + headerPolicy.fillInAndWriteHeaderToBuffer(true /* updatesLastDecayedTime */, + 0 /* unigramCount */, 0 /* bigramCount */, + 0 /* extendedRegionSize */, dictBuffers->getWritableHeaderBuffer()); + if (!DynamicPtWritingUtils::writeEmptyDictionary( + dictBuffers->getWritableTrieBuffer(), 0 /* rootPos */)) { + AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); return false; } - return flushAllHeaderAndBodyToFile(filePath, &headerBuffer, &bodyBuffer); + return dictBuffers->flush(dirPath); } /* static */ bool DictFileWritingUtils::flushAllHeaderAndBodyToFile(const char *const filePath, BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody) { - const int tmpFileNameBufSize = strlen(filePath) - + strlen(TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE) + 1 /* terminator */; + const int tmpFileNameBufSize = FileUtils::getFilePathWithSuffixBufSize(filePath, + TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); // Name of a temporary file used for writing that is a connected string of original name and // TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE. char tmpFileName[tmpFileNameBufSize]; - snprintf(tmpFileName, tmpFileNameBufSize, "%s%s", filePath, - TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); - FILE *const file = fopen(tmpFileName, "wb"); - if (!file) { - AKLOGE("Dictionary file %s cannnot be opened.", tmpFileName); - ASSERT(false); + FileUtils::getFilePathWithSuffix(filePath, TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE, + tmpFileNameBufSize, tmpFileName); + if (!DictFileWritingUtils::flushBufferToFile(tmpFileName, dictHeader)) { + AKLOGE("Dictionary header cannot be written to %s.", tmpFileName); + return false; + } + if (!DictFileWritingUtils::flushBufferToFile(tmpFileName, dictBody)) { + AKLOGE("Dictionary structure cannot be written to %s.", tmpFileName); + return false; + } + if (rename(tmpFileName, filePath) != 0) { + AKLOGE("Dictionary file %s cannot be renamed to %s", tmpFileName, filePath);; return false; } - // Write the dictionary header. - if (!writeBufferToFile(file, dictHeader)) { - remove(tmpFileName); - AKLOGE("Dictionary header cannnot be written. size: %d", dictHeader->getTailPosition()); + return true; +} + +/* static */ bool DictFileWritingUtils::flushBufferToFileWithSuffix(const char *const basePath, + const char *const suffix, const BufferWithExtendableBuffer *const buffer) { + const int filePathBufSize = FileUtils::getFilePathWithSuffixBufSize(basePath, suffix); + char filePath[filePathBufSize]; + FileUtils::getFilePathWithSuffix(basePath, suffix, filePathBufSize, filePath); + return flushBufferToFile(filePath, buffer); +} + +/* static */ bool DictFileWritingUtils::flushBufferToFile(const char *const filePath, + const BufferWithExtendableBuffer *const buffer) { + FILE *const file = fopen(filePath, "wb"); + if (!file) { + AKLOGE("File %s cannot be opened.", filePath); ASSERT(false); return false; } - // Write the dictionary body. - if (!writeBufferToFile(file, dictBody)) { - remove(tmpFileName); - AKLOGE("Dictionary body cannnot be written. size: %d", dictBody->getTailPosition()); + if (!writeBufferToFile(file, buffer)) { + remove(filePath); + AKLOGE("Buffer cannot be written to the file %s. size: %d", filePath, + buffer->getTailPosition()); ASSERT(false); return false; } fclose(file); - rename(tmpFileName, filePath); return true; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h index bd4ac66fd..54ec651f7 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h @@ -28,20 +28,28 @@ class BufferWithExtendableBuffer; class DictFileWritingUtils { public: + static const char *const TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE; + static bool createEmptyDictFile(const char *const filePath, const int dictVersion, - const HeaderReadWriteUtils::AttributeMap *const attributeMap); + const std::vector<int> localeAsCodePointVector, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap); static bool flushAllHeaderAndBodyToFile(const char *const filePath, BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody); + static bool flushBufferToFileWithSuffix(const char *const basePath, const char *const suffix, + const BufferWithExtendableBuffer *const buffer); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(DictFileWritingUtils); - static const char *const TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE; + static bool createEmptyV4DictFile(const char *const filePath, + const std::vector<int> localeAsCodePointVector, + const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap); - static bool createEmptyV3DictFile(const char *const filePath, - const HeaderReadWriteUtils::AttributeMap *const attributeMap); + static bool flushBufferToFile(const char *const filePath, + const BufferWithExtendableBuffer *const buffer); static bool writeBufferToFile(FILE *const file, const BufferWithExtendableBuffer *const buffer); diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp new file mode 100644 index 000000000..fb80f38c5 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/utils/file_utils.h" + +#include <cstdio> +#include <cstring> +#include <dirent.h> +#include <fcntl.h> +#include <libgen.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +namespace latinime { + +// Returns -1 on error. +/* static */ int FileUtils::getFileSize(const char *const filePath) { + const int fd = open(filePath, O_RDONLY); + if (fd == -1) { + return -1; + } + struct stat statBuf; + if (fstat(fd, &statBuf) != 0) { + close(fd); + return -1; + } + close(fd); + return static_cast<int>(statBuf.st_size); +} + +/* static */ bool FileUtils::existsDir(const char *const dirPath) { + DIR *const dir = opendir(dirPath); + if (dir == NULL) { + return false; + } + closedir(dir); + return true; +} + +// Remove a directory and all files in the directory. +/* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath) { + return removeDirAndFiles(dirPath, 5 /* maxTries */); +} + +// Remove a directory and all files in the directory, trying up to maxTimes. +/* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath, const int maxTries) { + DIR *const dir = opendir(dirPath); + if (dir == NULL) { + AKLOGE("Cannot open dir %s.", dirPath); + return true; + } + struct dirent *dirent; + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_type == DT_DIR) { + continue; + } + if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { + continue; + } + const int filePathBufSize = getFilePathBufSize(dirPath, dirent->d_name); + char filePath[filePathBufSize]; + getFilePath(dirPath, dirent->d_name, filePathBufSize, filePath); + if (remove(filePath) != 0) { + AKLOGE("Cannot remove file %s.", filePath); + closedir(dir); + return false; + } + } + closedir(dir); + if (remove(dirPath) != 0) { + if (maxTries > 0) { + // On NFS, deleting files sometimes creates new files. I'm not sure what the + // correct way of dealing with this is, but for the time being, this seems to work. + removeDirAndFiles(dirPath, maxTries - 1); + } else { + AKLOGE("Cannot remove directory %s.", dirPath); + return false; + } + } + return true; +} + +/* static */ int FileUtils::getFilePathWithSuffixBufSize(const char *const filePath, + const char *const suffix) { + return strlen(filePath) + strlen(suffix) + 1 /* terminator */; +} + +/* static */ void FileUtils::getFilePathWithSuffix(const char *const filePath, + const char *const suffix, const int filePathBufSize, char *const outFilePath) { + snprintf(outFilePath, filePathBufSize, "%s%s", filePath, suffix); +} + +/* static */ int FileUtils::getFilePathBufSize(const char *const dirPath, + const char *const fileName) { + return strlen(dirPath) + 1 /* '/' */ + strlen(fileName) + 1 /* terminator */; +} + +/* static */ void FileUtils::getFilePath(const char *const dirPath, const char *const fileName, + const int filePathBufSize, char *const outFilePath) { + snprintf(outFilePath, filePathBufSize, "%s/%s", dirPath, fileName); +} + +/* static */ bool FileUtils::getFilePathWithoutSuffix(const char *const filePath, + const char *const suffix, const int outDirPathBufSize, char *const outDirPath) { + const int filePathLength = strlen(filePath); + const int suffixLength = strlen(suffix); + if (filePathLength <= suffixLength) { + AKLOGE("File path length (%s:%d) is shorter that suffix length (%s:%d).", + filePath, filePathLength, suffix, suffixLength); + return false; + } + const int resultFilePathLength = filePathLength - suffixLength; + if (outDirPathBufSize <= resultFilePathLength) { + AKLOGE("outDirPathBufSize is too small. filePath: %s, suffix: %s, outDirPathBufSize: %d", + filePath, suffix, outDirPathBufSize); + return false; + } + if (strncmp(filePath + resultFilePathLength, suffix, suffixLength) != 0) { + AKLOGE("File Path %s does not have %s as a suffix", filePath, suffix); + return false; + } + snprintf(outDirPath, resultFilePathLength + 1 /* terminator */, "%s", filePath); + return true; +} + +/* static */ void FileUtils::getDirPath(const char *const filePath, const int outDirPathBufSize, + char *const outDirPath) { + for (int i = strlen(filePath) - 1; i >= 0; --i) { + if (filePath[i] == '/') { + if (i >= outDirPathBufSize) { + AKLOGE("outDirPathBufSize is too small. filePath: %s, outDirPathBufSize: %d", + filePath, outDirPathBufSize); + ASSERT(false); + return; + } + snprintf(outDirPath, i + 1 /* terminator */, "%s", filePath); + return; + } + } +} + +/* static */ void FileUtils::getBasename(const char *const filePath, + const int outNameBufSize, char *const outName) { + const int filePathBufSize = strlen(filePath) + 1 /* terminator */; + char filePathBuf[filePathBufSize]; + snprintf(filePathBuf, filePathBufSize, "%s", filePath); + const char *const baseName = basename(filePathBuf); + const int baseNameLength = strlen(baseName); + if (baseNameLength >= outNameBufSize) { + AKLOGE("outNameBufSize is too small. filePath: %s, outNameBufSize: %d", + filePath, outNameBufSize); + return; + } + snprintf(outName, baseNameLength + 1 /* terminator */, "%s", baseName); +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h new file mode 100644 index 000000000..4f1b93a6a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013, 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_FILE_UTILS_H +#define LATINIME_FILE_UTILS_H + +#include "defines.h" + +namespace latinime { + +class FileUtils { + public: + // Returns -1 on error. + static int getFileSize(const char *const filePath); + + static bool existsDir(const char *const dirPath); + + // Remove a directory and all files in the directory. + static bool removeDirAndFiles(const char *const dirPath); + + static int getFilePathWithSuffixBufSize(const char *const filePath, const char *const suffix); + + static void getFilePathWithSuffix(const char *const filePath, const char *const suffix, + const int filePathBufSize, char *const outFilePath); + + static int getFilePathBufSize(const char *const dirPath, const char *const fileName); + + static void getFilePath(const char *const dirPath, const char *const fileName, + const int filePathBufSize, char *const outFilePath); + + // Returns whether the filePath have the suffix. + static bool getFilePathWithoutSuffix(const char *const filePath, const char *const suffix, + const int dirPathBufSize, char *const outDirPath); + + static void getDirPath(const char *const filePath, const int dirPathBufSize, + char *const outDirPath); + + static void getBasename(const char *const filePath, const int outNameBufSize, + char *const outName); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtils); + + static bool removeDirAndFiles(const char *const dirPath, const int maxTries); +}; +} // namespace latinime +#endif /* LATINIME_FILE_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp index 1632fd072..c7d3df984 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp @@ -14,141 +14,199 @@ * limitations under the License. */ +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +#include <algorithm> #include <cmath> -#include <ctime> #include <stdlib.h> -#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" - -#include "suggest/core/policy/dictionary_header_structure_policy.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" #include "suggest/policyimpl/dictionary/utils/probability_utils.h" +#include "utils/time_keeper.h" namespace latinime { -const int ForgettingCurveUtils::MAX_UNIGRAM_COUNT = 12000; -const int ForgettingCurveUtils::MAX_UNIGRAM_COUNT_AFTER_GC = 10000; -const int ForgettingCurveUtils::MAX_BIGRAM_COUNT = 12000; -const int ForgettingCurveUtils::MAX_BIGRAM_COUNT_AFTER_GC = 10000; - -const int ForgettingCurveUtils::MAX_COMPUTED_PROBABILITY = 127; -const int ForgettingCurveUtils::MAX_ENCODED_PROBABILITY = 15; -const int ForgettingCurveUtils::MIN_VALID_ENCODED_PROBABILITY = 3; -const int ForgettingCurveUtils::ENCODED_PROBABILITY_STEP = 1; -// Currently, we try to decay each uni/bigram once every 2 hours. Accordingly, the expected -// duration of the decay is approximately 66hours. -const float ForgettingCurveUtils::MIN_PROBABILITY_TO_DECAY = 0.03f; +const int ForgettingCurveUtils::MULTIPLIER_TWO_IN_PROBABILITY_SCALE = 8; const int ForgettingCurveUtils::DECAY_INTERVAL_SECONDS = 2 * 60 * 60; -const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityTable; -ForgettingCurveUtils::TimeKeeper ForgettingCurveUtils::sTimeKeeper; +const int ForgettingCurveUtils::MAX_LEVEL = 3; +const int ForgettingCurveUtils::MIN_VALID_LEVEL = 1; +const int ForgettingCurveUtils::MAX_ELAPSED_TIME_STEP_COUNT = 15; +const int ForgettingCurveUtils::DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD = 14; -void ForgettingCurveUtils::TimeKeeper::setCurrentTime() { - mCurrentTime = time(0); -} +const float ForgettingCurveUtils::UNIGRAM_COUNT_HARD_LIMIT_WEIGHT = 1.2; +const float ForgettingCurveUtils::BIGRAM_COUNT_HARD_LIMIT_WEIGHT = 1.2; -/* static */ int ForgettingCurveUtils::getProbability(const int encodedUnigramProbability, - const int encodedBigramProbability) { - if (encodedUnigramProbability == NOT_A_PROBABILITY) { - return NOT_A_PROBABILITY; - } else if (encodedBigramProbability == NOT_A_PROBABILITY) { - return backoff(decodeProbability(encodedUnigramProbability)); +const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityTable; + +// TODO: Revise the logic to decide the initial probability depending on the given probability. +/* static */ const HistoricalInfo ForgettingCurveUtils::createUpdatedHistoricalInfo( + const HistoricalInfo *const originalHistoricalInfo, + const int newProbability, const int timestamp, const HeaderPolicy *const headerPolicy) { + if (newProbability != NOT_A_PROBABILITY && originalHistoricalInfo->getLevel() == 0) { + return HistoricalInfo(timestamp, MIN_VALID_LEVEL /* level */, 0 /* count */); + } else if (!originalHistoricalInfo->isValid()) { + // Initial information. + return HistoricalInfo(timestamp, 0 /* level */, 1 /* count */); } else { - const int unigramProbability = decodeProbability(encodedUnigramProbability); - const int bigramProbability = decodeProbability(encodedBigramProbability); - return min(max(unigramProbability, bigramProbability), MAX_COMPUTED_PROBABILITY); + const int updatedCount = originalHistoricalInfo->getCount() + 1; + if (updatedCount >= headerPolicy->getForgettingCurveOccurrencesToLevelUp()) { + // The count exceeds the max value the level can be incremented. + if (originalHistoricalInfo->getLevel() >= MAX_LEVEL) { + // The level is already max. + return HistoricalInfo(timestamp, originalHistoricalInfo->getLevel(), + originalHistoricalInfo->getCount()); + } else { + // Level up. + return HistoricalInfo(timestamp, originalHistoricalInfo->getLevel() + 1, + 0 /* count */); + } + } else { + return HistoricalInfo(timestamp, originalHistoricalInfo->getLevel(), updatedCount); + } } } -// Caveat: Unlike getProbability(), this method doesn't assume special bigram probability encoding -// (i.e. unigram probability + bigram probability delta). -/* static */ int ForgettingCurveUtils::getUpdatedEncodedProbability( - const int originalEncodedProbability, const int newProbability) { - if (originalEncodedProbability == NOT_A_PROBABILITY) { - // The bigram relation is not in this dictionary. - if (newProbability == NOT_A_PROBABILITY) { - // The bigram target is not in other dictionaries. - return 0; - } else { - return MIN_VALID_ENCODED_PROBABILITY; - } +/* static */ int ForgettingCurveUtils::decodeProbability( + const HistoricalInfo *const historicalInfo, const HeaderPolicy *const headerPolicy) { + const int elapsedTimeStepCount = getElapsedTimeStepCount(historicalInfo->getTimeStamp(), + headerPolicy->getForgettingCurveDurationToLevelDown()); + return sProbabilityTable.getProbability( + headerPolicy->getForgettingCurveProbabilityValuesTableId(), + std::min(std::max(historicalInfo->getLevel(), 0), MAX_LEVEL), + std::min(std::max(elapsedTimeStepCount, 0), MAX_ELAPSED_TIME_STEP_COUNT)); +} + +/* static */ int ForgettingCurveUtils::getProbability(const int unigramProbability, + const int bigramProbability) { + if (unigramProbability == NOT_A_PROBABILITY) { + return NOT_A_PROBABILITY; + } else if (bigramProbability == NOT_A_PROBABILITY) { + return std::min(backoff(unigramProbability), MAX_PROBABILITY); } else { - if (newProbability != NOT_A_PROBABILITY - && originalEncodedProbability < MIN_VALID_ENCODED_PROBABILITY) { - return MIN_VALID_ENCODED_PROBABILITY; - } - return min(originalEncodedProbability + ENCODED_PROBABILITY_STEP, MAX_ENCODED_PROBABILITY); + // TODO: Investigate better way to handle bigram probability. + return std::min(std::max(unigramProbability, + bigramProbability + MULTIPLIER_TWO_IN_PROBABILITY_SCALE), MAX_PROBABILITY); } } -/* static */ int ForgettingCurveUtils::isValidEncodedProbability(const int encodedProbability) { - return encodedProbability >= MIN_VALID_ENCODED_PROBABILITY; +/* static */ bool ForgettingCurveUtils::needsToKeep(const HistoricalInfo *const historicalInfo, + const HeaderPolicy *const headerPolicy) { + return historicalInfo->getLevel() > 0 + || getElapsedTimeStepCount(historicalInfo->getTimeStamp(), + headerPolicy->getForgettingCurveDurationToLevelDown()) + < DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD; } -/* static */ int ForgettingCurveUtils::getEncodedProbabilityToSave(const int encodedProbability, - const DictionaryHeaderStructurePolicy *const headerPolicy) { - const int elapsedTime = sTimeKeeper.peekCurrentTime() - headerPolicy->getLastDecayedTime(); - const int decayIterationCount = max(elapsedTime / DECAY_INTERVAL_SECONDS, 1); - int currentEncodedProbability = max(min(encodedProbability, MAX_ENCODED_PROBABILITY), 0); - // TODO: Implement the decay in more proper way. - for (int i = 0; i < decayIterationCount; ++i) { - const float currentRate = static_cast<float>(currentEncodedProbability) - / static_cast<float>(MAX_ENCODED_PROBABILITY); - const float thresholdToDecay = (1.0f - MIN_PROBABILITY_TO_DECAY) * currentRate; - const float randValue = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); - if (thresholdToDecay < randValue) { - currentEncodedProbability = max(currentEncodedProbability - ENCODED_PROBABILITY_STEP, - 0); - } +/* static */ const HistoricalInfo ForgettingCurveUtils::createHistoricalInfoToSave( + const HistoricalInfo *const originalHistoricalInfo, + const HeaderPolicy *const headerPolicy) { + if (originalHistoricalInfo->getTimeStamp() == NOT_A_TIMESTAMP) { + return HistoricalInfo(); + } + const int durationToLevelDownInSeconds = headerPolicy->getForgettingCurveDurationToLevelDown(); + const int elapsedTimeStep = getElapsedTimeStepCount( + originalHistoricalInfo->getTimeStamp(), durationToLevelDownInSeconds); + if (elapsedTimeStep <= MAX_ELAPSED_TIME_STEP_COUNT) { + // No need to update historical info. + return *originalHistoricalInfo; } - return currentEncodedProbability; + // Level down. + const int maxLevelDownAmonut = elapsedTimeStep / (MAX_ELAPSED_TIME_STEP_COUNT + 1); + const int levelDownAmount = (maxLevelDownAmonut >= originalHistoricalInfo->getLevel()) ? + originalHistoricalInfo->getLevel() : maxLevelDownAmonut; + const int adjustedTimestampInSeconds = originalHistoricalInfo->getTimeStamp() + + levelDownAmount * durationToLevelDownInSeconds; + return HistoricalInfo(adjustedTimestampInSeconds, + originalHistoricalInfo->getLevel() - levelDownAmount, 0 /* count */); } /* static */ bool ForgettingCurveUtils::needsToDecay(const bool mindsBlockByDecay, - const int unigramCount, const int bigramCount, - const DictionaryHeaderStructurePolicy *const headerPolicy) { - if (unigramCount >= ForgettingCurveUtils::MAX_UNIGRAM_COUNT) { + const int unigramCount, const int bigramCount, const HeaderPolicy *const headerPolicy) { + if (unigramCount >= getUnigramCountHardLimit(headerPolicy->getMaxUnigramCount())) { // Unigram count exceeds the limit. return true; - } else if (bigramCount >= ForgettingCurveUtils::MAX_BIGRAM_COUNT) { + } else if (bigramCount >= getBigramCountHardLimit(headerPolicy->getMaxBigramCount())) { // Bigram count exceeds the limit. return true; } if (mindsBlockByDecay) { return false; } - if (headerPolicy->getLastDecayedTime() + DECAY_INTERVAL_SECONDS < time(0)) { + if (headerPolicy->getLastDecayedTime() + DECAY_INTERVAL_SECONDS + < TimeKeeper::peekCurrentTime()) { // Time to decay. return true; } return false; } -/* static */ int ForgettingCurveUtils::decodeProbability(const int encodedProbability) { - if (encodedProbability < MIN_VALID_ENCODED_PROBABILITY) { - return NOT_A_PROBABILITY; - } else { - return min(sProbabilityTable.getProbability(encodedProbability), MAX_ENCODED_PROBABILITY); - } -} - // See comments in ProbabilityUtils::backoff(). /* static */ int ForgettingCurveUtils::backoff(const int unigramProbability) { - if (unigramProbability == NOT_A_PROBABILITY) { - return NOT_A_PROBABILITY; - } else { - return max(unigramProbability - 8, 0); + // See TODO comments in ForgettingCurveUtils::getProbability(). + return unigramProbability; +} + +/* static */ int ForgettingCurveUtils::getElapsedTimeStepCount(const int timestamp, + const int durationToLevelDownInSeconds) { + const int elapsedTimeInSeconds = TimeKeeper::peekCurrentTime() - timestamp; + const int timeStepDurationInSeconds = + durationToLevelDownInSeconds / (MAX_ELAPSED_TIME_STEP_COUNT + 1); + return elapsedTimeInSeconds / timeStepDurationInSeconds; +} + +const int ForgettingCurveUtils::ProbabilityTable::PROBABILITY_TABLE_COUNT = 4; +const int ForgettingCurveUtils::ProbabilityTable::WEAK_PROBABILITY_TABLE_ID = 0; +const int ForgettingCurveUtils::ProbabilityTable::MODEST_PROBABILITY_TABLE_ID = 1; +const int ForgettingCurveUtils::ProbabilityTable::STRONG_PROBABILITY_TABLE_ID = 2; +const int ForgettingCurveUtils::ProbabilityTable::AGGRESSIVE_PROBABILITY_TABLE_ID = 3; +const int ForgettingCurveUtils::ProbabilityTable::WEAK_MAX_PROBABILITY = 127; +const int ForgettingCurveUtils::ProbabilityTable::MODEST_BASE_PROBABILITY = 32; +const int ForgettingCurveUtils::ProbabilityTable::STRONG_BASE_PROBABILITY = 35; +const int ForgettingCurveUtils::ProbabilityTable::AGGRESSIVE_BASE_PROBABILITY = 40; + + +ForgettingCurveUtils::ProbabilityTable::ProbabilityTable() : mTables() { + mTables.resize(PROBABILITY_TABLE_COUNT); + for (int tableId = 0; tableId < PROBABILITY_TABLE_COUNT; ++tableId) { + mTables[tableId].resize(MAX_LEVEL + 1); + for (int level = 0; level <= MAX_LEVEL; ++level) { + mTables[tableId][level].resize(MAX_ELAPSED_TIME_STEP_COUNT + 1); + const float initialProbability = getBaseProbabilityForLevel(tableId, level); + const float endProbability = getBaseProbabilityForLevel(tableId, level - 1); + for (int timeStepCount = 0; timeStepCount <= MAX_ELAPSED_TIME_STEP_COUNT; + ++timeStepCount) { + if (level == 0) { + mTables[tableId][level][timeStepCount] = NOT_A_PROBABILITY; + continue; + } + const float probability = initialProbability + * powf(initialProbability / endProbability, + -1.0f * static_cast<float>(timeStepCount) + / static_cast<float>(MAX_ELAPSED_TIME_STEP_COUNT + 1)); + mTables[tableId][level][timeStepCount] = + std::min(std::max(static_cast<int>(probability), 1), MAX_PROBABILITY); + } + } } } -ForgettingCurveUtils::ProbabilityTable::ProbabilityTable() : mTable() { - // Table entry is as follows: - // 1, 1, 1, 2, 3, 5, 6, 9, 13, 18, 25, 34, 48, 66, 91, 127. - // Note that first MIN_VALID_ENCODED_PROBABILITY values are not used. - mTable.resize(MAX_ENCODED_PROBABILITY + 1); - for (int i = 0; i <= MAX_ENCODED_PROBABILITY; ++i) { - const int probability = static_cast<int>(powf(static_cast<float>(MAX_COMPUTED_PROBABILITY), - static_cast<float>(i) / static_cast<float>(MAX_ENCODED_PROBABILITY))); - mTable[i] = min(MAX_COMPUTED_PROBABILITY, max(0, probability)); +/* static */ int ForgettingCurveUtils::ProbabilityTable::getBaseProbabilityForLevel( + const int tableId, const int level) { + if (tableId == WEAK_PROBABILITY_TABLE_ID) { + // Max probability is 127. + return static_cast<float>(WEAK_MAX_PROBABILITY / (1 << (MAX_LEVEL - level))); + } else if (tableId == MODEST_PROBABILITY_TABLE_ID) { + // Max probability is 128. + return static_cast<float>(MODEST_BASE_PROBABILITY * (level + 1)); + } else if (tableId == STRONG_PROBABILITY_TABLE_ID) { + // Max probability is 140. + return static_cast<float>(STRONG_BASE_PROBABILITY * (level + 1)); + } else if (tableId == AGGRESSIVE_PROBABILITY_TABLE_ID) { + // Max probability is 160. + return static_cast<float>(AGGRESSIVE_BASE_PROBABILITY * (level + 1)); + } else { + return NOT_A_PROBABILITY; } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h index 2ad423874..bb8690939 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h @@ -20,48 +20,43 @@ #include <vector> #include "defines.h" +#include "suggest/policyimpl/dictionary/utils/historical_info.h" namespace latinime { -class DictionaryHeaderStructurePolicy; +class HeaderPolicy; -// TODO: Check the elapsed time and decrease the probability depending on the time. Time field is -// required to introduced to each terminal PtNode and bigram entry. -// TODO: Quit using bigram probability to indicate the delta. class ForgettingCurveUtils { public: - class TimeKeeper { - public: - TimeKeeper() : mCurrentTime(0) {} - void setCurrentTime(); - int peekCurrentTime() const { return mCurrentTime; }; - - private: - DISALLOW_COPY_AND_ASSIGN(TimeKeeper); + static const HistoricalInfo createUpdatedHistoricalInfo( + const HistoricalInfo *const originalHistoricalInfo, const int newProbability, + const int timestamp, const HeaderPolicy *const headerPolicy); - int mCurrentTime; - }; + static const HistoricalInfo createHistoricalInfoToSave( + const HistoricalInfo *const originalHistoricalInfo, + const HeaderPolicy *const headerPolicy); - static const int MAX_UNIGRAM_COUNT; - static const int MAX_UNIGRAM_COUNT_AFTER_GC; - static const int MAX_BIGRAM_COUNT; - static const int MAX_BIGRAM_COUNT_AFTER_GC; - - static TimeKeeper sTimeKeeper; + static int decodeProbability(const HistoricalInfo *const historicalInfo, + const HeaderPolicy *const headerPolicy); static int getProbability(const int encodedUnigramProbability, const int encodedBigramProbability); - static int getUpdatedEncodedProbability(const int originalEncodedProbability, - const int newProbability); + static bool needsToKeep(const HistoricalInfo *const historicalInfo, + const HeaderPolicy *const headerPolicy); - static int isValidEncodedProbability(const int encodedProbability); + static bool needsToDecay(const bool mindsBlockByDecay, const int unigramCount, + const int bigramCount, const HeaderPolicy *const headerPolicy); - static int getEncodedProbabilityToSave(const int encodedProbability, - const DictionaryHeaderStructurePolicy *const headerPolicy); + AK_FORCE_INLINE static int getUnigramCountHardLimit(const int maxUnigramCount) { + return static_cast<int>(static_cast<float>(maxUnigramCount) + * UNIGRAM_COUNT_HARD_LIMIT_WEIGHT); + } - static bool needsToDecay(const bool mindsBlockByDecay, const int unigramCount, - const int bigramCount, const DictionaryHeaderStructurePolicy *const headerPolicy); + AK_FORCE_INLINE static int getBigramCountHardLimit(const int maxBigramCount) { + return static_cast<int>(static_cast<float>(maxBigramCount) + * BIGRAM_COUNT_HARD_LIMIT_WEIGHT); + } private: DISALLOW_IMPLICIT_CONSTRUCTORS(ForgettingCurveUtils); @@ -70,31 +65,46 @@ class ForgettingCurveUtils { public: ProbabilityTable(); - int getProbability(const int encodedProbability) const { - if (encodedProbability < 0 || encodedProbability > static_cast<int>(mTable.size())) { - return NOT_A_PROBABILITY; - } - return mTable[encodedProbability]; + int getProbability(const int tableId, const int level, + const int elapsedTimeStepCount) const { + return mTables[tableId][level][elapsedTimeStepCount]; } private: DISALLOW_COPY_AND_ASSIGN(ProbabilityTable); - std::vector<int> mTable; + static const int PROBABILITY_TABLE_COUNT; + static const int WEAK_PROBABILITY_TABLE_ID; + static const int MODEST_PROBABILITY_TABLE_ID; + static const int STRONG_PROBABILITY_TABLE_ID; + static const int AGGRESSIVE_PROBABILITY_TABLE_ID; + + static const int WEAK_MAX_PROBABILITY; + static const int MODEST_BASE_PROBABILITY; + static const int STRONG_BASE_PROBABILITY; + static const int AGGRESSIVE_BASE_PROBABILITY; + + std::vector<std::vector<std::vector<int> > > mTables; + + static int getBaseProbabilityForLevel(const int tableId, const int level); }; - static const int MAX_COMPUTED_PROBABILITY; - static const int MAX_ENCODED_PROBABILITY; - static const int MIN_VALID_ENCODED_PROBABILITY; - static const int ENCODED_PROBABILITY_STEP; - static const float MIN_PROBABILITY_TO_DECAY; + static const int MULTIPLIER_TWO_IN_PROBABILITY_SCALE; static const int DECAY_INTERVAL_SECONDS; - static const ProbabilityTable sProbabilityTable; + static const int MAX_LEVEL; + static const int MIN_VALID_LEVEL; + static const int MAX_ELAPSED_TIME_STEP_COUNT; + static const int DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD; - static int decodeProbability(const int encodedProbability); + static const float UNIGRAM_COUNT_HARD_LIMIT_WEIGHT; + static const float BIGRAM_COUNT_HARD_LIMIT_WEIGHT; + + static const ProbabilityTable sProbabilityTable; static int backoff(const int unigramProbability); + + static int getElapsedTimeStepCount(const int timestamp, const int durationToLevelDown); }; } // namespace latinime #endif /* LATINIME_FORGETTING_CURVE_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp index 1d77d5c27..cd3c403fa 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp @@ -41,10 +41,13 @@ const int FormatUtils::DICTIONARY_MINIMUM_SIZE = 12; // Dictionary format version number (2 bytes) // Options (2 bytes) // Header size (4 bytes) : integer, big endian - if (ByteArrayUtils::readUint16(dict, 4) == 2) { + // Conceptually this converts the hardcoded value of the bytes in the file into + // the symbolic value we use in the code. But we want the constants to be the + // same so we use them for both here. + if (ByteArrayUtils::readUint16(dict, 4) == VERSION_2) { return VERSION_2; - } else if (ByteArrayUtils::readUint16(dict, 4) == 3) { - return VERSION_3; + } else if (ByteArrayUtils::readUint16(dict, 4) == VERSION_4) { + return VERSION_4; } else { return UNKNOWN_VERSION; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h index 79ed0de29..759b1c9b2 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h @@ -17,7 +17,7 @@ #ifndef LATINIME_FORMAT_UTILS_H #define LATINIME_FORMAT_UTILS_H -#include <stdint.h> +#include <cstdint> #include "defines.h" @@ -29,9 +29,10 @@ namespace latinime { class FormatUtils { public: enum FORMAT_VERSION { - VERSION_2, - VERSION_3, - UNKNOWN_VERSION + // These MUST have the same values as the relevant constants in FormatSpec.java. + VERSION_2 = 2, + VERSION_4 = 401, + UNKNOWN_VERSION = -1 }; // 32 bit magic number is stored at the beginning of the dictionary header to reject diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/historical_info.h b/native/jni/src/suggest/policyimpl/dictionary/utils/historical_info.h new file mode 100644 index 000000000..428ca8626 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/historical_info.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013, 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_HISTORICAL_INFO_H +#define LATINIME_HISTORICAL_INFO_H + +#include "defines.h" + +namespace latinime { + +class HistoricalInfo { + public: + // Invalid historical info. + HistoricalInfo() + : mTimestamp(NOT_A_TIMESTAMP), mLevel(0), mCount(0) {} + + HistoricalInfo(const int timestamp, const int level, const int count) + : mTimestamp(timestamp), mLevel(level), mCount(count) {} + + bool isValid() const { + return mTimestamp != NOT_A_TIMESTAMP; + } + + int getTimeStamp() const { + return mTimestamp; + } + + int getLevel() const { + return mLevel; + } + + int getCount() const { + return mCount; + } + + private: + // Copy constructor is public to use this class as a type of return value. + DISALLOW_ASSIGNMENT_OPERATOR(HistoricalInfo); + + const int mTimestamp; + const int mLevel; + const int mCount; +}; +} // namespace latinime +#endif /* LATINIME_HISTORICAL_INFO_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp new file mode 100644 index 000000000..d3e0c237f --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +#include <cerrno> +#include <climits> +#include <cstdio> +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "suggest/policyimpl/dictionary/utils/file_utils.h" + +namespace latinime { + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const path, const int bufferOffset, const int bufferSize, + const bool isUpdatable) { + const int mmapFd = open(path, O_RDONLY); + if (mmapFd < 0) { + AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno); + return MmappedBufferPtr(nullptr); + } + const int pagesize = sysconf(_SC_PAGESIZE); + const int offset = bufferOffset % pagesize; + int alignedOffset = bufferOffset - offset; + int alignedSize = bufferSize + offset; + const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ; + void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd, + alignedOffset); + if (mmappedBuffer == MAP_FAILED) { + AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); + close(mmapFd); + return MmappedBufferPtr(nullptr); + } + uint8_t *const buffer = static_cast<uint8_t *>(mmappedBuffer) + offset; + if (!buffer) { + AKLOGE("DICT: buffer is null"); + close(mmapFd); + return MmappedBufferPtr(nullptr); + } + return MmappedBufferPtr(new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, + mmapFd, isUpdatable)); +} + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const path, const bool isUpdatable) { + const int fileSize = FileUtils::getFileSize(path); + if (fileSize == -1) { + return MmappedBufferPtr(nullptr); + } else if (fileSize == 0) { + return MmappedBufferPtr(new MmappedBuffer(isUpdatable)); + } else { + return openBuffer(path, 0 /* bufferOffset */, fileSize, isUpdatable); + } +} + +/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer( + const char *const dirPath, const char *const fileName, const bool isUpdatable) { + const int filePathBufferSize = PATH_MAX + 1 /* terminator */; + char filePath[filePathBufferSize]; + const int filePathLength = snprintf(filePath, filePathBufferSize, "%s%s", dirPath, + fileName); + if (filePathLength >= filePathBufferSize) { + return MmappedBufferPtr(nullptr); + } + return openBuffer(filePath, isUpdatable); +} + +MmappedBuffer::~MmappedBuffer() { + if (mAlignedSize == 0) { + return; + } + int ret = munmap(mMmappedBuffer, mAlignedSize); + if (ret != 0) { + AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); + } + ret = close(mMmapFd); + if (ret != 0) { + AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); + } +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h index 6b69116eb..8460087ab 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h @@ -17,11 +17,8 @@ #ifndef LATINIME_MMAPPED_BUFFER_H #define LATINIME_MMAPPED_BUFFER_H -#include <cerrno> -#include <fcntl.h> -#include <stdint.h> -#include <sys/mman.h> -#include <unistd.h> +#include <cstdint> +#include <memory> #include "defines.h" @@ -29,46 +26,18 @@ namespace latinime { class MmappedBuffer { public: - static MmappedBuffer* openBuffer(const char *const path, const int bufferOffset, - const int bufferSize, const bool isUpdatable) { - const int openMode = isUpdatable ? O_RDWR : O_RDONLY; - const int mmapFd = open(path, openMode); - if (mmapFd < 0) { - AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno); - return 0; - } - const int pagesize = getpagesize(); - const int offset = bufferOffset % pagesize; - int alignedOffset = bufferOffset - offset; - int alignedSize = bufferSize + offset; - const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ; - void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd, - alignedOffset); - if (mmappedBuffer == MAP_FAILED) { - AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); - close(mmapFd); - return 0; - } - uint8_t *const buffer = static_cast<uint8_t *>(mmappedBuffer) + offset; - if (!buffer) { - AKLOGE("DICT: buffer is null"); - close(mmapFd); - return 0; - } - return new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, mmapFd, - isUpdatable); - } + typedef std::unique_ptr<const MmappedBuffer> MmappedBufferPtr; - ~MmappedBuffer() { - int ret = munmap(mMmappedBuffer, mAlignedSize); - if (ret != 0) { - AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); - } - ret = close(mMmapFd); - if (ret != 0) { - AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); - } - } + static MmappedBufferPtr openBuffer(const char *const path, + const int bufferOffset, const int bufferSize, const bool isUpdatable); + + // Mmap entire file. + static MmappedBufferPtr openBuffer(const char *const path, const bool isUpdatable); + + static MmappedBufferPtr openBuffer(const char *const dirPath, const char *const fileName, + const bool isUpdatable); + + ~MmappedBuffer(); AK_FORCE_INLINE uint8_t *getBuffer() const { return mBuffer; @@ -89,6 +58,11 @@ class MmappedBuffer { : mBuffer(buffer), mBufferSize(bufferSize), mMmappedBuffer(mmappedBuffer), mAlignedSize(alignedSize), mMmapFd(mmapFd), mIsUpdatable(isUpdatable) {} + // Empty file. We have to handle an empty file as a valid part of a dictionary. + AK_FORCE_INLINE MmappedBuffer(const bool isUpdatable) + : mBuffer(nullptr), mBufferSize(0), mMmappedBuffer(nullptr), mAlignedSize(0), + mMmapFd(0), mIsUpdatable(isUpdatable) {} + DISALLOW_IMPLICIT_CONSTRUCTORS(MmappedBuffer); uint8_t *const mBuffer; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h index 21fe355b8..3b339e61a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h @@ -17,12 +17,11 @@ #ifndef LATINIME_PROBABILITY_UTILS_H #define LATINIME_PROBABILITY_UTILS_H -#include <stdint.h> - #include "defines.h" namespace latinime { +// TODO: Quit using bigram probability to indicate the delta. class ProbabilityUtils { public: static AK_FORCE_INLINE int backoff(const int unigramProbability) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.cpp new file mode 100644 index 000000000..d336306b9 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "suggest/policyimpl/dictionary/utils/sparse_table.h" + +namespace latinime { + +const int SparseTable::NOT_EXIST = -1; +const int SparseTable::INDEX_SIZE = 4; + +bool SparseTable::contains(const int id) const { + const int readingPos = getPosInIndexTable(id); + if (id < 0 || mIndexTableBuffer->getTailPosition() <= readingPos) { + return false; + } + const int index = mIndexTableBuffer->readUint(INDEX_SIZE, readingPos); + return index != NOT_EXIST; +} + +uint32_t SparseTable::get(const int id) const { + const int indexTableReadingPos = getPosInIndexTable(id); + const int index = mIndexTableBuffer->readUint(INDEX_SIZE, indexTableReadingPos); + const int contentTableReadingPos = getPosInContentTable(id, index); + if (contentTableReadingPos < 0 + || contentTableReadingPos >= mContentTableBuffer->getTailPosition()) { + AKLOGE("contentTableReadingPos(%d) is invalid. id: %d, index: %d", + contentTableReadingPos, id, index); + return NOT_A_DICT_POS; + } + const int contentValue = mContentTableBuffer->readUint(mDataSize, contentTableReadingPos); + return contentValue == NOT_EXIST ? NOT_A_DICT_POS : contentValue; +} + +bool SparseTable::set(const int id, const uint32_t value) { + const int posInIndexTable = getPosInIndexTable(id); + // Extends the index table if needed. + int tailPos = mIndexTableBuffer->getTailPosition(); + while (tailPos <= posInIndexTable) { + if (!mIndexTableBuffer->writeUintAndAdvancePosition(NOT_EXIST, INDEX_SIZE, &tailPos)) { + AKLOGE("cannot extend index table. tailPos: %d to: %d", tailPos, posInIndexTable); + return false; + } + } + if (contains(id)) { + // The entry is already in the content table. + const int index = mIndexTableBuffer->readUint(INDEX_SIZE, posInIndexTable); + if (!mContentTableBuffer->writeUint(value, mDataSize, getPosInContentTable(id, index))) { + AKLOGE("cannot update value %d. pos: %d, tailPos: %d, mDataSize: %d", value, + getPosInContentTable(id, index), mContentTableBuffer->getTailPosition(), + mDataSize); + return false; + } + return true; + } + // The entry is not in the content table. + // Create new entry in the content table. + const int index = getIndexFromContentTablePos(mContentTableBuffer->getTailPosition()); + if (!mIndexTableBuffer->writeUint(index, INDEX_SIZE, posInIndexTable)) { + AKLOGE("cannot write index %d. pos %d", index, posInIndexTable); + return false; + } + // Write a new block that containing the entry to be set. + int writingPos = getPosInContentTable(0 /* id */, index); + for (int i = 0; i < mBlockSize; ++i) { + if (!mContentTableBuffer->writeUintAndAdvancePosition(NOT_EXIST, mDataSize, + &writingPos)) { + AKLOGE("cannot write content table to extend. writingPos: %d, tailPos: %d, " + "mDataSize: %d", writingPos, mContentTableBuffer->getTailPosition(), mDataSize); + return false; + } + } + return mContentTableBuffer->writeUint(value, mDataSize, getPosInContentTable(id, index)); +} + +int SparseTable::getIndexFromContentTablePos(const int contentTablePos) const { + return contentTablePos / mDataSize / mBlockSize; +} + +int SparseTable::getPosInIndexTable(const int id) const { + return (id / mBlockSize) * INDEX_SIZE; +} + +int SparseTable::getPosInContentTable(const int id, const int index) const { + const int offset = id % mBlockSize; + return (index * mBlockSize + offset) * mDataSize; +} + +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.h b/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.h new file mode 100644 index 000000000..fca8120f1 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/sparse_table.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013, 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_SPARSE_TABLE_H +#define LATINIME_SPARSE_TABLE_H + +#include <cstdint> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { + +// Note that there is a corresponding implementation in SparseTable.java. +// TODO: Support multiple content buffers. +class SparseTable { + public: + SparseTable(BufferWithExtendableBuffer *const indexTableBuffer, + BufferWithExtendableBuffer *const contentTableBuffer, const int blockSize, + const int dataSize) + : mIndexTableBuffer(indexTableBuffer), mContentTableBuffer(contentTableBuffer), + mBlockSize(blockSize), mDataSize(dataSize) {} + + bool contains(const int id) const; + + uint32_t get(const int id) const; + + bool set(const int id, const uint32_t value); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SparseTable); + + int getIndexFromContentTablePos(const int contentTablePos) const; + + int getPosInIndexTable(const int id) const; + + int getPosInContentTable(const int id, const int index) const; + + static const int NOT_EXIST; + static const int INDEX_SIZE; + + BufferWithExtendableBuffer *const mIndexTableBuffer; + BufferWithExtendableBuffer *const mContentTableBuffer; + const int mBlockSize; + const int mDataSize; +}; +} // namespace latinime +#endif /* LATINIME_SPARSE_TABLE_H */ diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp index 104eb2a7a..fa9600c74 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp @@ -22,6 +22,12 @@ const float ScoringParams::MAX_SPATIAL_DISTANCE = 1.0f; const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY = 40; const int ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED = 120; const float ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD = 1.0f; + +const float ScoringParams::EXACT_MATCH_PROMOTION = 1.1f; +const float ScoringParams::CASE_ERROR_PENALTY_FOR_EXACT_MATCH = 0.01f; +const float ScoringParams::ACCENT_ERROR_PENALTY_FOR_EXACT_MATCH = 0.02f; +const float ScoringParams::DIGRAPH_PENALTY_FOR_EXACT_MATCH = 0.03f; + // TODO: Unlimit max cache dic node size const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE = 170; const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT = 310; @@ -31,8 +37,8 @@ const float ScoringParams::DISTANCE_WEIGHT_LENGTH = 0.1524f; const float ScoringParams::PROXIMITY_COST = 0.0694f; const float ScoringParams::FIRST_CHAR_PROXIMITY_COST = 0.072f; const float ScoringParams::FIRST_PROXIMITY_COST = 0.07788f; -const float ScoringParams::OMISSION_COST = 0.4676f; -const float ScoringParams::OMISSION_COST_SAME_CHAR = 0.399f; +const float ScoringParams::OMISSION_COST = 0.467f; +const float ScoringParams::OMISSION_COST_SAME_CHAR = 0.345f; const float ScoringParams::OMISSION_COST_FIRST_CHAR = 0.5256f; const float ScoringParams::INSERTION_COST = 0.7248f; const float ScoringParams::TERMINAL_INSERTION_COST = 0.8128f; @@ -40,18 +46,18 @@ const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.5508f; const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.674f; const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.639f; const float ScoringParams::TRANSPOSITION_COST = 0.5608f; -const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.339f; +const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.334f; const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.4576f; const float ScoringParams::SUBSTITUTION_COST = 0.3806f; -const float ScoringParams::COST_NEW_WORD = 0.0312f; +const float ScoringParams::COST_NEW_WORD = 0.0314f; const float ScoringParams::COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE = 0.3224f; const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.1214f; -const float ScoringParams::COST_FIRST_LOOKAHEAD = 0.4836f; -const float ScoringParams::COST_LOOKAHEAD = 0.00624f; -const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.06836f; +const float ScoringParams::COST_FIRST_COMPLETION = 0.4836f; +const float ScoringParams::COST_COMPLETION = 0.00624f; +const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.0683f; const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.0362f; const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.4182f; const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f; const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f; -const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.045f; +const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.095f; } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h index 7d4b5c3c7..b66962019 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h @@ -32,6 +32,11 @@ class ScoringParams { static const int MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT; static const int THRESHOLD_SHORT_WORD_LENGTH; + static const float EXACT_MATCH_PROMOTION; + static const float CASE_ERROR_PENALTY_FOR_EXACT_MATCH; + static const float ACCENT_ERROR_PENALTY_FOR_EXACT_MATCH; + static const float DIGRAPH_PENALTY_FOR_EXACT_MATCH; + // Numerically optimized parameters (currently for tap typing only). // TODO: add ability to modify these constants programmatically. // TODO: explore optimization of gesture parameters. @@ -54,8 +59,8 @@ class ScoringParams { static const float COST_NEW_WORD; static const float COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE; static const float DISTANCE_WEIGHT_LANGUAGE; - static const float COST_FIRST_LOOKAHEAD; - static const float COST_LOOKAHEAD; + static const float COST_FIRST_COMPLETION; + static const float COST_COMPLETION; static const float HAS_PROXIMITY_TERMINAL_COST; static const float HAS_EDIT_CORRECTION_TERMINAL_COST; static const float HAS_MULTI_WORD_TERMINAL_COST; diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h index 56ffcc93e..66ea62406 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h @@ -18,7 +18,9 @@ #define LATINIME_TYPING_SCORING_H #include "defines.h" +#include "suggest/core/dictionary/error_type_utils.h" #include "suggest/core/policy/scoring.h" +#include "suggest/core/session/dic_traverse_session.h" #include "suggest/policyimpl/typing/scoring_params.h" namespace latinime { @@ -30,40 +32,40 @@ class TypingScoring : public Scoring { public: static const TypingScoring *getInstance() { return &sInstance; } - AK_FORCE_INLINE bool getMostProbableString( - const DicTraverseSession *const traverseSession, const int terminalSize, - const float languageWeight, int *const outputCodePoints, int *const type, - int *const freq) const { - return false; - } - - AK_FORCE_INLINE void safetyNetForMostProbableString(const int terminalSize, - const int maxScore, int *const outputCodePoints, int *const frequencies) const { - } - - AK_FORCE_INLINE void searchWordWithDoubleLetter(DicNode *terminals, - const int terminalSize, int *doubleLetterTerminalIndex, - DoubleLetterLevel *doubleLetterLevel) const { - } + AK_FORCE_INLINE void getMostProbableString(const DicTraverseSession *const traverseSession, + const float languageWeight, SuggestionResults *const outSuggestionResults) const {} AK_FORCE_INLINE float getAdjustedLanguageWeight(DicTraverseSession *const traverseSession, - DicNode *const terminals, const int size) const { + DicNode *const terminals, const int size) const { return 1.0f; } - AK_FORCE_INLINE int calculateFinalScore(const float compoundDistance, - const int inputSize, const bool forceCommit) const { + AK_FORCE_INLINE int calculateFinalScore(const float compoundDistance, const int inputSize, + const ErrorTypeUtils::ErrorType containedErrorTypes, const bool forceCommit, + const bool boostExactMatches) const { const float maxDistance = ScoringParams::DISTANCE_WEIGHT_LANGUAGE + static_cast<float>(inputSize) * ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT; - const float score = ScoringParams::TYPING_BASE_OUTPUT_SCORE - - compoundDistance / maxDistance - + (forceCommit ? ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD : 0.0f); + float score = ScoringParams::TYPING_BASE_OUTPUT_SCORE - compoundDistance / maxDistance; + if (forceCommit) { + score += ScoringParams::AUTOCORRECT_OUTPUT_THRESHOLD; + } + if (boostExactMatches && ErrorTypeUtils::isExactMatch(containedErrorTypes)) { + score += ScoringParams::EXACT_MATCH_PROMOTION; + if ((ErrorTypeUtils::MATCH_WITH_CASE_ERROR & containedErrorTypes) != 0) { + score -= ScoringParams::CASE_ERROR_PENALTY_FOR_EXACT_MATCH; + } + if ((ErrorTypeUtils::MATCH_WITH_ACCENT_ERROR & containedErrorTypes) != 0) { + score -= ScoringParams::ACCENT_ERROR_PENALTY_FOR_EXACT_MATCH; + } + if ((ErrorTypeUtils::MATCH_WITH_DIGRAPH & containedErrorTypes) != 0) { + score -= ScoringParams::DIGRAPH_PENALTY_FOR_EXACT_MATCH; + } + } return static_cast<int>(score * SUGGEST_INTERFACE_OUTPUT_SCALE); } - AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost(const int terminalIndex, - const int doubleLetterTerminalIndex, - const DoubleLetterLevel doubleLetterLevel) const { + AK_FORCE_INLINE float getDoubleLetterDemotionDistanceCost( + const DicNode *const terminalDicNode) const { return 0.0f; } @@ -71,6 +73,16 @@ class TypingScoring : public Scoring { return false; } + AK_FORCE_INLINE bool autoCorrectsToMultiWordSuggestionIfTop() const { + return true; + } + + AK_FORCE_INLINE bool sameAsTyped(const DicTraverseSession *const traverseSession, + const DicNode *const dicNode) const { + return traverseSession->getProximityInfoState(0)->sameAsTyped( + dicNode->getOutputWordBuf(), dicNode->getNodeCodePointCount()); + } + private: DISALLOW_COPY_AND_ASSIGN(TypingScoring); static const TypingScoring sInstance; diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h index 007c19e0a..cb3dfac70 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h @@ -17,7 +17,7 @@ #ifndef LATINIME_TYPING_TRAVERSAL_H #define LATINIME_TYPING_TRAVERSAL_H -#include <stdint.h> +#include <cstdint> #include "defines.h" #include "suggest/core/dicnode/dic_node.h" @@ -81,7 +81,7 @@ class TypingTraversal : public Traversal { return false; } const int point0Index = dicNode->getInputIndex(0); - return dicNode->isTerminalWordNode() + return dicNode->isTerminalDicNode() && traverseSession->getProximityInfoState(0)-> hasSpaceProximity(point0Index); } @@ -96,7 +96,7 @@ class TypingTraversal : public Traversal { if (dicNode->isCompletion(inputSize)) { return false; } - if (!dicNode->isTerminalWordNode()) { + if (!dicNode->isTerminalDicNode()) { return false; } const int16_t pointIndex = dicNode->getInputIndex(0); @@ -137,25 +137,19 @@ class TypingTraversal : public Traversal { return ScoringParams::MAX_SPATIAL_DISTANCE; } - AK_FORCE_INLINE bool autoCorrectsToMultiWordSuggestionIfTop() const { - return true; - } - AK_FORCE_INLINE int getDefaultExpandDicNodeSize() const { return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION; } - AK_FORCE_INLINE bool sameAsTyped( - const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { - return traverseSession->getProximityInfoState(0)->sameAsTyped( - dicNode->getOutputWordBuf(), dicNode->getNodeCodePointCount()); - } - AK_FORCE_INLINE int getMaxCacheSize(const int inputSize) const { return (inputSize <= 1) ? ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT : ScoringParams::MAX_CACHE_DIC_NODE_SIZE; } + AK_FORCE_INLINE int getTerminalCacheSize() const { + return MAX_RESULTS; + } + AK_FORCE_INLINE bool isPossibleOmissionChildNode( const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const { @@ -172,9 +166,8 @@ class TypingTraversal : public Traversal { if (probability < ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY) { return false; } - const int c = dicNode->getOutputWordBuf()[0]; const bool shortCappedWord = dicNode->getNodeCodePointCount() - < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && CharUtils::isAsciiUpper(c); + < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && dicNode->isFirstCharUppercase(); return !shortCappedWord || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED; } diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp index 5b6b5e874..54f65c786 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp @@ -23,39 +23,64 @@ namespace latinime { const TypingWeighting TypingWeighting::sInstance; -ErrorType TypingWeighting::getErrorType(const CorrectionType correctionType, +ErrorTypeUtils::ErrorType TypingWeighting::getErrorType(const CorrectionType correctionType, const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const { switch (correctionType) { case CT_MATCH: if (isProximityDicNode(traverseSession, dicNode)) { - return ET_PROXIMITY_CORRECTION; + return ErrorTypeUtils::PROXIMITY_CORRECTION; + } else if (dicNode->isInDigraph()) { + return ErrorTypeUtils::MATCH_WITH_DIGRAPH; } else { - return ET_NOT_AN_ERROR; + // Compare the node code point with original primary code point on the keyboard. + const ProximityInfoState *const pInfoState = + traverseSession->getProximityInfoState(0); + const int primaryOriginalCodePoint = pInfoState->getPrimaryOriginalCodePointAt( + dicNode->getInputIndex(0)); + const int nodeCodePoint = dicNode->getNodeCodePoint(); + if (primaryOriginalCodePoint == nodeCodePoint) { + // Node code point is same as original code point on the keyboard. + return ErrorTypeUtils::NOT_AN_ERROR; + } else if (CharUtils::toLowerCase(primaryOriginalCodePoint) == + CharUtils::toLowerCase(nodeCodePoint)) { + // Only cases of the code points are different. + return ErrorTypeUtils::MATCH_WITH_CASE_ERROR; + } else if (CharUtils::toBaseCodePoint(primaryOriginalCodePoint) == + CharUtils::toBaseCodePoint(nodeCodePoint)) { + // Node code point is a variant of original code point. + return ErrorTypeUtils::MATCH_WITH_ACCENT_ERROR; + } else { + // Node code point is a variant of original code point and the cases are also + // different. + return ErrorTypeUtils::MATCH_WITH_ACCENT_ERROR + | ErrorTypeUtils::MATCH_WITH_CASE_ERROR; + } } + break; case CT_ADDITIONAL_PROXIMITY: - return ET_PROXIMITY_CORRECTION; + return ErrorTypeUtils::PROXIMITY_CORRECTION; case CT_OMISSION: if (parentDicNode->canBeIntentionalOmission()) { - return ET_INTENTIONAL_OMISSION; + return ErrorTypeUtils::INTENTIONAL_OMISSION; } else { - return ET_EDIT_CORRECTION; + return ErrorTypeUtils::EDIT_CORRECTION; } break; case CT_SUBSTITUTION: case CT_INSERTION: case CT_TERMINAL_INSERTION: case CT_TRANSPOSITION: - return ET_EDIT_CORRECTION; + return ErrorTypeUtils::EDIT_CORRECTION; case CT_NEW_WORD_SPACE_OMISSION: case CT_NEW_WORD_SPACE_SUBSTITUTION: - return ET_NEW_WORD; + return ErrorTypeUtils::NEW_WORD; case CT_TERMINAL: - return ET_NOT_AN_ERROR; + return ErrorTypeUtils::NOT_AN_ERROR; case CT_COMPLETION: - return ET_COMPLETION; + return ErrorTypeUtils::COMPLETION; default: - return ET_NOT_AN_ERROR; + return ErrorTypeUtils::NOT_AN_ERROR; } } } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h index 9f0a331e3..0ba439b47 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h @@ -19,6 +19,7 @@ #include "defines.h" #include "suggest/core/dicnode/dic_node_utils.h" +#include "suggest/core/dictionary/error_type_utils.h" #include "suggest/core/layout/touch_position_correction_utils.h" #include "suggest/core/policy/weighting.h" #include "suggest/core/session/dic_traverse_session.h" @@ -71,8 +72,6 @@ class TypingWeighting : public Weighting { float getMatchedCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, DicNode_InputStateG *inputStateG) const { const int pointIndex = dicNode->getInputIndex(0); - // Note: min() required since length can be MAX_POINT_TO_KEY_LENGTH for characters not on - // the keyboard (like accented letters) const float normalizedSquaredLength = traverseSession->getProximityInfoState(0) ->getPointToKeyLength(pointIndex, CharUtils::toBaseLowerCase(dicNode->getNodeCodePoint())); @@ -167,8 +166,8 @@ class TypingWeighting : public Weighting { const bool firstCompletion = dicNode->getInputIndex(0) == traverseSession->getInputSize(); // TODO: Change the cost for the first completion for the gesture? - const float cost = firstCompletion ? ScoringParams::COST_FIRST_LOOKAHEAD - : ScoringParams::COST_LOOKAHEAD; + const float cost = firstCompletion ? ScoringParams::COST_FIRST_COMPLETION + : ScoringParams::COST_COMPLETION; return cost; } @@ -204,7 +203,7 @@ class TypingWeighting : public Weighting { return cost * traverseSession->getMultiWordCostMultiplier(); } - ErrorType getErrorType(const CorrectionType correctionType, + ErrorTypeUtils::ErrorType getErrorType(const CorrectionType correctionType, const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const; diff --git a/native/jni/src/suggest/policyimpl/utils/edit_distance.h b/native/jni/src/suggest/policyimpl/utils/edit_distance.h index 0871c37ce..4cfd0b3f3 100644 --- a/native/jni/src/suggest/policyimpl/utils/edit_distance.h +++ b/native/jni/src/suggest/policyimpl/utils/edit_distance.h @@ -17,6 +17,8 @@ #ifndef LATINIME_EDIT_DISTANCE_H #define LATINIME_EDIT_DISTANCE_H +#include <algorithm> + #include "defines.h" #include "suggest/policyimpl/utils/edit_distance_policy.h" @@ -38,13 +40,13 @@ class EditDistance { for (int i = 0; i < beforeLength; ++i) { for (int j = 0; j < afterLength; ++j) { - dp[(afterLength + 1) * (i + 1) + (j + 1)] = min( + dp[(afterLength + 1) * (i + 1) + (j + 1)] = std::min( dp[(afterLength + 1) * i + (j + 1)] + policy->getInsertionCost(i, j), - min(dp[(afterLength + 1) * (i + 1) + j] + policy->getDeletionCost(i, j), - dp[(afterLength + 1) * i + j] - + policy->getSubstitutionCost(i, j))); + std::min( + dp[(afterLength + 1) * (i + 1) + j] + policy->getDeletionCost(i, j), + dp[(afterLength + 1) * i + j] + policy->getSubstitutionCost(i, j))); if (policy->allowTransposition(i, j)) { - dp[(afterLength + 1) * (i + 1) + (j + 1)] = min( + dp[(afterLength + 1) * (i + 1) + (j + 1)] = std::min( dp[(afterLength + 1) * (i + 1) + (j + 1)], dp[(afterLength + 1) * (i - 1) + (j - 1)] + policy->getTranspositionCost(i, j)); diff --git a/native/jni/src/utils/autocorrection_threshold_utils.cpp b/native/jni/src/utils/autocorrection_threshold_utils.cpp index 1f8ee0814..349786a27 100644 --- a/native/jni/src/utils/autocorrection_threshold_utils.cpp +++ b/native/jni/src/utils/autocorrection_threshold_utils.cpp @@ -16,6 +16,7 @@ #include "utils/autocorrection_threshold_utils.h" +#include <algorithm> #include <cmath> #include "defines.h" @@ -99,7 +100,7 @@ const int AutocorrectionThresholdUtils::FULL_WORD_MULTIPLIER = 2; const float maxScore = score >= S_INT_MAX ? static_cast<float>(S_INT_MAX) : static_cast<float>(MAX_INITIAL_SCORE) * powf(static_cast<float>(TYPED_LETTER_MULTIPLIER), - static_cast<float>(min(beforeLength, afterLength - spaceCount))) + static_cast<float>(std::min(beforeLength, afterLength - spaceCount))) * static_cast<float>(FULL_WORD_MULTIPLIER); return (static_cast<float>(score) / maxScore) * weight; diff --git a/native/jni/src/utils/char_utils.cpp b/native/jni/src/utils/char_utils.cpp index 0e7039610..adc474b4c 100644 --- a/native/jni/src/utils/char_utils.cpp +++ b/native/jni/src/utils/char_utils.cpp @@ -1118,7 +1118,8 @@ static int compare_pair_capital(const void *a, const void *b) { /* U+0118 */ 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067, /* U+0120 */ 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127, /* U+0128 */ 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, - /* U+0130 */ 0x0049, 0x0131, 0x0049, 0x0069, 0x004A, 0x006A, 0x004B, 0x006B, + // U+0131: Manually changed from 0131 to 0049 + /* U+0130 */ 0x0049, 0x0049, 0x0049, 0x0069, 0x004A, 0x006A, 0x004B, 0x006B, /* U+0138 */ 0x0138, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C, /* U+0140 */ 0x006C, 0x004C, 0x006C, 0x004E, 0x006E, 0x004E, 0x006E, 0x004E, // U+0141: Manually changed from 0141 to 004C @@ -1273,4 +1274,6 @@ static int compare_pair_capital(const void *a, const void *b) { /* U+04F0 */ 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04F6, 0x04F7, /* U+04F8 */ 0x042B, 0x044B, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, }; + +/* static */ const std::vector<int> CharUtils::EMPTY_STRING(1 /* size */, '\0' /* value */); } // namespace latinime diff --git a/native/jni/src/utils/char_utils.h b/native/jni/src/utils/char_utils.h index 41663c81a..239419d5b 100644 --- a/native/jni/src/utils/char_utils.h +++ b/native/jni/src/utils/char_utils.h @@ -18,6 +18,7 @@ #define LATINIME_CHAR_UTILS_H #include <cctype> +#include <vector> #include "defines.h" @@ -86,6 +87,7 @@ class CharUtils { } static unsigned short latin_tolower(const unsigned short c); + static const std::vector<int> EMPTY_STRING; private: DISALLOW_IMPLICIT_CONSTRUCTORS(CharUtils); diff --git a/native/jni/src/utils/hash_map_compat.h b/native/jni/src/utils/hash_map_compat.h deleted file mode 100644 index a1e982bc4..000000000 --- a/native/jni/src/utils/hash_map_compat.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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_HASH_MAP_COMPAT_H -#define LATINIME_HASH_MAP_COMPAT_H - -// TODO: Use std::unordered_map that has been standardized in C++11 - -#ifdef __APPLE__ -#include <ext/hash_map> -#else // __APPLE__ -#include <hash_map> -#endif // __APPLE__ - -#ifdef __SGI_STL_PORT -#define hash_map_compat stlport::hash_map -#else // __SGI_STL_PORT -#define hash_map_compat __gnu_cxx::hash_map -#endif // __SGI_STL_PORT - -#endif // LATINIME_HASH_MAP_COMPAT_H diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h new file mode 100644 index 000000000..2ce02dc05 --- /dev/null +++ b/native/jni/src/utils/jni_data_utils.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 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_JNI_DATA_UTILS_H +#define LATINIME_JNI_DATA_UTILS_H + +#include <vector> + +#include "defines.h" +#include "jni.h" +#include "suggest/core/policy/dictionary_header_structure_policy.h" +#include "suggest/policyimpl/dictionary/header/header_read_write_utils.h" + +namespace latinime { + +class JniDataUtils { + public: + static void jintarrayToVector(JNIEnv *env, jintArray array, std::vector<int> *const outVector) { + if (!array) { + outVector->clear(); + return; + } + const jsize arrayLength = env->GetArrayLength(array); + outVector->resize(arrayLength); + env->GetIntArrayRegion(array, 0 /* start */, arrayLength, outVector->data()); + } + + static DictionaryHeaderStructurePolicy::AttributeMap constructAttributeMap(JNIEnv *env, + jobjectArray attributeKeyStringArray, jobjectArray attributeValueStringArray) { + DictionaryHeaderStructurePolicy::AttributeMap attributeMap; + const int keyCount = env->GetArrayLength(attributeKeyStringArray); + for (int i = 0; i < keyCount; i++) { + jstring keyString = static_cast<jstring>( + env->GetObjectArrayElement(attributeKeyStringArray, i)); + const jsize keyUtf8Length = env->GetStringUTFLength(keyString); + char keyChars[keyUtf8Length + 1]; + env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars); + keyChars[keyUtf8Length] = '\0'; + DictionaryHeaderStructurePolicy::AttributeMap::key_type key; + HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key); + + jstring valueString = static_cast<jstring>( + env->GetObjectArrayElement(attributeValueStringArray, i)); + const jsize valueUtf8Length = env->GetStringUTFLength(valueString); + char valueChars[valueUtf8Length + 1]; + env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars); + valueChars[valueUtf8Length] = '\0'; + DictionaryHeaderStructurePolicy::AttributeMap::mapped_type value; + HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); + attributeMap[key] = value; + } + return attributeMap; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(JniDataUtils); +}; +} // namespace latinime +#endif // LATINIME_JNI_DATA_UTILS_H diff --git a/native/jni/src/utils/time_keeper.cpp b/native/jni/src/utils/time_keeper.cpp new file mode 100644 index 000000000..026284060 --- /dev/null +++ b/native/jni/src/utils/time_keeper.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013, 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. + */ + +#include "utils/time_keeper.h" + +#include <ctime> + +namespace latinime { + +int TimeKeeper::sCurrentTime; +bool TimeKeeper::sSetForTesting; + +/* static */ void TimeKeeper::setCurrentTime() { + if (!sSetForTesting) { + sCurrentTime = time(0); + } +} + +/* static */ void TimeKeeper::startTestModeWithForceCurrentTime(const int currentTime) { + sCurrentTime = currentTime; + sSetForTesting = true; +} + +/* static */ void TimeKeeper::stopTestMode() { + sSetForTesting = false; +} + +} // namespace latinime diff --git a/native/jni/src/utils/time_keeper.h b/native/jni/src/utils/time_keeper.h new file mode 100644 index 000000000..d066757e4 --- /dev/null +++ b/native/jni/src/utils/time_keeper.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013, 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_TIME_KEEPER_H +#define LATINIME_TIME_KEEPER_H + +#include "defines.h" + +namespace latinime { + +class TimeKeeper { + public: + static void setCurrentTime(); + + static void startTestModeWithForceCurrentTime(const int currentTime); + + static void stopTestMode(); + + static int peekCurrentTime() { return sCurrentTime; }; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TimeKeeper); + + static int sCurrentTime; + static bool sSetForTesting; +}; +} // namespace latinime +#endif /* LATINIME_TIME_KEEPER_H */ diff --git a/native/jni/src/suggest/core/dicnode/dic_node_release_listener.h b/native/jni/tests/defines_test.cpp index 2ca4f21bd..f7b80b2b5 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_release_listener.h +++ b/native/jni/tests/defines_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 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,22 +14,21 @@ * limitations under the License. */ -#ifndef LATINIME_DIC_NODE_RELEASE_LISTENER_H -#define LATINIME_DIC_NODE_RELEASE_LISTENER_H - #include "defines.h" +#include <gtest/gtest.h> + namespace latinime { +namespace { -class DicNode; +TEST(DefinesTest, NELEMSForFixedLengthArray) { + const size_t SMALL_ARRAY_SIZE = 1; + const size_t LARGE_ARRAY_SIZE = 100; + int smallArray[SMALL_ARRAY_SIZE]; + int largeArray[LARGE_ARRAY_SIZE]; + EXPECT_EQ(SMALL_ARRAY_SIZE, NELEMS(smallArray)); + EXPECT_EQ(LARGE_ARRAY_SIZE, NELEMS(largeArray)); +} -class DicNodeReleaseListener { - public: - DicNodeReleaseListener() {} - virtual ~DicNodeReleaseListener() {} - virtual void onReleased(DicNode *dicNode) = 0; - private: - DISALLOW_COPY_AND_ASSIGN(DicNodeReleaseListener); -}; -} // namespace latinime -#endif // LATINIME_DIC_NODE_RELEASE_LISTENER_H +} // namespace +} // namespace latinime diff --git a/native/jni/tests/suggest/core/dictionary/bloom_filter_test.cpp b/native/jni/tests/suggest/core/dictionary/bloom_filter_test.cpp new file mode 100644 index 000000000..b62021784 --- /dev/null +++ b/native/jni/tests/suggest/core/dictionary/bloom_filter_test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "suggest/core/dictionary/bloom_filter.h" + +#include <gtest/gtest.h> + +#include <algorithm> +#include <cstdlib> +#include <functional> +#include <random> +#include <unordered_set> +#include <vector> + +namespace latinime { +namespace { + +TEST(BloomFilterTest, TestFilter) { + static const int TEST_RANDOM_DATA_MAX = 65536; + static const int ELEMENT_COUNT = 1000; + std::vector<int> elements; + + // Initialize data set with random integers. + { + // Use the uniform integer distribution [0, TEST_RANDOM_DATA_MAX]. + std::uniform_int_distribution<int> distribution(0, TEST_RANDOM_DATA_MAX); + auto randomNumberGenerator = std::bind(distribution, std::mt19937()); + for (int i = 0; i < ELEMENT_COUNT; ++i) { + elements.push_back(randomNumberGenerator()); + } + } + + // Make sure BloomFilter contains nothing by default. + BloomFilter bloomFilter; + for (const int elem : elements) { + ASSERT_FALSE(bloomFilter.isInFilter(elem)); + } + + // Copy some of the test vector into bloom filter. + std::unordered_set<int> elementsThatHaveBeenSetInFilter; + { + // Use the uniform integer distribution [0, 1]. + std::uniform_int_distribution<int> distribution(0, 1); + auto randomBitGenerator = std::bind(distribution, std::mt19937()); + for (const int elem : elements) { + if (randomBitGenerator() == 0) { + bloomFilter.setInFilter(elem); + elementsThatHaveBeenSetInFilter.insert(elem); + } + } + } + + for (const int elem : elements) { + const bool existsInFilter = bloomFilter.isInFilter(elem); + const bool hasBeenSetInFilter = + elementsThatHaveBeenSetInFilter.find(elem) != elementsThatHaveBeenSetInFilter.end(); + if (hasBeenSetInFilter) { + EXPECT_TRUE(existsInFilter) << "elem: " << elem; + } + if (!existsInFilter) { + EXPECT_FALSE(hasBeenSetInFilter) << "elem: " << elem; + } + } +} + +} // namespace +} // namespace latinime diff --git a/native/jni/tests/suggest/core/layout/normal_distribution_2d_test.cpp b/native/jni/tests/suggest/core/layout/normal_distribution_2d_test.cpp new file mode 100644 index 000000000..1d6a27c4f --- /dev/null +++ b/native/jni/tests/suggest/core/layout/normal_distribution_2d_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "suggest/core/layout/normal_distribution_2d.h" + +#include <gtest/gtest.h> + +#include <vector> + +namespace latinime { +namespace { + +static const float ORIGIN_X = 0.0f; +static const float ORIGIN_Y = 0.0f; +static const float LARGE_STANDARD_DEVIATION = 100.0f; +static const float SMALL_STANDARD_DEVIATION = 10.0f; +static const float ZERO_RADIAN = 0.0f; + +TEST(NormalDistribution2DTest, ProbabilityDensity) { + const NormalDistribution2D distribution(ORIGIN_X, LARGE_STANDARD_DEVIATION, ORIGIN_Y, + SMALL_STANDARD_DEVIATION, ZERO_RADIAN); + + static const float SMALL_COORDINATE = 10.0f; + static const float LARGE_COORDINATE = 20.0f; + // The probability density of the point near the distribution center is larger than the + // probability density of the point that is far from distribution center. + EXPECT_GE(distribution.getProbabilityDensity(SMALL_COORDINATE, SMALL_COORDINATE), + distribution.getProbabilityDensity(LARGE_COORDINATE, LARGE_COORDINATE)); + // The probability density of the point shifted toward the direction that has larger standard + // deviation is larger than the probability density of the point shifted towards another + // direction. + EXPECT_GE(distribution.getProbabilityDensity(LARGE_COORDINATE, SMALL_COORDINATE), + distribution.getProbabilityDensity(SMALL_COORDINATE, LARGE_COORDINATE)); +} + +TEST(NormalDistribution2DTest, Rotate) { + static const float COORDINATES[] = {0.0f, 10.0f, 100.0f, -20.0f}; + static const float EPSILON = 0.01f; + const NormalDistribution2D distribution(ORIGIN_X, LARGE_STANDARD_DEVIATION, ORIGIN_Y, + SMALL_STANDARD_DEVIATION, ZERO_RADIAN); + const NormalDistribution2D rotatedDistribution(ORIGIN_X, LARGE_STANDARD_DEVIATION, ORIGIN_Y, + SMALL_STANDARD_DEVIATION, M_PI_4); + for (const float x : COORDINATES) { + for (const float y : COORDINATES) { + // The probability density of the rotated distribution at the point and the probability + // density of the original distribution at the rotated point are the same. + const float probabilityDensity0 = distribution.getProbabilityDensity(x, y); + const float probabilityDensity1 = rotatedDistribution.getProbabilityDensity(-y, x); + EXPECT_NEAR(probabilityDensity0, probabilityDensity1, EPSILON); + } + } +} + +} // namespace +} // namespace latinime diff --git a/native/jni/tests/utils/autocorrection_threshold_utils_test.cpp b/native/jni/tests/utils/autocorrection_threshold_utils_test.cpp new file mode 100644 index 000000000..cc8db700f --- /dev/null +++ b/native/jni/tests/utils/autocorrection_threshold_utils_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "utils/autocorrection_threshold_utils.h" + +#include <gtest/gtest.h> + +#include <vector> + +namespace latinime { +namespace { + +int CalcEditDistance(const std::vector<int> &before, + const std::vector<int> &after) { + return AutocorrectionThresholdUtils::editDistance( + &before[0], before.size(), &after[0], after.size()); +} + +TEST(AutocorrectionThresholdUtilsTest, SameData) { + EXPECT_EQ(0, CalcEditDistance({1}, {1})); + EXPECT_EQ(0, CalcEditDistance({2, 2}, {2, 2})); + EXPECT_EQ(0, CalcEditDistance({3, 3, 3}, {3, 3, 3})); +} + +} // namespace +} // namespace latinime diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 09a63c590..4ca846be1 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.inputmethod.latin.tests"> - <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" /> + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> diff --git a/tests/res/values/donottranslate.xml b/tests/res/values/donottranslate.xml index 3f7634a03..263d0af24 100644 --- a/tests/res/values/donottranslate.xml +++ b/tests/res/values/donottranslate.xml @@ -58,5 +58,5 @@ <string name="upper_indirect_string_with_literal">x,!TEXT/MULTIPLE_CHARS,y</string> <string name="upper_indirect2_string">!TEXT/UPPER_INDIRECT_STRING</string> <string name="upper_infinite_indirection">infinite,!TEXT/INFINITE_INDIRECTION,loop</string> - <string name="indirect_navigate_actions_as_more_key">!fixedColumnOrder!2,!text/action_previous_as_more_key,!text/action_next_as_more_key</string> + <string name="keyspec_indirect_navigate_actions">!fixedColumnOrder!2,!text/keyspec_action_previous,!text/keyspec_action_next</string> </resources> diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java new file mode 100644 index 000000000..06139b808 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2014 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.res.Resources; +import android.test.suitebuilder.annotation.MediumTest; +import android.text.InputType; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.RunInLocale; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +@MediumTest +public final class KeyboardLayoutSetActionLabelTests extends KeyboardLayoutSetTestsBase { + private static void doTestActionKey(final String tag, final KeyboardLayoutSet layoutSet, + final int elementId, final String label, final int iconId) { + final Keyboard keyboard = layoutSet.getKeyboard(elementId); + final Key enterKey = keyboard.getKey(Constants.CODE_ENTER); + assertNotNull(tag + " enter key on " + keyboard.mId, enterKey); + assertEquals(tag + " enter label " + enterKey, label, enterKey.getLabel()); + assertEquals(tag + " enter icon " + enterKey, iconId, enterKey.getIconId()); + } + + private void doTestActionLabel(final String tag, final InputMethodSubtype subtype, + final int actionId, final int labelResId) { + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.imeOptions = actionId; + final RunInLocale<String> job = new RunInLocale<String>() { + @Override + protected String job(final Resources res) { + return res.getString(labelResId); + } + }; + final Resources res = getContext().getResources(); + final String label; + if (subtype.getLocale().equals(SubtypeLocaleUtils.NO_LANGUAGE)) { + // Using system locale. + label = res.getString(labelResId); + } else { + label = job.runInLocale(res, SubtypeLocaleUtils.getSubtypeLocale(subtype)); + } + // Test text layouts. + editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; + final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test phone number layouts. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test normal number layout. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test number password layouts. + editorInfo.inputType = + InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, + label, KeyboardIconsSet.ICON_UNDEFINED); + } + + private void doTestActionKeyIcon(final String tag, final InputMethodSubtype subtype, + final int actionId, final String iconName) { + final int iconId = KeyboardIconsSet.getIconId(iconName); + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.imeOptions = actionId; + // Test text layouts. + editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; + final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, null /* label */, iconId); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, null /* label */, iconId); + doTestActionKey( + tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, null /* label */, iconId); + // Test phone number layouts. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, null /* label */, iconId); + doTestActionKey( + tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, null /* label */, iconId); + // Test normal number layout. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId); + // Test number password layout. + editorInfo.inputType = + InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId); + } + + public void testActionUnspecified() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "unspecifiled " + + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_UNSPECIFIED, "enter_key"); + } + } + + public void testActionNone() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "none " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_NONE, "enter_key"); + } + } + + public void testActionGo() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "go " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_GO, R.string.label_go_key); + } + } + + public void testActionSearch() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "search " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_SEARCH, "search_key"); + } + } + + public void testActionSend() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "send " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_SEND, R.string.label_send_key); + } + } + + public void testActionNext() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "next " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_NEXT, R.string.label_next_key); + } + } + + public void testActionDone() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "done " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_DONE, R.string.label_done_key); + } + } + + public void testActionPrevious() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "previous " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel( + tag, subtype, EditorInfo.IME_ACTION_PREVIOUS, R.string.label_previous_key); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java new file mode 100644 index 000000000..e4aaf0317 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.ArrayList; + +@SmallTest +public class KeyboardLayoutSetSubtypesCountTests extends KeyboardLayoutSetTestsBase { + private static final int NUMBER_OF_SUBTYPES = 70; + private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 45; + private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2; + + private static String toString(final ArrayList<InputMethodSubtype> subtypeList) { + final StringBuilder sb = new StringBuilder(); + for (int index = 0; index < subtypeList.size(); index++) { + final InputMethodSubtype subtype = subtypeList.get(index); + sb.append(index + ": "); + sb.append(SubtypeLocaleUtils.getSubtypeNameForLogging(subtype)); + sb.append("\n"); + } + return sb.toString(); + } + + public final void testAllSubtypesCount() { + final ArrayList<InputMethodSubtype> allSubtypesList = getAllSubtypesList(); + assertEquals(toString(allSubtypesList), NUMBER_OF_SUBTYPES, allSubtypesList.size()); + } + + public final void testAsciiCapableSubtypesCount() { + final ArrayList<InputMethodSubtype> asciiCapableSubtypesList = + getAsciiCapableSubtypesList(); + assertEquals(toString(asciiCapableSubtypesList), + NUMBER_OF_ASCII_CAPABLE_SUBTYPES, asciiCapableSubtypesList.size()); + } + + public final void testAdditionalSubtypesCount() { + final ArrayList<InputMethodSubtype> additionalSubtypesList = getAdditionalSubtypesList(); + assertEquals(toString(additionalSubtypesList), + NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES, additionalSubtypesList.size()); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java new file mode 100644 index 000000000..0fb6ff2b4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 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.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.ContextThemeWrapper; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; +import com.android.inputmethod.keyboard.KeyboardLayoutSet.Builder; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputMethodManager; +import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.ResourceUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.ArrayList; +import java.util.Locale; + +@SmallTest +public class KeyboardLayoutSetTestsBase extends AndroidTestCase { + private static final KeyboardTheme DEFAULT_KEYBOARD_THEME = + KeyboardTheme.getDefaultKeyboardTheme(); + + // All input method subtypes of LatinIME. + private final ArrayList<InputMethodSubtype> mAllSubtypesList = CollectionUtils.newArrayList(); + private final ArrayList<InputMethodSubtype> mAsciiCapableSubtypesList = + CollectionUtils.newArrayList(); + private final ArrayList<InputMethodSubtype> mAdditionalSubtypesList = + CollectionUtils.newArrayList(); + + private Context mThemeContext; + private int mScreenMetrics; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics); + + mThemeContext = new ContextThemeWrapper(mContext, DEFAULT_KEYBOARD_THEME.mStyleId); + RichInputMethodManager.init(mThemeContext); + final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); + + final InputMethodInfo imi = richImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + if (AdditionalSubtypeUtils.isAdditionalSubtype(subtype)) { + mAdditionalSubtypesList.add(subtype); + continue; + } + mAllSubtypesList.add(subtype); + if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) { + mAsciiCapableSubtypesList.add(subtype); + } + } + } + + protected final ArrayList<InputMethodSubtype> getAllSubtypesList() { + return mAllSubtypesList; + } + + protected final ArrayList<InputMethodSubtype> getAsciiCapableSubtypesList() { + return mAsciiCapableSubtypesList; + } + + protected final ArrayList<InputMethodSubtype> getAdditionalSubtypesList() { + return mAdditionalSubtypesList; + } + + protected final boolean isPhone() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; + } + + protected final InputMethodSubtype getSubtype(final Locale locale, + final String keyboardLayout) { + for (final InputMethodSubtype subtype : mAllSubtypesList) { + final Locale subtypeLocale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + final String subtypeLayout = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype); + if (locale.equals(subtypeLocale) && keyboardLayout.equals(subtypeLayout)) { + // Found subtype that matches locale and keyboard layout. + return subtype; + } + } + for (final InputMethodSubtype subtype : mAsciiCapableSubtypesList) { + final Locale subtypeLocale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + if (locale.equals(subtypeLocale)) { + // Create additional subtype. + return AdditionalSubtypeUtils.createAdditionalSubtype( + locale.toString(), keyboardLayout, null /* extraValue */); + } + } + throw new RuntimeException( + "Unknown subtype: locale=" + locale + " keyboardLayout=" + keyboardLayout); + } + + protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype, + final EditorInfo editorInfo) { + return createKeyboardLayoutSet(subtype, editorInfo, false /* isShortcutImeEnabled */, + false /* showsVoiceInputKey */, false /* isLanguageSwitchKeyEnabled */); + } + + protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype, + final EditorInfo editorInfo, final boolean isShortcutImeEnabled, + final boolean showsVoiceInputKey, final boolean isLanguageSwitchKeyEnabled) { + final Context context = mThemeContext; + final Resources res = context.getResources(); + final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res); + final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res); + final Builder builder = new Builder(context, editorInfo); + builder.setKeyboardGeometry(keyboardWidth, keyboardHeight) + .setSubtype(subtype) + .setOptions(isShortcutImeEnabled, showsVoiceInputKey, isLanguageSwitchKeyEnabled); + return builder.build(); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java index afb2b0343..8e26e7fc7 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2014 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. @@ -17,643 +17,39 @@ package com.android.inputmethod.keyboard.internal; import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; -import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT; import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; -import android.content.Context; -import android.content.res.Resources; -import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.utils.RunInLocale; - -import java.util.Arrays; -import java.util.Locale; @SmallTest -public class KeySpecParserTests extends AndroidTestCase { - private final static Locale TEST_LOCALE = Locale.ENGLISH; - final KeyboardCodesSet mCodesSet = new KeyboardCodesSet(); - final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); - - private static final String CODE_SETTINGS = "!code/key_settings"; - private static final String ICON_SETTINGS = "!icon/settings_key"; - private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(Locale.ROOT); - private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(Locale.ROOT); - private static final String CODE_NON_EXISTING = "!code/non_existing"; - private static final String ICON_NON_EXISTING = "!icon/non_existing"; - - private int mCodeSettings; - private int mCodeActionNext; - private int mSettingsIconId; - +public final class KeySpecParserTests extends KeySpecParserTestsBase { @Override - protected void setUp() throws Exception { - super.setUp(); - - final String language = TEST_LOCALE.getLanguage(); - mCodesSet.setLanguage(language); - mTextsSet.setLanguage(language); - final Context context = getContext(); - new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - mTextsSet.loadStringResources(context); - return null; - } - }.runInLocale(context.getResources(), TEST_LOCALE); - - mCodeSettings = KeySpecParser.parseCode( - CODE_SETTINGS, mCodesSet, CODE_UNSPECIFIED); - mCodeActionNext = KeySpecParser.parseCode( - "!code/key_action_next", mCodesSet, CODE_UNSPECIFIED); - mSettingsIconId = KeySpecParser.getIconId(ICON_SETTINGS); - } - - private void assertParser(String message, String moreKeySpec, String expectedLabel, - String expectedOutputText, int expectedIcon, int expectedCode) { - final String labelResolved = KeySpecParser.resolveTextReference(moreKeySpec, mTextsSet); - final MoreKeySpec spec = new MoreKeySpec(labelResolved, false /* needsToUpperCase */, - Locale.US, mCodesSet); - assertEquals(message + " [label]", expectedLabel, spec.mLabel); - assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText); + protected void assertParser(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIcon, + final int expectedCode) { + final String keySpecResolved = mTextsSet.resolveTextReference(keySpec); + final String actualLabel = KeySpecParser.getLabel(keySpecResolved); + final String actualOutputText = KeySpecParser.getOutputText(keySpecResolved); + final int actualIcon = KeySpecParser.getIconId(keySpecResolved); + final int actualCode = KeySpecParser.getCode(keySpecResolved); + assertEquals(message + " [label]", expectedLabel, actualLabel); + assertEquals(message + " [ouptputText]", expectedOutputText, actualOutputText); assertEquals(message + " [icon]", KeyboardIconsSet.getIconName(expectedIcon), - KeyboardIconsSet.getIconName(spec.mIconId)); + KeyboardIconsSet.getIconName(actualIcon)); assertEquals(message + " [code]", Constants.printableCode(expectedCode), - Constants.printableCode(spec.mCode)); - } - - 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 bang", "!", - "!", null, ICON_UNDEFINED, '!'); - assertParser("Single escaped bang", "\\!", - "!", 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, CODE_OUTPUT_TEXT); - assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1, - "a", SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single surrogate with outputText", PAIR3 + "|abc", - PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped outputText", "a|a\\|c", - "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped surrogate outputText", - "a|" + PAIR1 + "\\|" + PAIR2, - "a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with comma outputText", "a|a,b", - "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped comma outputText", "a|a\\,b", - "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with outputText starts with bang", "a|!bc", - "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2, - "a", "!" + SURROGATE2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with outputText contains bang", "a|a!c", - "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Single letter with escaped bang outputText", "a|\\!bc", - "a", "!bc", ICON_UNDEFINED, 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, CODE_OUTPUT_TEXT); - assertParser("Simple surrogate label", SURROGATE1, - SURROGATE1, SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar", "a\\|c", - "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2, - PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, - ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped escape", "a\\\\c", - "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma", "a,c", - "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped comma", "a\\,c", - "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang", "!bc", - "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Surrogate label starts with bang", "!" + SURROGATE1, - "!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang", "a!c", - "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bang", "\\!bc", - "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped letter", "\\abc", - "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText", "abc|def", - "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma and outputText", "a,c|def", - "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped comma label with outputText", "a\\,c|def", - "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped label with outputText", "a\\|c|def", - "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped escape label with outputText", "a\\\\|def", - "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and outputText", "!bc|def", - "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang label and outputText", "a!c|def", - "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bang label with outputText", "\\!bc|def", - "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with comma outputText", "abc|a,b", - "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped comma outputText", "abc|a\\,b", - "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText starts with bang", "abc|!bc", - "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with outputText contains bang", "abc|a!c", - "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bang outputText", "abc|\\!bc", - "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", - "a|c", "d|f", ICON_UNDEFINED, 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, CODE_OUTPUT_TEXT); - assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", - null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", - null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", - null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, - "!bc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, - "a!c", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Escaped bang 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 testResourceReference() { - assertParser("Settings as more key", "!text/settings_as_more_key", - null, null, mSettingsIconId, mCodeSettings); - - assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next", - "Next", null, ICON_UNDEFINED, mCodeActionNext); - - assertParser("Popular domain", - "!text/keylabel_for_popular_domain|!text/keylabel_for_popular_domain ", - ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + Constants.printableCode(actualCode)); } - public void testFormatError() { - assertParserError("Empty spec", "", null, - null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty label with outputText", "|a", - null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty label with code", "|" + CODE_SETTINGS, - null, null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Empty outputText with label", "a|", - "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Empty icon and code", "|", + // TODO: Remove this method. + // These should throw {@link KeySpecParserError} when Key.keyLabel attribute become mandatory. + public void testEmptySpec() { + assertParser("Null spec", null, + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParser("Empty spec", "", null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Icon without code", ICON_SETTINGS, - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", - null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, - "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Third bar at end", "a|b|", - "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); - assertParserError("Multiple bar", "a|b|c", - "a", null, ICON_UNDEFINED, 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, CODE_UNSPECIFIED); - assertParserError("Multiple bar with icon and code", - ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", - null, null, mSettingsIconId, mCodeSettings); - } - - public void testUselessUpperCaseSpecifier() { - assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE, - "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE, - "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE, - "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc", - "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc", - "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c", - "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc", - "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE, - "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE, - "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE, - "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE, - "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", - "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED, - CODE_OUTPUT_TEXT); - assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT", - "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED, - CODE_OUTPUT_TEXT); - assertParser("POPULAR DOMAIN", - "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", - "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", - ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE, - null, null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParser("ICON without code", ICON_SETTINGS_UPPERCASE, - "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT); - assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c", - "a", null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c", - null, null, mSettingsIconId, CODE_UNSPECIFIED); - assertParserError("Multiple bar with ICON and CODE", - ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c", - null, null, mSettingsIconId, mCodeSettings); - } - - private static void assertArrayEquals(String message, Object[] expected, Object[] actual) { - if (expected == actual) { - return; - } - if (expected == null || actual == null) { - assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); - return; - } - if (expected.length != actual.length) { - assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); - return; - } - for (int i = 0; i < expected.length; i++) { - assertEquals(message + " [" + i + "]", - Arrays.toString(expected), Arrays.toString(actual)); - } - } - - private static void assertInsertAdditionalMoreKeys(String message, String[] moreKeys, - String[] additionalMoreKeys, String[] expected) { - final String[] actual = - KeySpecParser.insertAdditionalMoreKeys( moreKeys, additionalMoreKeys); - assertArrayEquals(message, expected, actual); - } - - public void testEmptyEntry() { - assertInsertAdditionalMoreKeys("null more keys and null additons", - null, - null, - null); - assertInsertAdditionalMoreKeys("null more keys and empty additons", - null, - new String[0], - null); - assertInsertAdditionalMoreKeys("empty more keys and null additons", - new String[0], - null, - null); - assertInsertAdditionalMoreKeys("empty more keys and empty additons", - new String[0], - new String[0], - null); - - assertInsertAdditionalMoreKeys("filter out empty more keys", - new String[] { null, "a", "", "b", null }, - null, - new String[] { "a", "b" }); - assertInsertAdditionalMoreKeys("filter out empty additons", - new String[] { "a", "%", "b", "%", "c", "%", "d" }, - new String[] { null, "A", "", "B", null }, - new String[] { "a", "A", "b", "B", "c", "d" }); - } - - public void testInsertAdditionalMoreKeys() { - // Escaped marker. - assertInsertAdditionalMoreKeys("escaped marker", - new String[] { "\\%", "%-)" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "\\%", "%-)" }); - - // 0 more key. - assertInsertAdditionalMoreKeys("null & null", null, null, null); - assertInsertAdditionalMoreKeys("null & 1 additon", - null, - new String[] { "1" }, - new String[] { "1" }); - assertInsertAdditionalMoreKeys("null & 2 additons", - null, - new String[] { "1", "2" }, - new String[] { "1", "2" }); - - // 0 additional more key. - assertInsertAdditionalMoreKeys("1 more key & null", - new String[] { "A" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("2 more keys & null", - new String[] { "A", "B" }, - null, - new String[] { "A", "B" }); - - // No marker. - assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker", - new String[] { "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker", - new String[] { "A" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker", - new String[] { "A", "B" }, - new String[] { "1" }, - new String[] { "1", "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker", - new String[] { "A", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A", "B" }); - - // 1 marker. - assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head", - new String[] { "%", "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail", - new String[] { "A", "%" }, - new String[] { "1" }, - new String[] { "A", "1" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle", - new String[] { "A", "%", "B" }, - new String[] { "1" }, - new String[] { "A", "1", "B" }); - - // 1 marker & excess additional more keys. - assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head", - new String[] { "%", "A", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "B", "2" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail", - new String[] { "A", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "A", "B", "1", "2" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle", - new String[] { "A", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "B", "2" }); - - // 2 markers. - assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers", - new String[] { "%", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "2" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head", - new String[] { "%", "%", "A" }, - new String[] { "1", "2" }, - new String[] { "1", "2", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail", - new String[] { "A", "%", "%" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "2" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "A", "1", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", - new String[] { "%", "A", "%", "B" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", - new String[] { "%", "A", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "B", "2" }); - assertInsertAdditionalMoreKeys("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 more keys. - assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers", - new String[] { "%", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "2", "3" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head", - new String[] { "%", "%", "A" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "2", "A", "3" }); - assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail", - new String[] { "A", "%", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "A", "1", "2", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1", "2", "3" }, - new String[] { "A", "1", "2", "B", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", - new String[] { "%", "A", "%", "B" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "2", "B", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", - new String[] { "%", "A", "B", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "B", "2", "3" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 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. - assertInsertAdditionalMoreKeys("0 more key & null & excess marker", - new String[] { "%" }, - null, - null); - assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head", - new String[] { "%", "A" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail", - new String[] { "A", "%" }, - null, - new String[] { "A" }); - assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle", - new String[] { "A", "%", "B" }, - null, - new String[] { "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & null & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - null, - new String[] { "A", "B" }); - - // Excess markers. - assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker", - new String[] { "%", "%" }, - new String[] { "1" }, - new String[] { "1" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head", - new String[] { "%", "%", "A" }, - new String[] { "1" }, - new String[] { "1", "A" }); - assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail", - new String[] { "A", "%", "%" }, - new String[] { "1" }, - new String[] { "A", "1" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle", - new String[] { "A", "%", "%", "B" }, - new String[] { "1" }, - new String[] { "A", "1", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - new String[] { "1" }, - new String[] { "1", "A", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers", - new String[] { "%", "A", "%", "B", "%" }, - new String[] { "1", "2" }, - new String[] { "1", "A", "2", "B" }); - assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers", - new String[] { "%", "A", "%", "%", "B", "%" }, - new String[] { "1", "2", "3" }, - new String[] { "1", "A", "2", "3", "B" }); - } - - private static final String HAS_LABEL = "!hasLabel!"; - private static final String NEEDS_DIVIDER = "!needsDividers!"; - private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!"; - private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; - - private static void assertGetBooleanValue(String message, String key, String[] moreKeys, - String[] expected, boolean expectedValue) { - final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); - final boolean actualValue = KeySpecParser.getBooleanValue(actual, key); - assertEquals(message + " [value]", expectedValue, actualValue); - assertArrayEquals(message, expected, actual); - } - - public void testGetBooleanValue() { - assertGetBooleanValue("Has label", HAS_LABEL, - new String[] { HAS_LABEL, "a", "b", "c" }, - new String[] { null, "a", "b", "c" }, true); - // Upper case specification will not work. - assertGetBooleanValue("HAS LABEL", HAS_LABEL, - new String[] { HAS_LABEL.toUpperCase(Locale.ROOT), "a", "b", "c" }, - new String[] { "!HASLABEL!", "a", "b", "c" }, false); - - assertGetBooleanValue("No has label", HAS_LABEL, - new String[] { "a", "b", "c" }, - new String[] { "a", "b", "c" }, false); - assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false); - - // Upper case specification will not work. - assertGetBooleanValue("Multiple has label", HAS_LABEL, - new String[] { - "a", HAS_LABEL.toUpperCase(Locale.ROOT), "b", "c", HAS_LABEL, "d" }, - new String[] { - "a", "!HASLABEL!", "b", "c", null, "d" }, true); - // Upper case specification will not work. - assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL, - new String[] { - "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(Locale.ROOT), "d" }, - new String[] { - "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true); - } - - private static void assertGetIntValue(String message, String key, int defaultValue, - String[] moreKeys, String[] expected, int expectedValue) { - final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); - final int actualValue = KeySpecParser.getIntValue(actual, key, defaultValue); - assertEquals(message + " [value]", expectedValue, actualValue); - assertArrayEquals(message, expected, actual); - } - - public void testGetIntValue() { - assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, - new String[] { null, "a", "b", "c" }, 3); - // Upper case specification will not work. - assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "3", "a", "b", "c" }, - new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1); - - assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1, - new String[] { "a", "b", "c" }, - new String[] { "a", "b", "c" }, -1); - assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1, - new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, - new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1); - - assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1, - new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" }, - new String[] { null, "a", null, "b" }, 3); - // Upper case specification will not work. - assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1, - new String[] { - FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "5", HAS_LABEL, "a", - FIXED_COLUMN_ORDER + "3", "b" }, - new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3); } } diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java new file mode 100644 index 000000000..b8cb11b6b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTestsBase.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2014 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 static com.android.inputmethod.keyboard.internal.KeyboardCodesSet.PREFIX_CODE; +import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; +import static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.PREFIX_ICON; +import static com.android.inputmethod.latin.Constants.CODE_OUTPUT_TEXT; +import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; + +import android.test.AndroidTestCase; + +import java.util.Locale; + +abstract class KeySpecParserTestsBase extends AndroidTestCase { + private final static Locale TEST_LOCALE = Locale.ENGLISH; + protected final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); + + private static final String CODE_SETTINGS_NAME = "key_settings"; + private static final String CODE_SETTINGS = PREFIX_CODE + CODE_SETTINGS_NAME; + private static final String ICON_SETTINGS_NAME = "settings_key"; + private static final String ICON_SETTINGS = PREFIX_ICON + ICON_SETTINGS_NAME; + private static final String CODE_SETTINGS_UPPERCASE = CODE_SETTINGS.toUpperCase(Locale.ROOT); + private static final String ICON_SETTINGS_UPPERCASE = ICON_SETTINGS.toUpperCase(Locale.ROOT); + private static final String CODE_NON_EXISTING = PREFIX_CODE + "non_existing"; + private static final String ICON_NON_EXISTING = PREFIX_ICON + "non_existing"; + + private int mCodeSettings; + private int mCodeActionNext; + private int mSettingsIconId; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mTextsSet.setLocale(TEST_LOCALE, getContext()); + mCodeSettings = KeyboardCodesSet.getCode(CODE_SETTINGS_NAME); + mCodeActionNext = KeyboardCodesSet.getCode("key_action_next"); + mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME); + } + + abstract protected void assertParser(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIcon, + final int expectedCode); + + protected void assertParserError(final String message, final String keySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIconId, + final int expectedCode) { + try { + assertParser(message, keySpec, expectedLabel, expectedOutputText, expectedIconId, + expectedCode); + fail(message); + } catch (Exception pcpe) { + // success. + } + } + + // \U001d11e: MUSICAL SYMBOL G CLEF + private static final String SURROGATE_PAIR1 = "\ud834\udd1e"; + private static final int SURROGATE_CODE1 = SURROGATE_PAIR1.codePointAt(0); + // \U001d122: MUSICAL SYMBOL F CLEF + private static final String SURROGATE_PAIR2 = "\ud834\udd22"; + private static final int SURROGATE_CODE2 = SURROGATE_PAIR2.codePointAt(0); + // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. + private static final String SURROGATE_PAIR3 = "\ud87e\udca6"; + private static final String SURROGATE_PAIRS4 = SURROGATE_PAIR1 + SURROGATE_PAIR2; + private static final String SURROGATE_PAIRS5 = SURROGATE_PAIRS4 + SURROGATE_PAIR3; + + public void testSingleLetter() { + assertParser("Single letter", "a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate", SURROGATE_PAIR1, + SURROGATE_PAIR1, null, ICON_UNDEFINED, SURROGATE_CODE1); + assertParser("Sole vertical bar", "|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single escaped vertical 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", "\\" + SURROGATE_PAIR2, + SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2); + assertParser("Single bang", "!", + "!", null, ICON_UNDEFINED, '!'); + assertParser("Single escaped bang", "\\!", + "!", null, ICON_UNDEFINED, '!'); + assertParser("Single output text letter", "a|a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate pair outputText", "G Clef|" + SURROGATE_PAIR1, + "G Clef", null, ICON_UNDEFINED, SURROGATE_CODE1); + assertParser("Single letter with outputText", "a|abc", + "a", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText", "a|" + SURROGATE_PAIRS4, + "a", SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single surrogate with outputText", SURROGATE_PAIR3 + "|abc", + SURROGATE_PAIR3, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped outputText", "a|a\\|c", + "a", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped surrogate outputText", + "a|" + SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2, + "a", SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with comma outputText", "a|a,b", + "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped comma outputText", "a|a\\,b", + "a", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText starts with bang", "a|!bc", + "a", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText starts with bang", + "a|!" + SURROGATE_PAIRS5, + "a", "!" + SURROGATE_PAIRS5, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText contains bang", "a|a!c", + "a", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped bang outputText", "a|\\!bc", + "a", "!bc", ICON_UNDEFINED, 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, CODE_OUTPUT_TEXT); + assertParser("Simple surrogate label", SURROGATE_PAIRS4, + SURROGATE_PAIRS4, SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar", "a\\|c", + "a|c", "a|c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Surrogate label with escaped bar", SURROGATE_PAIR1 + "\\|" + SURROGATE_PAIR2, + SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, SURROGATE_PAIR1 + "|" + SURROGATE_PAIR2, + ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped escape", "a\\\\c", + "a\\c", "a\\c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma", "a,c", + "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma", "a\\,c", + "a,c", "a,c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang", "!bc", + "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Surrogate label starts with bang", "!" + SURROGATE_PAIRS4, + "!" + SURROGATE_PAIRS4, "!" + SURROGATE_PAIRS4, ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang", "a!c", + "a!c", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bang", "\\!bc", + "!bc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped letter", "\\abc", + "abc", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText", "abc|def", + "abc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma and outputText", "a,c|def", + "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped comma label with outputText", "a\\,c|def", + "a,c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped label with outputText", "a\\|c|def", + "a|c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped escape label with outputText", "a\\\\|def", + "a\\", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and outputText", "!bc|def", + "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang label and outputText", "a!c|def", + "a!c", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bang label with outputText", "\\!bc|def", + "!bc", "def", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with comma outputText", "abc|a,b", + "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma outputText", "abc|a\\,b", + "abc", "a,b", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText starts with bang", "abc|!bc", + "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with outputText contains bang", "abc|a!c", + "abc", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bang outputText", "abc|\\!bc", + "abc", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", + "a|c", "d|f", ICON_UNDEFINED, 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 testCodes() { + assertParser("Hexadecimal code", "a|0x1000", + "a", null, ICON_UNDEFINED, 0x1000); + assertParserError("Illegal hexadecimal code", "a|0x100X", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParser("Escaped hexadecimal code 1", "a|\\0x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped hexadecimal code 2", "a|0\\x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped hexadecimal code 2", "a|0\\x1000", + "a", "0x1000", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Illegally escaped hexadecimal code", "a|0x1\\000", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + // This is a workaround to have a key that has a supplementary code point. We can't put a + // string in resource as a XML entity of a supplementary code point or a surrogate pair. + // TODO: Should pass this test. +// assertParser("Hexadecimal supplementary code", String.format("a|0x%06x", SURROGATE_CODE2), +// SURROGATE_PAIR2, null, ICON_UNDEFINED, SURROGATE_CODE2); + assertParser("Zero is treated as output text", "a|0", + "a", null, ICON_UNDEFINED, '0'); + assertParser("Digit is treated as output text", "a|3", + "a", null, ICON_UNDEFINED, '3'); + assertParser("Decimal number is treated as an output text", "a|2014", + "a", "2014", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + } + + public void testIcons() { + assertParser("Icon with single letter", ICON_SETTINGS + "|a", + null, null, mSettingsIconId, 'a'); + assertParser("Icon with outputText", ICON_SETTINGS + "|abc", + null, "abc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc", + null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c", + null, "a!c", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc", + null, "!bc", mSettingsIconId, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS, + "!bc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS, + "a!c", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Escaped bang 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 testResourceReference() { + assertParser("Settings as more key", "!text/keyspec_settings", + null, null, mSettingsIconId, mCodeSettings); + + assertParser("Action next as more key", "!text/label_next_key|!code/key_action_next", + "Next", null, ICON_UNDEFINED, mCodeActionNext); + + assertParser("Popular domain", + "!text/keyspec_popular_domain|!text/keyspec_popular_domain ", + ".com", ".com ", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + } + + public void testFormatError() { + assertParserError("Empty label with outputText", "|a", + null, "a", ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty label with code", "|" + CODE_SETTINGS, + null, null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Empty outputText with label", "a|", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Icon without code", ICON_SETTINGS, + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", + null, "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, + "abc", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Third bar at end", "a|b|", + "a", null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Multiple bar", "a|b|c", + "a", null, ICON_UNDEFINED, 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, CODE_UNSPECIFIED); + assertParserError("Multiple bar with icon and code", + ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", + null, null, mSettingsIconId, mCodeSettings); + } + + public void testUselessUpperCaseSpecifier() { + assertParser("Single letter with CODE", "a|" + CODE_SETTINGS_UPPERCASE, + "a", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label with CODE", "abc|" + CODE_SETTINGS_UPPERCASE, + "abc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped label with CODE", "a\\|c|" + CODE_SETTINGS_UPPERCASE, + "a|c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText", ICON_SETTINGS_UPPERCASE + "|abc", + "!ICON/SETTINGS_KEY", "abc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText starts with bang", ICON_SETTINGS_UPPERCASE + "|!bc", + "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with outputText contains bang", ICON_SETTINGS_UPPERCASE + "|a!c", + "!ICON/SETTINGS_KEY", "a!c", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with escaped bang outputText", ICON_SETTINGS_UPPERCASE + "|\\!bc", + "!ICON/SETTINGS_KEY", "!bc", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label starts with bang and CODE", "!bc|" + CODE_SETTINGS_UPPERCASE, + "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Label contains bang and CODE", "a!c|" + CODE_SETTINGS_UPPERCASE, + "a!c", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("Escaped bang label with CODE", "\\!bc|" + CODE_SETTINGS_UPPERCASE, + "!bc", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("ICON with CODE", ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE, + "!ICON/SETTINGS_KEY", "!CODE/KEY_SETTINGS", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParser("SETTINGS AS MORE KEY", "!TEXT/SETTINGS_AS_MORE_KEY", + "!TEXT/SETTINGS_AS_MORE_KEY", "!TEXT/SETTINGS_AS_MORE_KEY", ICON_UNDEFINED, + CODE_OUTPUT_TEXT); + assertParser("ACTION NEXT AS MORE KEY", "!TEXT/LABEL_NEXT_KEY|!CODE/KEY_ACTION_NEXT", + "!TEXT/LABEL_NEXT_KEY", "!CODE/KEY_ACTION_NEXT", ICON_UNDEFINED, + CODE_OUTPUT_TEXT); + assertParser("POPULAR DOMAIN", + "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN|!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", + "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN", "!TEXT/KEYLABEL_FOR_POPULAR_DOMAIN ", + ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Empty label with CODE", "|" + CODE_SETTINGS_UPPERCASE, + null, null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Empty outputText with ICON", ICON_SETTINGS_UPPERCASE + "|", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParser("ICON without code", ICON_SETTINGS_UPPERCASE, + "!ICON/SETTINGS_KEY", "!ICON/SETTINGS_KEY", ICON_UNDEFINED, CODE_OUTPUT_TEXT); + assertParserError("Multiple bar with label and CODE", "a|" + CODE_SETTINGS_UPPERCASE + "|c", + "a", null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Multiple bar with ICON and outputText", ICON_SETTINGS_UPPERCASE + "|b|c", + null, null, mSettingsIconId, CODE_UNSPECIFIED); + assertParserError("Multiple bar with ICON and CODE", + ICON_SETTINGS_UPPERCASE + "|" + CODE_SETTINGS_UPPERCASE + "|c", + null, null, mSettingsIconId, mCodeSettings); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java new file mode 100644 index 000000000..eb906cd9f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSetTests.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 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.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.RichInputMethodManager; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +@SmallTest +public final class KeyboardTextsSetTests extends AndroidTestCase { + // All input method subtypes of LatinIME. + private List<InputMethodSubtype> mAllSubtypesList; + + @Override + protected void setUp() throws Exception { + super.setUp(); + RichInputMethodManager.init(getContext()); + final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); + + final ArrayList<InputMethodSubtype> allSubtypesList = CollectionUtils.newArrayList(); + final InputMethodInfo imi = richImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + allSubtypesList.add(subtype); + } + mAllSubtypesList = Collections.unmodifiableList(allSubtypesList); + } + + // Test that the text {@link KeyboardTextsSet#SWITCH_TO_ALPHA_KEY_LABEL} exists for all + // subtypes. The text is needed to implement Emoji Keyboard, see + // {@link KeyboardSwitcher#setEmojiKeyboard()}. + public void testSwitchToAlphaKeyLabel() { + final Context context = getContext(); + final KeyboardTextsSet textsSet = new KeyboardTextsSet(); + for (final InputMethodSubtype subtype : mAllSubtypesList) { + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + textsSet.setLocale(locale, context); + final String switchToAlphaKeyLabel = textsSet.getText( + KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL); + assertNotNull("Switch to alpha key label of " + locale, switchToAlphaKeyLabel); + assertFalse("Switch to alpha key label of " + locale, switchToAlphaKeyLabel.isEmpty()); + } + } + + private static final String[] TEXT_NAMES_FROM_RESOURCE = { + // Labels for action. + "label_go_key", + "label_send_key", + "label_next_key", + "label_done_key", + "label_previous_key", + // Other labels. + "label_pause_key", + "label_wait_key", + }; + + // Test that the text from resources are correctly loaded for all subtypes. + public void testTextFromResources() { + final Context context = getContext(); + final KeyboardTextsSet textsSet = new KeyboardTextsSet(); + for (final InputMethodSubtype subtype : mAllSubtypesList) { + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + textsSet.setLocale(locale, context); + for (final String name : TEXT_NAMES_FROM_RESOURCE) { + final String text = textsSet.getText(name); + assertNotNull(name + " of " + locale, text); + assertFalse(name + " of " + locale, text.isEmpty()); + } + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java new file mode 100644 index 000000000..0be1e374c --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2014 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 static com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE; +import static com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper.FORMAT_TYPE_LANGUAGE_ONLY; +import static com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper.FORMAT_TYPE_NONE; + +import android.content.Context; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.RichInputMethodManager; +import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +@SmallTest +public class LanguageOnSpacebarHelperTests extends AndroidTestCase { + private final LanguageOnSpacebarHelper mLanguageOnSpacebarHelper = + new LanguageOnSpacebarHelper(); + + private RichInputMethodManager mRichImm; + + InputMethodSubtype EN_US_QWERTY; + InputMethodSubtype EN_GB_QWERTY; + InputMethodSubtype FR_AZERTY; + InputMethodSubtype FR_CA_QWERTY; + InputMethodSubtype FR_CH_SWISS; + InputMethodSubtype FR_CH_QWERTY; + InputMethodSubtype FR_CH_QWERTZ; + InputMethodSubtype ZZ_QWERTY; + + @Override + protected void setUp() throws Exception { + super.setUp(); + final Context context = getContext(); + RichInputMethodManager.init(context); + mRichImm = RichInputMethodManager.getInstance(); + SubtypeLocaleUtils.init(context); + + EN_US_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.US.toString(), "qwerty"); + EN_GB_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.UK.toString(), "qwerty"); + FR_AZERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.FRENCH.toString(), "azerty"); + FR_CA_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.CANADA_FRENCH.toString(), "qwerty"); + FR_CH_SWISS = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "fr_CH", "swiss"); + FR_CH_QWERTZ = AdditionalSubtypeUtils.createAdditionalSubtype( + "fr_CH", "qwertz", null); + FR_CH_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + "fr_CH", "qwerty", null); + ZZ_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); + } + + private static List<InputMethodSubtype> asList(final InputMethodSubtype ... subtypes) { + return Arrays.asList(subtypes); + } + + public void testOneSubtype() { + mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY)); + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */); + assertEquals("one same English (US)", FORMAT_TYPE_NONE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("one same NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + + mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(FR_AZERTY)); + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */); + assertEquals("one diff English (US)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("one diff NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + } + + public void testTwoSubtypes() { + mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY, FR_AZERTY)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */); + assertEquals("two same English (US)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("two same French)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_AZERTY)); + assertEquals("two same NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */); + assertEquals("two diff English (US)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("two diff French", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_AZERTY)); + assertEquals("two diff NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + } + + public void testSameLanuageSubtypes() { + mLanguageOnSpacebarHelper.updateEnabledSubtypes( + asList(EN_US_QWERTY, EN_GB_QWERTY, FR_AZERTY, ZZ_QWERTY)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */); + assertEquals("two same English (US)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("two same English (UK)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_GB_QWERTY)); + assertEquals("two same NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */); + assertEquals("two diff English (US)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY)); + assertEquals("two diff English (UK)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_GB_QWERTY)); + assertEquals("two diff NoLanguage", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY)); + } + + public void testMultiSameLanuageSubtypes() { + mLanguageOnSpacebarHelper.updateEnabledSubtypes( + asList(FR_AZERTY, FR_CA_QWERTY, FR_CH_SWISS, FR_CH_QWERTY, FR_CH_QWERTZ)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */); + assertEquals("multi same French", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_AZERTY)); + assertEquals("multi same French (CA)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CA_QWERTY)); + assertEquals("multi same French (CH)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_SWISS)); + assertEquals("multi same French (CH) (QWERTY)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_QWERTY)); + assertEquals("multi same French (CH) (QWERTZ)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_QWERTZ)); + + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */); + assertEquals("multi diff French", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_AZERTY)); + assertEquals("multi diff French (CA)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CA_QWERTY)); + assertEquals("multi diff French (CH)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_SWISS)); + assertEquals("multi diff French (CH) (QWERTY)", FORMAT_TYPE_FULL_LOCALE, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_QWERTY)); + assertEquals("multi diff French (CH) (QWERTZ)", FORMAT_TYPE_LANGUAGE_ONLY, + mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(FR_CH_QWERTZ)); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java index 6e3e37add..a353e5a35 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java @@ -125,8 +125,9 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } @Override - public void requestUpdatingShiftState() { - mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); + public void requestUpdatingShiftState(final int currentAutoCapsState, + final int currentRecapitalizeState) { + mState.onUpdateShiftState(currentAutoCapsState, currentRecapitalizeState); } @Override @@ -149,7 +150,7 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } public void loadKeyboard() { - mState.onLoadKeyboard(); + mState.onLoadKeyboard(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); } public void saveKeyboardState() { @@ -157,11 +158,17 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } public void onPressKey(final int code, final boolean isSinglePointer) { - mState.onPressKey(code, isSinglePointer, mAutoCapsState); + mState.onPressKey(code, isSinglePointer, mAutoCapsState, + RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); } public void onReleaseKey(final int code, final boolean withSliding) { - mState.onReleaseKey(code, withSliding); + onReleaseKey(code, withSliding, mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); + } + + public void onReleaseKey(final int code, final boolean withSliding, + final int currentAutoCapsState, final int currentRecapitalizeState) { + mState.onReleaseKey(code, withSliding, currentAutoCapsState, currentRecapitalizeState); if (mLongPressTimeoutCode == code) { mLongPressTimeoutCode = 0; } @@ -176,10 +183,10 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { } else { mAutoCapsState = mAutoCapsMode; } - mState.onCodeInput(code, mAutoCapsState); + mState.onCodeInput(code, mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); } public void onFinishSlidingInput() { - mState.onFinishSlidingInput(); + mState.onFinishSlidingInput(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE); } } diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java index 2eb448c82..514ad1cf0 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java @@ -23,7 +23,6 @@ import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.MediumTest; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.RunInLocale; import java.lang.reflect.Field; import java.util.ArrayList; @@ -31,7 +30,7 @@ import java.util.Arrays; import java.util.Locale; @MediumTest -public class KeySpecParserSplitTests extends InstrumentationTestCase { +public class MoreKeySpecSplitTests extends InstrumentationTestCase { private static final Locale TEST_LOCALE = Locale.ENGLISH; final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); @@ -41,20 +40,16 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { final Instrumentation instrumentation = getInstrumentation(); final Context targetContext = instrumentation.getTargetContext(); - mTextsSet.setLanguage(TEST_LOCALE.getLanguage()); - new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - mTextsSet.loadStringResources(targetContext); - return null; - } - }.runInLocale(targetContext.getResources(), TEST_LOCALE); + mTextsSet.setLocale(TEST_LOCALE, targetContext); final String[] testResourceNames = getAllResourceIdNames( com.android.inputmethod.latin.tests.R.string.class); - mTextsSet.loadStringResourcesInternal(instrumentation.getContext(), testResourceNames, + final Context testContext = instrumentation.getContext(); + final Resources testRes = testContext.getResources(); + final String testResPackageName = testRes.getResourcePackageName( // This dummy raw resource is needed to be able to load string resources from a test // APK successfully. com.android.inputmethod.latin.tests.R.raw.dummy_resource_for_testing); + mTextsSet.loadStringResourcesInternal(testRes, testResourceNames, testResPackageName); } private static String[] getAllResourceIdNames(final Class<?> resourceIdClass) { @@ -92,8 +87,8 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { private void assertTextArray(final String message, final String value, final String ... expectedArray) { - final String resolvedActual = KeySpecParser.resolveTextReference(value, mTextsSet); - final String[] actual = KeySpecParser.splitKeySpecs(resolvedActual); + final String resolvedActual = mTextsSet.resolveTextReference(value); + final String[] actual = MoreKeySpec.splitKeySpecs(resolvedActual); final String[] expected = (expectedArray.length == 0) ? null : expectedArray; assertArrayEquals(message, expected, actual); } @@ -116,6 +111,14 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { private static final String SURROGATE1 = PAIR1 + PAIR2; private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; + public void testResolveNullText() { + assertNull("resolve null", mTextsSet.resolveTextReference(null)); + } + + public void testResolveEmptyText() { + assertNull("resolve empty text", mTextsSet.resolveTextReference("!text/empty_string")); + } + public void testSplitZero() { assertTextArray("Empty string", ""); assertTextArray("Empty entry", ","); @@ -352,16 +355,16 @@ public class KeySpecParserSplitTests extends InstrumentationTestCase { } public void testLabelReferece() { - assertTextArray("Label time am", "!text/label_time_am", "AM"); + assertTextArray("Label time am", "!text/keylabel_time_am", "AM"); - assertTextArray("More keys for am pm", "!text/more_keys_for_am_pm", + assertTextArray("More keys for am pm", "!text/morekeys_am_pm", "!fixedColumnOrder!2", "!hasLabels!", "AM", "PM"); - assertTextArray("Settings as more key", "!text/settings_as_more_key", + assertTextArray("Settings as more key", "!text/keyspec_settings", "!icon/settings_key|!code/key_settings"); assertTextArray("Indirect naviagte actions as more key", - "!text/indirect_navigate_actions_as_more_key", + "!text/keyspec_indirect_navigate_actions", "!fixedColumnOrder!2", "!hasLabels!", "Prev|!code/key_action_previous", "!hasLabels!", "Next|!code/key_action_next"); diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java new file mode 100644 index 000000000..6c0d74941 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecTests.java @@ -0,0 +1,374 @@ +/* + * 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 static com.android.inputmethod.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED; +import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.Constants; + +import java.util.Arrays; +import java.util.Locale; + +@SmallTest +public final class MoreKeySpecTests extends KeySpecParserTestsBase { + @Override + protected void assertParser(final String message, final String moreKeySpec, + final String expectedLabel, final String expectedOutputText, final int expectedIconId, + final int expectedCode) { + final String labelResolved = mTextsSet.resolveTextReference(moreKeySpec); + final MoreKeySpec spec = new MoreKeySpec( + labelResolved, false /* needsToUpperCase */, Locale.US); + assertEquals(message + " [label]", expectedLabel, spec.mLabel); + assertEquals(message + " [ouptputText]", expectedOutputText, spec.mOutputText); + assertEquals(message + " [icon]", + KeyboardIconsSet.getIconName(expectedIconId), + KeyboardIconsSet.getIconName(spec.mIconId)); + assertEquals(message + " [code]", + Constants.printableCode(expectedCode), + Constants.printableCode(spec.mCode)); + } + + // TODO: Move this method to {@link KeySpecParserBase}. + public void testEmptySpec() { + assertParserError("Null spec", null, + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + assertParserError("Empty spec", "", + null, null, ICON_UNDEFINED, CODE_UNSPECIFIED); + } + + private static void assertArrayEquals(final String message, final Object[] expected, + final Object[] actual) { + if (expected == actual) { + return; + } + if (expected == null || actual == null) { + assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); + return; + } + if (expected.length != actual.length) { + assertEquals(message + " [length]", Arrays.toString(expected), Arrays.toString(actual)); + return; + } + for (int i = 0; i < expected.length; i++) { + assertEquals(message + " [" + i + "]", + Arrays.toString(expected), Arrays.toString(actual)); + } + } + + private static void assertInsertAdditionalMoreKeys(final String message, + final String[] moreKeys, final String[] additionalMoreKeys, final String[] expected) { + final String[] actual = MoreKeySpec.insertAdditionalMoreKeys(moreKeys, additionalMoreKeys); + assertArrayEquals(message, expected, actual); + } + + public void testEmptyEntry() { + assertInsertAdditionalMoreKeys("null more keys and null additons", + null, + null, + null); + assertInsertAdditionalMoreKeys("null more keys and empty additons", + null, + new String[0], + null); + assertInsertAdditionalMoreKeys("empty more keys and null additons", + new String[0], + null, + null); + assertInsertAdditionalMoreKeys("empty more keys and empty additons", + new String[0], + new String[0], + null); + + assertInsertAdditionalMoreKeys("filter out empty more keys", + new String[] { null, "a", "", "b", null }, + null, + new String[] { "a", "b" }); + assertInsertAdditionalMoreKeys("filter out empty additons", + new String[] { "a", "%", "b", "%", "c", "%", "d" }, + new String[] { null, "A", "", "B", null }, + new String[] { "a", "A", "b", "B", "c", "d" }); + } + + public void testInsertAdditionalMoreKeys() { + // Escaped marker. + assertInsertAdditionalMoreKeys("escaped marker", + new String[] { "\\%", "%-)" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "\\%", "%-)" }); + + // 0 more key. + assertInsertAdditionalMoreKeys("null & null", null, null, null); + assertInsertAdditionalMoreKeys("null & 1 additon", + null, + new String[] { "1" }, + new String[] { "1" }); + assertInsertAdditionalMoreKeys("null & 2 additons", + null, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + + // 0 additional more key. + assertInsertAdditionalMoreKeys("1 more key & null", + new String[] { "A" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("2 more keys & null", + new String[] { "A", "B" }, + null, + new String[] { "A", "B" }); + + // No marker. + assertInsertAdditionalMoreKeys("1 more key & 1 addtional & no marker", + new String[] { "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtionals & no marker", + new String[] { "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 addtional & no marker", + new String[] { "A", "B" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtionals & no marker", + new String[] { "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A", "B" }); + + // 1 marker. + assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at head", + new String[] { "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & marker at tail", + new String[] { "A", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + + // 1 marker & excess additional more keys. + assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at head", + new String[] { "%", "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & marker at tail", + new String[] { "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "B", "1", "2" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "B", "2" }); + + // 2 markers. + assertInsertAdditionalMoreKeys("0 more key & 2 addtional & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 2 addtional & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertInsertAdditionalMoreKeys("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 more keys. + assertInsertAdditionalMoreKeys("0 more key & 2 additons & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "3" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "A", "3" }); + assertInsertAdditionalMoreKeys("1 more key & 2 additons & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "B", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "B", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "B", "2", "3" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & 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. + assertInsertAdditionalMoreKeys("0 more key & null & excess marker", + new String[] { "%" }, + null, + null); + assertInsertAdditionalMoreKeys("1 more key & null & excess marker at head", + new String[] { "%", "A" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("1 more key & null & excess marker at tail", + new String[] { "A", "%" }, + null, + new String[] { "A" }); + assertInsertAdditionalMoreKeys("2 more keys & null & excess marker at middle", + new String[] { "A", "%", "B" }, + null, + new String[] { "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & null & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + null, + new String[] { "A", "B" }); + + // Excess markers. + assertInsertAdditionalMoreKeys("0 more key & 1 additon & excess marker", + new String[] { "%", "%" }, + new String[] { "1" }, + new String[] { "1" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at head", + new String[] { "%", "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertInsertAdditionalMoreKeys("1 more key & 1 additon & excess marker at tail", + new String[] { "A", "%", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess marker at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 1 additon & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 2 additons & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertInsertAdditionalMoreKeys("2 more keys & 3 additons & excess markers", + new String[] { "%", "A", "%", "%", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "3", "B" }); + } + + private static final String HAS_LABEL = "!hasLabel!"; + private static final String NEEDS_DIVIDER = "!needsDividers!"; + private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!"; + private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!"; + + private static void assertGetBooleanValue(final String message, final String key, + final String[] moreKeys, final String[] expected, final boolean expectedValue) { + final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); + final boolean actualValue = MoreKeySpec.getBooleanValue(actual, key); + assertEquals(message + " [value]", expectedValue, actualValue); + assertArrayEquals(message, expected, actual); + } + + public void testGetBooleanValue() { + assertGetBooleanValue("Has label", HAS_LABEL, + new String[] { HAS_LABEL, "a", "b", "c" }, + new String[] { null, "a", "b", "c" }, true); + // Upper case specification will not work. + assertGetBooleanValue("HAS LABEL", HAS_LABEL, + new String[] { HAS_LABEL.toUpperCase(Locale.ROOT), "a", "b", "c" }, + new String[] { "!HASLABEL!", "a", "b", "c" }, false); + + assertGetBooleanValue("No has label", HAS_LABEL, + new String[] { "a", "b", "c" }, + new String[] { "a", "b", "c" }, false); + assertGetBooleanValue("No has label with fixed clumn order", HAS_LABEL, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, false); + + // Upper case specification will not work. + assertGetBooleanValue("Multiple has label", HAS_LABEL, + new String[] { + "a", HAS_LABEL.toUpperCase(Locale.ROOT), "b", "c", HAS_LABEL, "d" }, + new String[] { + "a", "!HASLABEL!", "b", "c", null, "d" }, true); + // Upper case specification will not work. + assertGetBooleanValue("Multiple has label with needs dividers", HAS_LABEL, + new String[] { + "a", HAS_LABEL, "b", NEEDS_DIVIDER, HAS_LABEL.toUpperCase(Locale.ROOT), "d" }, + new String[] { + "a", null, "b", NEEDS_DIVIDER, "!HASLABEL!", "d" }, true); + } + + private static void assertGetIntValue(final String message, final String key, + final int defaultValue, final String[] moreKeys, final String[] expected, + final int expectedValue) { + final String[] actual = Arrays.copyOf(moreKeys, moreKeys.length); + final int actualValue = MoreKeySpec.getIntValue(actual, key, defaultValue); + assertEquals(message + " [value]", expectedValue, actualValue); + assertArrayEquals(message, expected, actual); + } + + public void testGetIntValue() { + assertGetIntValue("Fixed column order 3", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER + "3", "a", "b", "c" }, + new String[] { null, "a", "b", "c" }, 3); + // Upper case specification will not work. + assertGetIntValue("FIXED COLUMN ORDER 3", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "3", "a", "b", "c" }, + new String[] { "!FIXEDCOLUMNORDER!3", "a", "b", "c" }, -1); + + assertGetIntValue("No fixed column order", FIXED_COLUMN_ORDER, -1, + new String[] { "a", "b", "c" }, + new String[] { "a", "b", "c" }, -1); + assertGetIntValue("No fixed column order with auto column order", FIXED_COLUMN_ORDER, -1, + new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, + new String[] { AUTO_COLUMN_ORDER + "5", "a", "b", "c" }, -1); + + assertGetIntValue("Multiple fixed column order 3,5", FIXED_COLUMN_ORDER, -1, + new String[] { FIXED_COLUMN_ORDER + "3", "a", FIXED_COLUMN_ORDER + "5", "b" }, + new String[] { null, "a", null, "b" }, 3); + // Upper case specification will not work. + assertGetIntValue("Multiple fixed column order 5,3 with has label", FIXED_COLUMN_ORDER, -1, + new String[] { + FIXED_COLUMN_ORDER.toUpperCase(Locale.ROOT) + "5", HAS_LABEL, "a", + FIXED_COLUMN_ORDER + "3", "b" }, + new String[] { "!FIXEDCOLUMNORDER!5", HAS_LABEL, "a", null, "b" }, 3); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java index 279559cfe..7908b260e 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java @@ -27,7 +27,7 @@ public class PointerTrackerQueueTests extends AndroidTestCase { public final int mId; public boolean mIsModifier; - public boolean mIsInSlidingKeyInput; + public boolean mIsInDraggingFinger; public long mPhantomUpEventTime = NOT_HAPPENED; public Element(int id) { @@ -40,8 +40,8 @@ public class PointerTrackerQueueTests extends AndroidTestCase { } @Override - public boolean isInSlidingKeyInput() { - return mIsInSlidingKeyInput; + public boolean isInDraggingFinger() { + return mIsInDraggingFinger; } @Override @@ -297,19 +297,19 @@ public class PointerTrackerQueueTests extends AndroidTestCase { assertEquals(Element.NOT_HAPPENED, mElement4.mPhantomUpEventTime); } - public void testIsAnyInSlidingKeyInput() { + public void testIsAnyInDraggingFinger() { Element.sPhantomUpCount = 0; - assertFalse(mQueue.isAnyInSlidingKeyInput()); + assertFalse(mQueue.isAnyInDraggingFinger()); mQueue.add(mElement1); mQueue.add(mElement2); mQueue.add(mElement3); mQueue.add(mElement4); - assertFalse(mQueue.isAnyInSlidingKeyInput()); + assertFalse(mQueue.isAnyInDraggingFinger()); - mElement3.mIsInSlidingKeyInput = true; - assertTrue(mQueue.isAnyInSlidingKeyInput()); + mElement3.mIsInDraggingFinger = true; + assertTrue(mQueue.isAnyInDraggingFinger()); assertEquals(0, Element.sPhantomUpCount); assertEquals(4, mQueue.size()); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java new file mode 100644 index 000000000..b0493d3f1 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.Symbols.RtlSymbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted.RtlSymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +public final class Arabic extends LayoutBase { + private static final String LAYOUT_NAME = "arabic"; + + public Arabic(final LayoutCustomizer customizer) { + super(customizer, ArabicSymbols.class, ArabicSymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class ArabicCustomizer extends LayoutCustomizer { + public ArabicCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey getAlphabetKey() { return ARABIC_ALPHABET_KEY; } + + @Override + public ExpectedKey getSymbolsKey() { return ARABIC_SYMBOLS_KEY; } + + @Override + public ExpectedKey getBackToSymbolsKey() { return ARABIC_BACK_TO_SYMBOLS_KEY; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { + return RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL; + } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { + return RtlSymbols.SINGLE_ANGLE_QUOTES_LR_RTL; + } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { + if (isPhone) { + // U+060C: "،" ARABIC COMMA + return joinKeys(key("\u060C", SETTINGS_KEY)); + } + return super.getKeysLeftToSpacebar(isPhone); + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + if (isPhone) { + return super.getKeysRightToSpacebar(isPhone); + } + // U+060C: "،" ARABIC COMMA + // U+061F: "؟" ARABIC QUESTION MARK + // U+061B: "؛" ARABIC SEMICOLON + return joinKeys( + key("\u060C", joinMoreKeys(":", "!", "\u061F", "\u061B", "-", "/", "\"", "'")), + key(".", getPunctuationMoreKeys(isPhone))); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return ARABIC_DIACRITICS; + } + + // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE + // U+200C: ZERO WIDTH NON-JOINER + // U+0628: "ب" ARABIC LETTER BEH + // U+062C: "ج" ARABIC LETTER JEEM + private static final ExpectedKey ARABIC_ALPHABET_KEY = key( + "\u0623\u200C\u0628\u200C\u062C", Constants.CODE_SWITCH_ALPHA_SYMBOL); + // U+0663: "٣" ARABIC-INDIC DIGIT THREE + // U+0662: "٢" ARABIC-INDIC DIGIT TWO + // U+0661: "١" ARABIC-INDIC DIGIT ONE + // U+061F: "؟" ARABIC QUESTION MARK + private static final ExpectedKey ARABIC_SYMBOLS_KEY = key( + "\u0663\u0662\u0661\u061F", Constants.CODE_SWITCH_ALPHA_SYMBOL); + private static final ExpectedKey ARABIC_BACK_TO_SYMBOLS_KEY = key( + "\u0663\u0662\u0661\u061F", Constants.CODE_SHIFT); + + private static final ExpectedKey[] ARABIC_DIACRITICS = { + // U+0655: "ٕ" ARABIC HAMZA BELOW + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+0652: "ْ" ARABIC SUKUN + // U+064D: "ٍ" ARABIC KASRATAN + // U+064C: "ٌ" ARABIC DAMMATAN + // U+064B: "ً" ARABIC FATHATAN + // U+0651: "ّ" ARABIC SHADDA + // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+0653: "ٓ" ARABIC MADDAH ABOVE + // U+0650: "ِ" ARABIC KASRA + // U+064F: "ُ" ARABIC DAMMA + // U+064E: "َ" ARABIC FATHA + // U+0640: "ـ" ARABIC TATWEEL + moreKey(" \u0655", "\u0655"), moreKey(" \u0654", "\u0654"), + moreKey(" \u0652", "\u0652"), moreKey(" \u064D", "\u064D"), + moreKey(" \u064C", "\u064C"), moreKey(" \u064B", "\u064B"), + moreKey(" \u0651", "\u0651"), moreKey(" \u0656", "\u0656"), + moreKey(" \u0670", "\u0670"), moreKey(" \u0653", "\u0653"), + moreKey(" \u0650", "\u0650"), moreKey(" \u064F", "\u064F"), + moreKey(" \u064E", "\u064E"), moreKey("\u0640\u0640\u0640", "\u0640") + }; + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + if (isPhone) { + return ALPHABET_COMMON; + } else { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE + builder.insertKeysAtRow(3, 2, "\u0626"); + return builder.build(); + } + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + return null; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0636: "ض" ARABIC LETTER DAD + // U+0661: "١" ARABIC-INDIC DIGIT ONE + key("\u0636", joinMoreKeys("1", "\u0661")), + // U+0635: "ص" ARABIC LETTER SAD + // U+0662: "٢" ARABIC-INDIC DIGIT TWO + key("\u0635", joinMoreKeys("2", "\u0662")), + // U+062B: "ث" ARABIC LETTER THEH + // U+0663: "٣" ARABIC-INDIC DIGIT THREE + key("\u062B", joinMoreKeys("3", "\u0663")), + // U+0642: "ق" ARABIC LETTER QAF + // U+0664: "٤" ARABIC-INDIC DIGIT FOUR + // U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE + key("\u0642", joinMoreKeys("4", "\u0664", "\u06A8")), + // U+0641: "ف" ARABIC LETTER FEH + // U+0665: "٥" ARABIC-INDIC DIGIT FIVE + // U+06A4: "ڤ" ARABIC LETTER VEH + // U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW + // U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW + key("\u0641", joinMoreKeys("5", "\u0665", "\u06A4", "\u06A2", "\u06A5")), + // U+063A: "غ" ARABIC LETTER GHAIN + // U+0666: "٦" ARABIC-INDIC DIGIT SIX + key("\u063A", joinMoreKeys("6", "\u0666")), + // U+0639: "ع" ARABIC LETTER AIN + // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN + key("\u0639", joinMoreKeys("7", "\u0667")), + // U+0647: "ه" ARABIC LETTER HEH + // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT + // U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM + // U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER + key("\u0647", joinMoreKeys("8", "\u0668", moreKey("\uFEEB", "\u0647\u200D"))), + // U+062E: "خ" ARABIC LETTER KHAH + // U+0669: "٩" ARABIC-INDIC DIGIT NINE + key("\u062E", joinMoreKeys("9", "\u0669")), + // U+062D: "ح" ARABIC LETTER HAH + // U+0660: "٠" ARABIC-INDIC DIGIT ZERO + key("\u062D", joinMoreKeys("0", "\u0660")), + // U+062C: "ج" ARABIC LETTER JEEM + // U+0686: "چ" ARABIC LETTER TCHEH + key("\u062C", moreKey("\u0686"))) + .setKeysOfRow(2, + // U+0634: "ش" ARABIC LETTER SHEEN + // U+069C: "ڜ" ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE + key("\u0634", moreKey("\u069C")), + // U+0633: "س" ARABIC LETTER SEEN + "\u0633", + // U+064A: "ي" ARABIC LETTER YEH + // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE + // U+0649: "ى" ARABIC LETTER ALEF MAKSURA + key("\u064A", joinMoreKeys("\u0626", "\u0649")), + // U+0628: "ب" ARABIC LETTER BEH + // U+067E: "پ" ARABIC LETTER PEH + key("\u0628", moreKey("\u067E")), + // U+0644: "ل" ARABIC LETTER LAM + // U+FEFB: "ﻻ" ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM + // U+0627: "ا" ARABIC LETTER ALEF + // U+FEF7: "ﻷ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM + // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE + // U+FEF9: "ﻹ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM + // U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW + // U+FEF5: "ﻵ" ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM + // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE + key("\u0644", + moreKey("\uFEFB", "\u0644\u0627"), moreKey("\uFEF7", "\u0644\u0623"), + moreKey("\uFEF9", "\u0644\u0625"), moreKey("\uFEF5", "\u0644\u0622")), + // U+0627: "ا" ARABIC LETTER ALEF + // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE + // U+0621: "ء" ARABIC LETTER HAMZA + // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE + // U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW + // U+0671: "ٱ" ARABIC LETTER ALEF WASLA + key("\u0627", joinMoreKeys("\u0622", "\u0621", "\u0623", "\u0625", "\u0671")), + // U+062A: "ت" ARABIC LETTER TEH + // U+0646: "ن" ARABIC LETTER NOON + // U+0645: "م" ARABIC LETTER MEEM + "\u062A", "\u0646", "\u0645", + // U+0643: "ك" ARABIC LETTER KAF + // U+06AF: "گ" ARABIC LETTER GAF + // U+06A9: "ک" ARABIC LETTER KEHEH + key("\u0643", joinMoreKeys("\u06AF", "\u06A9")), + // U+0637: "ط" ARABIC LETTER TAH + "\u0637") + .setKeysOfRow(3, + // U+0630: "ذ" ARABIC LETTER THAL + // U+0621: "ء" ARABIC LETTER HAMZA + // U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE + // U+0631: "ر" ARABIC LETTER REH + "\u0630", "\u0621", "\u0624", "\u0631", + // U+0649: "ى" ARABIC LETTER ALEF MAKSURA + // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE + key("\u0649", moreKey("\u0626")), + // U+0629: "ة" ARABIC LETTER TEH MARBUTA + // U+0648: "و" ARABIC LETTER WAW + "\u0629", "\u0648", + // U+0632: "ز" ARABIC LETTER ZAIN + // U+0698: "ژ" ARABIC LETTER JEH + key("\u0632", moreKey("\u0698")), + // U+0638: "ظ" ARABIC LETTER ZAH + // U+062F: "د" ARABIC LETTER DAL + "\u0638", "\u062F") + .build(); + + private static class ArabicSymbols extends RtlSymbols { + public ArabicSymbols(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+0661: "١" ARABIC-INDIC DIGIT ONE + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + .replaceKeyOfLabel("1", key("\u0661", + joinMoreKeys("1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B"))) + // U+0662: "٢" ARABIC-INDIC DIGIT TWO + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + .replaceKeyOfLabel("2", key("\u0662", joinMoreKeys("2", "\u00B2", "\u2154"))) + // U+0663: "٣" ARABIC-INDIC DIGIT THREE + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + .replaceKeyOfLabel("3", key("\u0663", + joinMoreKeys("3", "\u00B3", "\u00BE", "\u215C"))) + // U+0664: "٤" ARABIC-INDIC DIGIT FOUR + // U+2074: "⁴" SUPERSCRIPT FOUR + .replaceKeyOfLabel("4", key("\u0664", joinMoreKeys("4", "\u2074"))) + // U+0665: "٥" ARABIC-INDIC DIGIT FIVE + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + .replaceKeyOfLabel("5", key("\u0665", joinMoreKeys("5", "\u215D"))) + // U+0666: "٦" ARABIC-INDIC DIGIT SIX + .replaceKeyOfLabel("6", key("\u0666", moreKey("6"))) + // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + .replaceKeyOfLabel("7", key("\u0667", joinMoreKeys("7", "\u215E"))) + // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT + .replaceKeyOfLabel("8", key("\u0668", moreKey("8"))) + // U+0669: "٩" ARABIC-INDIC DIGIT NINE + .replaceKeyOfLabel("9", key("\u0669", moreKey("9"))) + // U+0660: "٠" ARABIC-INDIC DIGIT ZERO + // U+066B: "٫" ARABIC DECIMAL SEPARATOR + // U+066C: "٬" ARABIC THOUSANDS SEPARATOR + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + .replaceKeyOfLabel("0", key("\u0660", + joinMoreKeys("0", "\u066B", "\u066C", "\u207F", "\u2205"))) + // U+066A: "٪" ARABIC PERCENT SIGN + // U+2030: "‰" PER MILLE SIGN + .replaceKeyOfLabel("%", key("\u066A", joinMoreKeys("%", "\u2030"))) + // U+061B: "؛" ARABIC SEMICOLON + .replaceKeyOfLabel(";", key("\u061B", moreKey(";"))) + // U+061F: "؟" ARABIC QUESTION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + .replaceKeyOfLabel("?", key("\u061F", joinMoreKeys("?", "\u00BF"))) + // U+060C: "،" ARABIC COMMA + .replaceKeyOfLabel(",", "\u060C") + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + .replaceKeyOfLabel("(", key("(", ")", + moreKey("\uFD3E", "\uFD3F"), moreKey("<", ">"), moreKey("{", "}"), + moreKey("[", "]"))) + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + .replaceKeyOfLabel(")", key(")", "(", + moreKey("\uFD3F", "\uFD3E"), moreKey(">", "<"), moreKey("}", "{"), + moreKey("]", "["))) + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + .setMoreKeysOf("*", "\u2605", "\u066D") + .build(); + } + } + + private static class ArabicSymbolsShifted extends RtlSymbolsShifted { + public ArabicSymbolsShifted(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+2022: "•" BULLET + // U+266A: "♪" EIGHTH NOTE + .setMoreKeysOf("\u2022", "\u266A") + // U+060C: "،" ARABIC COMMA + .replaceKeyOfLabel(",", "\u060C") + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java new file mode 100644 index 000000000..204bb01f7 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Armenian Phonetic alphabet keyboard. + */ +public final class ArmenianPhonetic extends LayoutBase { + private static final String LAYOUT_NAME = "armenian_phonetic"; + + public ArmenianPhonetic(final LayoutCustomizer customizer) { + super(customizer, ArmenianSymbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class ArmenianPhoneticCustomizer extends LayoutCustomizer { + public ArmenianPhoneticCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return ARMENIAN_ALPHABET_KEY; } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + if (isPhone) { + return EMPTY_KEYS; + } + // U+055C: "՜" ARMENIAN EXCLAMATION MARK + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+055E: "՞" ARMENIAN QUESTION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + return joinKeys(key("!", joinMoreKeys("\u055C", "\u00A1")), + key("?", joinMoreKeys("\u055E", "\u00BF")), + SHIFT_KEY); + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + // U+0589: "։" ARMENIAN FULL STOP + // U+055D: "՝" ARMENIAN COMMA + final ExpectedKey fullStopKey = key("\u0589", getPunctuationMoreKeys(isPhone)); + return isPhone ? joinKeys(fullStopKey) : joinKeys("\u055D", fullStopKey); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return ARMENIAN_PUNCTUATION_MORE_KEYS; + } + + // U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB + // U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN + // U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM + private static final ExpectedKey ARMENIAN_ALPHABET_KEY = key( + "\u0531\u0532\u0533", Constants.CODE_SWITCH_ALPHA_SYMBOL); + + // U+055E: "՞" ARMENIAN QUESTION MARK + // U+055C: "՜" ARMENIAN EXCLAMATION MARK + // U+055A: "՚" ARMENIAN APOSTROPHE + // U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING + // U+055D: "՝" ARMENIAN COMMA + // U+055B: "՛" ARMENIAN EMPHASIS MARK + // U+058A: "֊" ARMENIAN HYPHEN + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+055F: "՟" ARMENIAN ABBREVIATION MARK + private static final ExpectedKey[] ARMENIAN_PUNCTUATION_MORE_KEYS = joinMoreKeys( + ",", "\u055E", "\u055C", ".", "\u055A", "\u0559", "?", "!", + "\u055D", "\u055B", "\u058A", "\u00BB", "\u00AB", "\u055F", ";", ":"); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + if (isPhone) { + // U+056D: "խ" ARMENIAN SMALL LETTER XEH + // U+0577: "շ" ARMENIAN SMALL LETTER SHA + builder.addKeysOnTheRightOfRow(3, "\u056D") + .addKeysOnTheRightOfRow(4, "\u0577"); + } else { + // U+056D: "խ" ARMENIAN SMALL LETTER XEH + // U+0577: "շ" ARMENIAN SMALL LETTER SHA + builder.addKeysOnTheRightOfRow(2, "\u056D") + .addKeysOnTheRightOfRow(3, "\u0577"); + } + return builder.build(); + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(4, DELETE_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(5, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0567: "է" ARMENIAN SMALL LETTER EH + key("\u0567", moreKey("1")), + // U+0569: "թ" ARMENIAN SMALL LETTER TO + key("\u0569", moreKey("2")), + // U+0583: "փ" ARMENIAN SMALL LETTER PIWR + key("\u0583", moreKey("3")), + // U+0571: "ձ" ARMENIAN SMALL LETTER JA + key("\u0571", moreKey("4")), + // U+057B: "ջ" ARMENIAN SMALL LETTER JHEH + key("\u057B", moreKey("5")), + // U+0580: "ր" ARMENIAN SMALL LETTER REH + key("\u0580", moreKey("6")), + // U+0579: "չ" ARMENIAN SMALL LETTER CHA + key("\u0579", moreKey("7")), + // U+0573: "ճ" ARMENIAN SMALL LETTER CHEH + key("\u0573", moreKey("8")), + // U+056A: "ժ" ARMENIAN SMALL LETTER ZHE + key("\u056A", moreKey("9")), + // U+056E: "ծ" ARMENIAN SMALL LETTER CA + key("\u056E", moreKey("0"))) + .setKeysOfRow(2, + // U+0584: "ք" ARMENIAN SMALL LETTER KEH + // U+0578: "ո" ARMENIAN SMALL LETTER VO + "\u0584", "\u0578", + // U+0565: "ե" ARMENIAN SMALL LETTER ECH + // U+0587: "և" ARMENIAN SMALL LIGATURE ECH YIWN + key("\u0565", moreKey("\u0587")), + // U+057C: "ռ" ARMENIAN SMALL LETTER RA + // U+057F: "տ" ARMENIAN SMALL LETTER TIWN + // U+0568: "ը" ARMENIAN SMALL LETTER ET + // U+0582: "ւ" ARMENIAN SMALL LETTER YIWN + // U+056B: "ի" ARMENIAN SMALL LETTER INI + // U+0585: "օ" ARMENIAN SMALL LETTER OH + // U+057A: "պ" ARMENIAN SMALL LETTER PEH + "\u057C", "\u057F", "\u0568", "\u0582", "\u056B", "\u0585", "\u057A") + .setKeysOfRow(3, + // U+0561: "ա" ARMENIAN SMALL LETTER AYB + // U+057D: "ս" ARMENIAN SMALL LETTER SEH + // U+0564: "դ" ARMENIAN SMALL LETTER DA + // U+0586: "ֆ" ARMENIAN SMALL LETTER FEH + // U+0563: "գ" ARMENIAN SMALL LETTER GIM + // U+0570: "հ" ARMENIAN SMALL LETTER HO + // U+0575: "յ" ARMENIAN SMALL LETTER YI + // U+056F: "կ" ARMENIAN SMALL LETTER KEN + // U+056C: "լ" ARMENIAN SMALL LETTER LIWN + "\u0561", "\u057D", "\u0564", "\u0586", "\u0563", "\u0570", "\u0575", "\u056F", + "\u056C") + .setKeysOfRow(4, + // U+0566: "զ" ARMENIAN SMALL LETTER ZA + // U+0572: "ղ" ARMENIAN SMALL LETTER GHAD + // U+0581: "ց" ARMENIAN SMALL LETTER CO + // U+057E: "վ" ARMENIAN SMALL LETTER VEW + // U+0562: "բ" ARMENIAN SMALL LETTER BEN + // U+0576: "ն" ARMENIAN SMALL LETTER NOW + // U+0574: "մ" ARMENIAN SMALL LETTER MEN + "\u0566", "\u0572", "\u0581", "\u057E", "\u0562", "\u0576", "\u0574") + .build(); + + private static final class ArmenianSymbols extends Symbols { + public ArmenianSymbols(final LayoutCustomizer customizer) { super(customizer); } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( + super.getLayout(isPhone)); + // U+055C: "՜" ARMENIAN EXCLAMATION MARK + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+055E: "՞" ARMENIAN QUESTION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + builder.setMoreKeysOf("!", "\u055C", "\u00A1") + .setMoreKeysOf("?", "\u055E", "\u00BF"); + return builder.build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Azerty.java b/tests/src/com/android/inputmethod/keyboard/layout/Azerty.java new file mode 100644 index 000000000..a0949637b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Azerty.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +/** + * The AZERTY alphabet keyboard. + */ +public final class Azerty extends LayoutBase { + public Azerty(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return "azerty"; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + customizer.setAccentedLetters(builder); + builder.replaceKeyOfLabel(ROW3_QUOTE, key("'", joinMoreKeys( + customizer.getSingleQuoteMoreKeys(), + customizer.getSingleAngleQuoteKeys()))); + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + final ExpectedKeyboardBuilder builder; + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED + || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) { + builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone)); + } else { + builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + getCustomizer().setAccentedLetters(builder); + builder.replaceKeyOfLabel(ROW3_QUOTE, "?"); + } + builder.toUpperCase(getLocale()); + return builder.build(); + } + + private static final String ROW3_QUOTE = "ROW3_QUOUTE"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("a", additionalMoreKey("1")), + key("z", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("y", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0"))) + .setKeysOfRow(2, "q", "s", "d", "f", "g", "h", "j", "k", "l", "m") + .setKeysOfRow(3, "w", "x", "c", "v", "b", "n", ROW3_QUOTE) + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Bulgarian.java b/tests/src/com/android/inputmethod/keyboard/layout/Bulgarian.java new file mode 100644 index 000000000..3282e44ae --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Bulgarian.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +public final class Bulgarian extends LayoutBase { + private static final String LAYOUT_NAME = "bulgarian"; + + public Bulgarian(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class BulgarianCustomizer extends LayoutCustomizer { + private final EastSlavicCustomizer mEastSlavicCustomizer; + + public BulgarianCustomizer(final Locale locale) { + super(locale); + mEastSlavicCustomizer = new EastSlavicCustomizer(locale); + } + + @Override + public ExpectedKey getAlphabetKey() { + return mEastSlavicCustomizer.getAlphabetKey(); + } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+044F: "я" CYRILLIC SMALL LETTER YA + key("\u044F", moreKey("1")), + // U+0432: "в" CYRILLIC SMALL LETTER VE + key("\u0432", moreKey("2")), + // U+0435: "е" CYRILLIC SMALL LETTER IE + key("\u0435", moreKey("3")), + // U+0440: "р" CYRILLIC SMALL LETTER ER + key("\u0440", moreKey("4")), + // U+0442: "т" CYRILLIC SMALL LETTER TE + key("\u0442", moreKey("5")), + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + key("\u044A", moreKey("6")), + // U+0443: "у" CYRILLIC SMALL LETTER U + key("\u0443", moreKey("7")), + // U+0438: "и" CYRILLIC SMALL LETTER I + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + key("\u0438", joinMoreKeys("8", "\u045D")), + // U+043E: "о" CYRILLIC SMALL LETTER O + key("\u043E", moreKey("9")), + // U+043F: "п" CYRILLIC SMALL LETTER PE + key("\u043F", moreKey("0")), + // U+0447: "ч" CYRILLIC SMALL LETTER CHE + "\u0447") + .setKeysOfRow(2, + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+0441: "с" CYRILLIC SMALL LETTER ES + // U+0434: "д" CYRILLIC SMALL LETTER DE + // U+0444: "ф" CYRILLIC SMALL LETTER EF + // U+0433: "г" CYRILLIC SMALL LETTER GHE + // U+0445: "х" CYRILLIC SMALL LETTER HA + // U+0439: "й" CYRILLIC SMALL LETTER SHORT I + // U+043A: "к" CYRILLIC SMALL LETTER KA + // U+043B: "л" CYRILLIC SMALL LETTER EL + // U+0448: "ш" CYRILLIC SMALL LETTER SHA + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + "\u0430", "\u0441", "\u0434", "\u0444", "\u0433", "\u0445", "\u0439", "\u043A", + "\u043B", "\u0448", "\u0449") + .setKeysOfRow(3, + // U+0437: "з" CYRILLIC SMALL LETTER ZE + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+0446: "ц" CYRILLIC SMALL LETTER TSE + // U+0436: "ж" CYRILLIC SMALL LETTER ZHE + // U+0431: "б" CYRILLIC SMALL LETTER BE + // U+043D: "н" CYRILLIC SMALL LETTER EN + // U+043C: "м" CYRILLIC SMALL LETTER EM + // U+044E: "ю" CYRILLIC SMALL LETTER YU + "\u0437", "\u044C", "\u0446", "\u0436", "\u0431", "\u043D", "\u043C", "\u044E") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/BulgarianBds.java b/tests/src/com/android/inputmethod/keyboard/layout/BulgarianBds.java new file mode 100644 index 000000000..20a5f7dac --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/BulgarianBds.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +public final class BulgarianBds extends LayoutBase { + private static final String LAYOUT_NAME = "bulgarian_bds"; + + public BulgarianBds(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class BulgarianBdsCustomizer extends EastSlavicCustomizer { + public BulgarianBdsCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0443: "у" CYRILLIC SMALL LETTER U + key("\u0443", moreKey("1")), + // U+0435: "е" CYRILLIC SMALL LETTER IE + key("\u0435", moreKey("2")), + // U+0438: "и" CYRILLIC SMALL LETTER I + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + key("\u0438", joinMoreKeys("3", "\u045D")), + // U+0448: "ш" CYRILLIC SMALL LETTER SHA + key("\u0448", moreKey("4")), + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + key("\u0449", moreKey("5")), + // U+043A: "к" CYRILLIC SMALL LETTER KA + key("\u043A", moreKey("6")), + // U+0441: "с" CYRILLIC SMALL LETTER ES + key("\u0441", moreKey("7")), + // U+0434: "д" CYRILLIC SMALL LETTER DE + key("\u0434", moreKey("8")), + // U+0437: "з" CYRILLIC SMALL LETTER ZE + key("\u0437", moreKey("9")), + // U+0446: "ц" CYRILLIC SMALL LETTER TSE + key("\u0446", moreKey("0")), + // U+0431: "б" CYRILLIC SMALL LETTER BE + "\u0431") + .setKeysOfRow(2, + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044F: "я" CYRILLIC SMALL LETTER YA + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+043E: "о" CYRILLIC SMALL LETTER O + // U+0436: "ж" CYRILLIC SMALL LETTER ZHE + // U+0433: "г" CYRILLIC SMALL LETTER GHE + // U+0442: "т" CYRILLIC SMALL LETTER TE + // U+043D: "н" CYRILLIC SMALL LETTER EN + // U+0432: "в" CYRILLIC SMALL LETTER VE + // U+043C: "м" CYRILLIC SMALL LETTER EM + // U+0447: "ч" CYRILLIC SMALL LETTER CHE + "\u044C", "\u044F", "\u0430", "\u043E", "\u0436", "\u0433", "\u0442", "\u043D", + "\u0432", "\u043C", "\u0447") + .setKeysOfRow(3, + // U+044E: "ю" CYRILLIC SMALL LETTER YU + // U+0439: "й" CYRILLIC SMALL LETTER SHORT I + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + // U+044D: "э" CYRILLIC SMALL LETTER E + // U+0444: "ф" CYRILLIC SMALL LETTER EF + // U+0445: "х" CYRILLIC SMALL LETTER HA + // U+043F: "п" CYRILLIC SMALL LETTER PE + // U+0440: "р" CYRILLIC SMALL LETTER ER + // U+043B: "л" CYRILLIC SMALL LETTER EL + "\u044E", "\u0439", "\u044A", "\u044D", "\u0444", "\u0445", "\u043F", "\u0440", + "\u043B") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Colemak.java b/tests/src/com/android/inputmethod/keyboard/layout/Colemak.java new file mode 100644 index 000000000..a4a9701cd --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Colemak.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +/** + * The Colemak alphabet keyboard. + */ +public final class Colemak extends LayoutBase { + private static final String LAYOUT_NAME = "colemak"; + + public Colemak(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + getCustomizer().setAccentedLetters(builder); + builder.replaceKeyOfLabel(ROW1_10, key(";", additionalMoreKey("0"), moreKey(":"))); + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + final ExpectedKeyboardBuilder builder; + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED + || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) { + builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone)); + } else { + builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + getCustomizer().setAccentedLetters(builder); + builder.replaceKeyOfLabel(ROW1_10, key(":", additionalMoreKey("0"))); + } + builder.toUpperCase(getLocale()); + return builder.build(); + } + + private static final String ROW1_10 = "ROW1_10"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("f", additionalMoreKey("3")), + key("p", additionalMoreKey("4")), + key("g", additionalMoreKey("5")), + key("j", additionalMoreKey("6")), + key("l", additionalMoreKey("7")), + key("u", additionalMoreKey("8")), + key("y", additionalMoreKey("9")), + ROW1_10) + .setKeysOfRow(2, "a", "r", "s", "t", "d", "h", "n", "e", "i", "o") + .setKeysOfRow(3, "z", "x", "c", "v", "b", "k", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/DevanagariLetterConstants.java b/tests/src/com/android/inputmethod/keyboard/layout/DevanagariLetterConstants.java new file mode 100644 index 000000000..bcf06f085 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/DevanagariLetterConstants.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 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.layout; + +import android.os.Build; + +/** + * This class offers label strings of Devanagari letters that need the dotted circle to draw + * its glyph. + */ +class DevanagariLetterConstants { + private static final boolean NEEDS_DOTTED_CIRCLE = + Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN; + // U+25CC: "◌" DOTTED CIRCLE + private static final String DOTTED_CIRCLE = NEEDS_DOTTED_CIRCLE ? "\u25CC" : ""; + + // U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + static final String SIGN_CANDRABINDU = DOTTED_CIRCLE + "\u0901"; + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + static final String SIGN_ANUSVARA = DOTTED_CIRCLE + "\u0902"; + // U+0903: "ः" DEVANAGARI SIGN VISARGA + static final String SIGN_VISARGA = DOTTED_CIRCLE + "\u0903"; + // U+093C: "़" DEVANAGARI SIGN NUKTA + static final String SIGN_NUKTA = DOTTED_CIRCLE + "\u093C"; + // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA + static final String SIGN_AVAGRAHA = DOTTED_CIRCLE + "\u093D"; + // U+093E: "ा" DEVANAGARI VOWEL SIGN AA + static final String VOWEL_SIGN_AA = DOTTED_CIRCLE + "\u093E"; + // U+093F: "ि" DEVANAGARI VOWEL SIGN I + static final String VOWEL_SIGN_I = DOTTED_CIRCLE + "\u093F"; + // U+0940: "ी" DEVANAGARI VOWEL SIGN II + static final String VOWEL_SIGN_II = DOTTED_CIRCLE + "\u0940"; + // U+0941: "ु" DEVANAGARI VOWEL SIGN U + static final String VOWEL_SIGN_U = DOTTED_CIRCLE + "\u0941"; + // U+0942: "ू" DEVANAGARI VOWEL SIGN UU + static final String VOWEL_SIGN_UU = DOTTED_CIRCLE + "\u0942"; + // U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R + static final String VOWEL_SIGN_VOCALIC_R = DOTTED_CIRCLE + "\u0943"; + // U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR + static final String VOWEL_SIGN_VOCALIC_RR = DOTTED_CIRCLE + "\u0944"; + // U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E + static final String VOWEL_SIGN_CANDRA_E = DOTTED_CIRCLE + "\u0945"; + // U+0947: "े" DEVANAGARI VOWEL SIGN E + static final String VOWEL_SIGN_E = DOTTED_CIRCLE + "\u0947"; + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + static final String VOWEL_SIGN_AI = DOTTED_CIRCLE + "\u0948"; + // U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O + static final String VOWEL_SIGN_CANDRA_O = DOTTED_CIRCLE + "\u0949"; + // U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O + static final String VOWEL_SIGN_SHORT_O = DOTTED_CIRCLE + "\u094A"; + // U+094B: "ो" DEVANAGARI VOWEL SIGN O + static final String VOWEL_SIGN_O = DOTTED_CIRCLE + "\u094B"; + // U+094C: "ौ" DEVANAGARI VOWEL SIGN AU + static final String VOWEL_SIGN_AU = DOTTED_CIRCLE + "\u094C"; + // U+094D: "्" DEVANAGARI SIGN VIRAMA + static final String SIGN_VIRAMA = DOTTED_CIRCLE + "\u094D"; + // U+0970: "॰" DEVANAGARI ABBREVIATION SIGN + static final String ABBREVIATION_SIGN = DOTTED_CIRCLE + "\u0970"; + // U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP + static final String LETTER_GLOTTAL_STOP = DOTTED_CIRCLE + "\u097D"; +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java new file mode 100644 index 000000000..99cf6e50e --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey; + +import java.util.Locale; + +/** + * The QWERTY alphabet keyboard. + */ +public final class Dvorak extends LayoutBase { + private static final String LAYOUT_NAME = "dvorak"; + + public Dvorak(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class DvorakCustomizer extends LayoutCustomizer { + public DvorakCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return isPhone ? joinKeys(SHIFT_KEY): joinKeys(SHIFT_KEY, key("q")); + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : joinKeys(key("z"), SHIFT_KEY); + } + + @Override + public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { + return isPhone ? joinKeys(key("q", SHORTCUT_KEY, SETTINGS_KEY)) : joinKeys(key("/")); + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + final ExpectedAdditionalMoreKey[] punctuationMoreKeys = + convertToAdditionalMoreKeys(getPunctuationMoreKeys(isPhone)); + return isPhone + ? joinKeys(key("z", punctuationMoreKeys)) + : joinKeys(key("?", moreKey("!")), key("-", moreKey("_"))); + } + + private static ExpectedAdditionalMoreKey[] convertToAdditionalMoreKeys( + final ExpectedKey ... moreKeys) { + final ExpectedAdditionalMoreKey[] additionalMoreKeys = + new ExpectedAdditionalMoreKey[moreKeys.length]; + for (int index = 0; index < moreKeys.length; index++) { + additionalMoreKeys[index] = ExpectedAdditionalMoreKey.newInstance(moreKeys[index]); + } + return additionalMoreKeys; + } + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_SYMBOLS + || elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { + return super.getLayout(isPhone, elementId); + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( + getCommonAlphabetLayout(isPhone)); + if (elementId == KeyboardId.ELEMENT_ALPHABET + || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + builder.addKeysOnTheLeftOfRow(1, + key("'", joinMoreKeys(additionalMoreKey("1"), "!", "\"")), + key(",", joinMoreKeys(additionalMoreKey("2"), "?", "<")), + key(".", joinMoreKeys(additionalMoreKey("3"), ">"))); + } else { + builder.addKeysOnTheLeftOfRow(1, + key("\"", additionalMoreKey("1")), + key("<", additionalMoreKey("2")), + key(">", additionalMoreKey("3"))); + } + convertCommonLayoutToKeyboard(builder, isPhone); + getCustomizer().setAccentedLetters(builder); + if (elementId != KeyboardId.ELEMENT_ALPHABET) { + builder.toUpperCase(getLocale()); + builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY); + } + return builder.build(); + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("p", additionalMoreKey("4")), + key("y", additionalMoreKey("5")), + key("f", additionalMoreKey("6")), + key("g", additionalMoreKey("7")), + key("c", additionalMoreKey("8")), + key("r", additionalMoreKey("9")), + key("l", additionalMoreKey("0"))) + .setKeysOfRow(2, "a", "o", "e", "u", "i", "d", "h", "t", "n", "s") + .setKeysOfRow(3, "j", "k", "x", "b", "m", "w", "v") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/EastSlavic.java b/tests/src/com/android/inputmethod/keyboard/layout/EastSlavic.java new file mode 100644 index 000000000..7fcc974c2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/EastSlavic.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +public final class EastSlavic extends LayoutBase { + private static final String LAYOUT_NAME = "east_slavic"; + + public EastSlavic(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class EastSlavicCustomizer extends LayoutCustomizer { + public EastSlavicCustomizer(final Locale locale) { + super(locale); + } + + @Override + public final ExpectedKey getAlphabetKey() { return EAST_SLAVIC_ALPHABET_KEY; } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS; + } + + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + private static final ExpectedKey EAST_SLAVIC_ALPHABET_KEY = key( + "\u0410\u0411\u0412", Constants.CODE_SWITCH_ALPHA_SYMBOL); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + public static final String ROW1_9 = "ROW1_9"; + public static final String ROW2_2 = "ROW2_2"; + public static final String ROW2_11 = "ROW2_11"; + public static final String ROW3_5 = "ROW3_5"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0443: "у" CYRILLIC SMALL LETTER U + key("\u0439", additionalMoreKey("1")), + // U+0446: "ц" CYRILLIC SMALL LETTER TSE + key("\u0446", additionalMoreKey("2")), + // U+0439: "й" CYRILLIC SMALL LETTER SHORT I + key("\u0443", additionalMoreKey("3")), + // U+043A: "к" CYRILLIC SMALL LETTER KA + key("\u043A", additionalMoreKey("4")), + // U+0435: "е" CYRILLIC SMALL LETTER IE + key("\u0435", additionalMoreKey("5")), + // U+043D: "н" CYRILLIC SMALL LETTER EN + key("\u043D", additionalMoreKey("6")), + // U+0433: "г" CYRILLIC SMALL LETTER GHE + key("\u0433", additionalMoreKey("7")), + // U+0448: "ш" CYRILLIC SMALL LETTER SHA + key("\u0448", additionalMoreKey("8")), + key(ROW1_9, additionalMoreKey("9")), + // U+0437: "з" CYRILLIC SMALL LETTER ZE + key("\u0437", additionalMoreKey("0")), + // U+0445: "х" CYRILLIC SMALL LETTER HA + "\u0445") + .setKeysOfRow(2, + // U+0444: "ф" CYRILLIC SMALL LETTER EF + // U+0432: "в" CYRILLIC SMALL LETTER VE + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+043F: "п" CYRILLIC SMALL LETTER PE + // U+0440: "р" CYRILLIC SMALL LETTER ER + // U+043E: "о" CYRILLIC SMALL LETTER O + // U+043B: "л" CYRILLIC SMALL LETTER EL + // U+0434: "д" CYRILLIC SMALL LETTER DE + // U+0436: "ж" CYRILLIC SMALL LETTER ZHE + "\u0444", ROW2_2, "\u0432", "\u0430", "\u043F", "\u0440", "\u043E", "\u043B", + "\u0434", "\u0436", ROW2_11) + .setKeysOfRow(3, + // U+044F: "я" CYRILLIC SMALL LETTER YA + // U+0447: "ч" CYRILLIC SMALL LETTER CHE + // U+0441: "с" CYRILLIC SMALL LETTER ES + // U+043C: "м" CYRILLIC SMALL LETTER EM + // U+0442: "т" CYRILLIC SMALL LETTER TE + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+0431: "б" CYRILLIC SMALL LETTER BE + // U+044E: "ю" CYRILLIC SMALL LETTER YU + "\u044F", "\u0447", "\u0441", "\u043C", ROW3_5, "\u0442", "\u044C", "\u0431", + "\u044E") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java new file mode 100644 index 000000000..a0070891a --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.Symbols.RtlSymbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted.RtlSymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +public final class Farsi extends LayoutBase { + private static final String LAYOUT_NAME = "farsi"; + + public Farsi(final LayoutCustomizer customizer) { + super(customizer, FarsiSymbols.class, FarsiSymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class FarsiCustomizer extends LayoutCustomizer { + public FarsiCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey getAlphabetKey() { return FARSI_ALPHABET_KEY; } + + @Override + public ExpectedKey getSymbolsKey() { return FARSI_SYMBOLS_KEY; } + + @Override + public ExpectedKey getBackToSymbolsKey() { return FARSI_BACK_TO_SYMBOLS_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_RIAL; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { + if (isPhone) { + // U+060C: "،" ARABIC COMMA + return joinKeys(key("\u060C", SETTINGS_KEY)); + } + return super.getKeysLeftToSpacebar(isPhone); + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + if (isPhone) { + return super.getKeysRightToSpacebar(isPhone); + } + // U+060C: "،" ARABIC COMMA + // U+061F: "؟" ARABIC QUESTION MARK + // U+061B: "؛" ARABIC SEMICOLON + return joinKeys( + key("\u060C", joinMoreKeys(":", "!", "\u061F", "\u061B", "-", "/", + RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL)), + key(".", getPunctuationMoreKeys(isPhone))); + } + + @Override + public ExpectedKey[] getSpaceKeys(final boolean isPhone) { + return joinKeys(SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY)); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return FARSI_DIACRITICS; + } + + // U+0627: "ا" ARABIC LETTER ALEF + // U+200C: ZERO WIDTH NON-JOINER + // U+0628: "ب" ARABIC LETTER BEH + // U+067E: "پ" ARABIC LETTER PEH + private static final ExpectedKey FARSI_ALPHABET_KEY = key( + "\u0627\u200C\u0628\u200C\u067E", Constants.CODE_SWITCH_ALPHA_SYMBOL); + // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE + // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO + // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE + // U+061F: "؟" ARABIC QUESTION MARK + private static final ExpectedKey FARSI_SYMBOLS_KEY = key( + "\u06F3\u06F2\u06F1\u061F", Constants.CODE_SWITCH_ALPHA_SYMBOL); + private static final ExpectedKey FARSI_BACK_TO_SYMBOLS_KEY = key( + "\u06F3\u06F2\u06F1\u061F", Constants.CODE_SHIFT); + // U+FDFC: "﷼" RIAL SIGN + private static final ExpectedKey CURRENCY_RIAL = key("\uFDFC", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + private static final ExpectedKey[] FARSI_DIACRITICS = { + // U+0655: "ٕ" ARABIC HAMZA BELOW + // U+0652: "ْ" ARABIC SUKUN + // U+0651: "ّ" ARABIC SHADDA + // U+064C: "ٌ" ARABIC DAMMATAN + // U+064D: "ٍ" ARABIC KASRATAN + // U+064B: "ً" ARABIC FATHATAN + // U+0654: "ٔ" ARABIC HAMZA ABOVE + // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF + // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF + // U+0653: "ٓ" ARABIC MADDAH ABOVE + // U+064F: "ُ" ARABIC DAMMA + // U+0650: "ِ" ARABIC KASRA + // U+064E: "َ" ARABIC FATHA + // U+0640: "ـ" ARABIC TATWEEL + moreKey(" \u0655", "\u0655"), moreKey(" \u0652", "\u0652"), + moreKey(" \u0651", "\u0651"), moreKey(" \u064C", "\u064C"), + moreKey(" \u064D", "\u064D"), moreKey(" \u064B", "\u064B"), + moreKey(" \u0654", "\u0654"), moreKey(" \u0656", "\u0656"), + moreKey(" \u0670", "\u0670"), moreKey(" \u0653", "\u0653"), + moreKey(" \u064F", "\u064F"), moreKey(" \u0650", "\u0650"), + moreKey(" \u064E", "\u064E"), moreKey("\u0640\u0640\u0640", "\u0640") + }; + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + if (isPhone) { + return ALPHABET_COMMON; + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE + builder.insertKeysAtRow(3, 10, "\u0622"); + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + return null; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0636: "ض" ARABIC LETTER DAD + // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE + key("\u0636", joinMoreKeys("\u06F1", "1")), + // U+0635: "ص" ARABIC LETTER SAD + // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO + key("\u0635", joinMoreKeys("\u06F2", "2")), + // U+062B: "ث" ARABIC LETTER THEH + // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE + key("\u062B", joinMoreKeys("\u06F3", "3")), + // U+0642: "ق" ARABIC LETTER QAF + // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR + key("\u0642", joinMoreKeys("\u06F4", "4")), + // U+0641: "ف" ARABIC LETTER FEH + // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE + key("\u0641", joinMoreKeys("\u06F5", "5")), + // U+063A: "غ" ARABIC LETTER GHAIN + // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX + key("\u063A", joinMoreKeys("\u06F6", "6")), + // U+0639: "ع" ARABIC LETTER AIN + // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN + key("\u0639", joinMoreKeys("\u06F7", "7")), + // U+0647: "ه" ARABIC LETTER HEH + // U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM + // U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER + // U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE + // U+0629: "ة" ARABIC LETTER TEH MARBUTA + // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT + key("\u0647", joinMoreKeys(moreKey("\uFEEB", "\u0647\u200D"), "\u0647\u0654", + "\u0629", "\u06F8", "8")), + // U+062E: "خ" ARABIC LETTER KHAH + // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE + key("\u062E", joinMoreKeys("\u06F9", "9")), + // U+062D: "ح" ARABIC LETTER HAH + // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO + key("\u062D", joinMoreKeys("\u06F0", "0")), + // U+062C: "ج" ARABIC LETTER JEEM + "\u062C") + .setKeysOfRow(2, + // U+0634: "ش" ARABIC LETTER SHEEN + // U+0633: "س" ARABIC LETTER SEEN + "\u0634", "\u0633", + // U+06CC: "ی" ARABIC LETTER FARSI YEH + // U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE + // U+064A: "ي" ARABIC LETTER YEH + // U+FBE8: "ﯨ" ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM + // U+0649: "ى" ARABIC LETTER ALEF MAKSURA + key("\u06CC", joinMoreKeys("\u0626", "\u064A", moreKey("\uFBE8", "\u0649"))), + // U+0628: "ب" ARABIC LETTER BEH + // U+0644: "ل" ARABIC LETTER LAM + "\u0628", "\u0644", + // U+0627: "ا" ARABIC LETTER ALEF + // U+0671: "ٱ" ARABIC LETTER ALEF WASLA + // U+0621: "ء" ARABIC LETTER HAMZA + // U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE + // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE + // U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW + key("\u0627", joinMoreKeys("\u0671", "\u0621", "\u0622", "\u0623", "\u0625")), + // U+062A: "ت" ARABIC LETTER TEH + // U+0629: "ة": ARABIC LETTER TEH MARBUTA + key("\u062A", moreKey("\u0629")), + // U+0646: "ن" ARABIC LETTER NOON + // U+0645: "م" ARABIC LETTER MEEM + "\u0646", "\u0645", + // U+06A9: "ک" ARABIC LETTER KEHEH + // U+0643: "ك" ARABIC LETTER KAF + key("\u06A9", moreKey("\u0643")), + // U+06AF: "گ" ARABIC LETTER GAF + "\u06AF") + .setKeysOfRow(3, + // U+0638: "ظ" ARABIC LETTER ZAH + // U+0637: "ط" ARABIC LETTER TAH + // U+0698: "ژ" ARABIC LETTER JEH + // U+0632: "ز" ARABIC LETTER ZAIN + // U+0631: "ر" ARABIC LETTER REH + // U+0630: "ذ" ARABIC LETTER THAL + // U+062F: "د" ARABIC LETTER DAL + // U+067E: "پ" ARABIC LETTER PEH + "\u0638", "\u0637", "\u0698", "\u0632", "\u0631", "\u0630", "\u062F", "\u067E", + // U+0648: "و" ARABIC LETTER WAW + // U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE + key("\u0648", moreKey("\u0624")), + // U+0686: "چ" ARABIC LETTER TCHEH + "\u0686") + .build(); + + private static class FarsiSymbols extends RtlSymbols { + public FarsiSymbols(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + .replaceKeyOfLabel("1", key("\u06F1", + joinMoreKeys("1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B"))) + // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + .replaceKeyOfLabel("2", key("\u06F2", joinMoreKeys("2", "\u00B2", "\u2154"))) + // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + .replaceKeyOfLabel("3", key("\u06F3", + joinMoreKeys("3", "\u00B3", "\u00BE", "\u215C"))) + // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR + // U+2074: "⁴" SUPERSCRIPT FOUR + .replaceKeyOfLabel("4", key("\u06F4", joinMoreKeys("4", "\u2074"))) + // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + .replaceKeyOfLabel("5", key("\u06F5", joinMoreKeys("5", "\u215D"))) + // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX + .replaceKeyOfLabel("6", key("\u06F6", moreKey("6"))) + // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + .replaceKeyOfLabel("7", key("\u06F7", joinMoreKeys("7", "\u215E"))) + // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT + .replaceKeyOfLabel("8", key("\u06F8", moreKey("8"))) + // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE + .replaceKeyOfLabel("9", key("\u06F9", moreKey("9"))) + // U+066C: "٬" ARABIC THOUSANDS SEPARATOR + .replaceKeyOfLabel("@", key("\u066C", moreKey("@"))) + // U+066B: "٫" ARABIC DECIMAL SEPARATOR + .replaceKeyOfLabel("#", key("\u066B", moreKey("#"))) + // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO + // U+066B: "٫" ARABIC DECIMAL SEPARATOR + // U+066C: "٬" ARABIC THOUSANDS SEPARATOR + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + .replaceKeyOfLabel("0", key("\u06F0", + joinMoreKeys("0", "\u066B", "\u066C", "\u207F", "\u2205"))) + // U+066A: "٪" ARABIC PERCENT SIGN + // U+2030: "‰" PER MILLE SIGN + .replaceKeyOfLabel("%", key("\u066A", joinMoreKeys("%", "\u2030"))) + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + .replaceKeyOfLabel("\"", key("\u00AB", "\u00BB", joinMoreKeys( + DOUBLE_QUOTES_9LR, DOUBLE_ANGLE_QUOTES_LR_RTL))) + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2265: "≥" GREATER-THAN EQUAL TO + .replaceKeyOfLabel("'", key("\u00BB", "\u00AB", joinMoreKeys( + SINGLE_QUOTES_9LR, SINGLE_ANGLE_QUOTES_LR_RTL))) + // U+061B: "؛" ARABIC SEMICOLON + .replaceKeyOfLabel(";", key("\u061B", moreKey(";"))) + // U+061F: "؟" ARABIC QUESTION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + .replaceKeyOfLabel("?", key("\u061F", joinMoreKeys("?", "\u00BF"))) + // U+060C: "،" ARABIC COMMA + .replaceKeyOfLabel(",", "\u060C") + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + .replaceKeyOfLabel("(", key("(", ")", + moreKey("\uFD3E", "\uFD3F"), moreKey("<", ">"), moreKey("{", "}"), + moreKey("[", "]"))) + // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS + // U+FD3E: "﴾" ORNATE LEFT PARENTHESIS + .replaceKeyOfLabel(")", key(")", "(", + moreKey("\uFD3F", "\uFD3E"), moreKey(">", "<"), moreKey("}", "{"), + moreKey("]", "["))) + // U+2605: "★" BLACK STAR + // U+066D: "٭" ARABIC FIVE POINTED STAR + .setMoreKeysOf("*", "\u2605", "\u066D") + .build(); + } + } + + private static class FarsiSymbolsShifted extends RtlSymbolsShifted { + public FarsiSymbolsShifted(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+2022: "•" BULLET + // U+266A: "♪" EIGHTH NOTE + .setMoreKeysOf("\u2022", "\u266A") + // U+060C: "،" ARABIC COMMA + .replaceKeyOfLabel(",", "\u060C") + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + .replaceKeyOfLabel("<", key("\u00AB", "\u00BB", + moreKey("\u2039", "\u203A"), moreKey("\u2264", "\u2265"), + moreKey("<", ">"))) + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2265: "≥" GREATER-THAN EQUAL TO + .replaceKeyOfLabel(">", key("\u00BB", "\u00AB", + moreKey("\u203A", "\u2039"), moreKey("\u2265", "\u2264"), + moreKey(">", "<"))) + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Georgian.java b/tests/src/com/android/inputmethod/keyboard/layout/Georgian.java new file mode 100644 index 000000000..6f20dfcd1 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Georgian.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Georgian alphabet keyboard. + */ +public final class Georgian extends LayoutBase { + private static final String LAYOUT_NAME = "georgian"; + + public Georgian(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class GeorgianCustomizer extends LayoutCustomizer { + public GeorgianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return GEORGIAN_ALPHABET_KEY; } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + // U+10D0: "ა" GEORGIAN LETTER AN + // U+10D1: "ბ" GEORGIAN LETTER BAN + // U+10D2: "გ" GEORGIAN LETTER GAN + private static final ExpectedKey GEORGIAN_ALPHABET_KEY = key( + "\u10D0\u10D1\u10D2", Constants.CODE_SWITCH_ALPHA_SYMBOL); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + return ALPHABET_COMMON; + } + + @Override + public ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, + final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+10E5: "ქ" GEORGIAN LETTER GHAN + key("\u10E5", moreKey("1")), + // U+10EC: "წ" GEORGIAN LETTER CIL + key("\u10EC", moreKey("2")), + // U+10D4: "ე" GEORGIAN LETTER EN + // U+10F1: "ჱ" GEORGIAN LETTER HE + key("\u10D4", joinMoreKeys("3", "\u10F1")), + // U+10E0: "რ" GEORGIAN LETTER RAE + key("\u10E0", moreKey("4")), + // U+10E2: "ტ" GEORGIAN LETTER TAR + key("\u10E2", moreKey("5")), + // U+10E7: "ყ" GEORGIAN LETTER QAR + // U+10F8: "ჸ" GEORGIAN LETTER ELIFI + key("\u10E7", joinMoreKeys("6", "\u10F8")), + // U+10E3: "უ" GEORGIAN LETTER UN + key("\u10E3", moreKey("7")), + // U+10D8: "ი" GEORGIAN LETTER IN + // U+10F2: "ჲ" GEORGIAN LETTER HIE + key("\u10D8", joinMoreKeys("8", "\u10F2")), + // U+10DD: "ო" GEORGIAN LETTER ON + key("\u10DD", moreKey("9")), + // U+10DE: "პ" GEORGIAN LETTER PAR + key("\u10DE", moreKey("0"))) + .setKeysOfRow(2, + // U+10D0: "ა" GEORGIAN LETTER AN + // U+10FA: "ჺ" GEORGIAN LETTER AIN + key("\u10D0", moreKey("\u10FA")), + // U+10E1: "ს" GEORGIAN LETTER SAN + // U+10D3: "დ" GEORGIAN LETTER DON + "\u10E1", "\u10D3", + // U+10E4: "ფ" GEORGIAN LETTER PHAR + // U+10F6: "ჶ" GEORGIAN LETTER FI + key("\u10E4", moreKey("\u10F6")), + // U+10D2: "გ" GEORGIAN LETTER GAN + // U+10F9: "ჹ" GEORGIAN LETTER TURNED GAN + key("\u10D2", moreKey("\u10F9")), + // U+10F0: "ჰ" GEORGIAN LETTER HAE + // U+10F5: "ჵ" GEORGIAN LETTER HOE + key("\u10F0", moreKey("\u10F5")), + // U+10EF: "ჯ" GEORGIAN LETTER JHAN + // U+10F7: "ჷ" GEORGIAN LETTER YN + key("\u10EF", moreKey("\u10F7")), + // U+10D9: "კ" GEORGIAN LETTER KAN + // U+10DA: "ლ" GEORGIAN LETTER LAS + "\u10D9", "\u10DA") + .setKeysOfRow(3, + // U+10D6: "ზ" GEORGIAN LETTER ZEN + "\u10D6", + // U+10EE: "ხ" GEORGIAN LETTER XAN + // U+10F4: "ჴ" GEORGIAN LETTER HAR + key("\u10EE", moreKey("\u10F4")), + // U+10EA: "ც" GEORGIAN LETTER CAN + "\u10EA", + // U+10D5: "ვ" GEORGIAN LETTER VIN + // U+10F3: "ჳ" GEORGIAN LETTER WE + key("\u10D5", moreKey("\u10F3")), + // U+10D1: "ბ" GEORGIAN LETTER BAN + "\u10D1", + // U+10DC: "ნ" GEORGIAN LETTER NAR + // U+10FC: "ჼ" MODIFIER LETTER GEORGIAN NAR + key("\u10DC", moreKey("\u10FC")), + // U+10DB: "მ" GEORGIAN LETTER MAN + "\u10DB") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("Q", moreKey("1")), + // U+10ED: "ჭ" GEORGIAN LETTER CHAR + key("\u10ED", moreKey("2")), + key("E", moreKey("3")), + // U+10E6: "ღ" GEORGIAN LETTER GHAN + key("\u10E6", moreKey("4")), + // U+10D7: "თ" GEORGIAN LETTER TAN + key("\u10D7", moreKey("5")), + key("Y", moreKey("6")), + key("U", moreKey("7")), + key("I", moreKey("8")), + key("O", moreKey("9")), + key("P", moreKey("0"))) + .setKeysOfRow(2, + // U+10E8: "შ" GEORGIAN LETTER SHIN + // U+10DF: "ჟ" GEORGIAN LETTER ZHAR + "A", "\u10E8", "D", "F", "G", "H", "\u10DF", "K", "L") + .setKeysOfRow(3, + // U+10EB: "ძ" GEORGIAN LETTER JIL + // U+10E9: "ჩ" GEORGIAN LETTER CHIN + "\u10EB", "X", "\u10E9", "V", "B", "N", "M") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Greek.java b/tests/src/com/android/inputmethod/keyboard/layout/Greek.java new file mode 100644 index 000000000..475052c75 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Greek.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Greek alphabet keyboard. + */ +public final class Greek extends LayoutBase { + private static final String LAYOUT_NAME = "greek"; + + public Greek(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class GreekCustomizer extends EuroCustomizer { + public GreekCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return GREEK_ALPHABET_KEY; } + + // U+0391: "Α" GREEK CAPITAL LETTER ALPHA + // U+0392: "Β" GREEK CAPITAL LETTER BETA + // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA + private static final ExpectedKey GREEK_ALPHABET_KEY = key( + "\u0391\u0392\u0393", Constants.CODE_SWITCH_ALPHA_SYMBOL); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + builder.replaceKeyOfLabel(ROW1_1, ROW1_1_SEMICOLON); + builder.replaceKeyOfLabel(ROW1_2, ROW1_2_FINAL_SIGMA); + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + builder.toUpperCase(getLocale()); + if (elementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED + || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED) { + builder.replaceKeyOfLabel(ROW1_1, ROW1_1_COLON); + } else { + builder.replaceKeyOfLabel(ROW1_1, ROW1_1_SEMICOLON); + } + builder.replaceKeyOfLabel(ROW1_2, ROW1_2_FINAL_SIGMA); + return builder.build(); + } + + private static final String ROW1_1 = "ROW1_1"; + private static final ExpectedKey ROW1_1_SEMICOLON = key(";", joinMoreKeys("1", ":")); + private static final ExpectedKey ROW1_1_COLON = key(":", joinMoreKeys("1", ";")); + + private static final String ROW1_2 = "ROW2_2"; + // U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA + private static final ExpectedKey ROW1_2_FINAL_SIGMA = key("\u03C2", moreKey("2")); + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key(ROW1_1, moreKey("1")), + key(ROW1_2, moreKey("2")), + // U+03B5: "ε" GREEK SMALL LETTER EPSILON + // U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS + key("\u03B5", joinMoreKeys("\u03AD", "3")), + // U+03C1: "ρ" GREEK SMALL LETTER RHO + key("\u03C1", moreKey("4")), + // U+03C4: "τ" GREEK SMALL LETTER TAU + key("\u03C4", moreKey("5")), + // U+03C5: "υ" GREEK SMALL LETTER UPSILON + // U+03CD: "ύ" GREEK SMALL LETTER UPSILON WITH TONOS + // U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA + // U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + key("\u03C5", joinMoreKeys("\u03CD", "6", "\u03CB", "\u03B0")), + // U+03B8: "θ" GREEK SMALL LETTER THETA + key("\u03B8", moreKey("7")), + // U+03B9: "ι" GREEK SMALL LETTER IOTA + // U+03AF: "ί" GREEK SMALL LETTER IOTA WITH TONOS + // U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA + // U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + key("\u03B9", joinMoreKeys("\u03AF", "8", "\u03CA", "\u0390")), + // U+03BF: "ο" GREEK SMALL LETTER OMICRON + // U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS + key("\u03BF", joinMoreKeys("\u03CC", "9")), + // U+03C0: "π" GREEK SMALL LETTER PI + key("\u03C0", moreKey("0"))) + .setKeysOfRow(2, + // U+03B1: "α" GREEK SMALL LETTER ALPHA + // U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS + key("\u03B1", moreKey("\u03AC")), + // U+03C3: "σ" GREEK SMALL LETTER SIGMA + // U+03B4: "δ" GREEK SMALL LETTER DELTA + // U+03C6: "φ" GREEK SMALL LETTER PHI + // U+03B3: "γ" GREEK SMALL LETTER GAMMA + "\u03C3", "\u03B4", "\u03C6", "\u03B3", + // U+03B7: "η" GREEK SMALL LETTER ETA + // U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS + key("\u03B7", moreKey("\u03AE")), + // U+03BE: "ξ" GREEK SMALL LETTER XI + // U+03BA: "κ" GREEK SMALL LETTER KAPPA + // U+03BB: "λ" GREEK SMALL LETTER LAMDA + "\u03BE", "\u03BA", "\u03BB") + .setKeysOfRow(3, + // U+03B6: "ζ" GREEK SMALL LETTER ZETA + // U+03C7: "χ" GREEK SMALL LETTER CHI + // U+03C8: "ψ" GREEK SMALL LETTER PSI + "\u03B6", "\u03C7", "\u03C8", + // U+03C9: "ω" GREEK SMALL LETTER OMEGA + // U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS + key("\u03C9", moreKey("\u03CE")), + // U+03B2: "β" GREEK SMALL LETTER BETA + // U+03BD: "ν" GREEK SMALL LETTER NU + // U+03BC: "μ" GREEK SMALL LETTER MU + "\u03B2", "\u03BD", "\u03BC") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Hebrew.java b/tests/src/com/android/inputmethod/keyboard/layout/Hebrew.java new file mode 100644 index 000000000..552f0d3d5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Hebrew.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.Symbols.RtlSymbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted.RtlSymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +public final class Hebrew extends LayoutBase { + private static final String LAYOUT_NAME = "hebrew"; + + public Hebrew(final LayoutCustomizer customizer) { + super(customizer, HebrewSymbols.class, RtlSymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class HebrewCustomizer extends LayoutCustomizer { + public HebrewCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey getAlphabetKey() { return HEBREW_ALPHABET_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_NEW_SHEQEL; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_LR9; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_LR9; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { + return RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL; + } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { + return RtlSymbols.SINGLE_ANGLE_QUOTES_LR_RTL; + } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS; + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? RTL_PHONE_PUNCTUATION_MORE_KEYS + : RTL_TABLET_PUNCTUATION_MORE_KEYS; + } + + // U+05D0: "א" HEBREW LETTER ALEF + // U+05D1: "ב" HEBREW LETTER BET + // U+05D2: "ג" HEBREW LETTER GIMEL + private static final ExpectedKey HEBREW_ALPHABET_KEY = key( + "\u05D0\u05D1\u05D2", Constants.CODE_SWITCH_ALPHA_SYMBOL); + // U+20AA: "₪" NEW SHEQEL SIGN + private static final ExpectedKey CURRENCY_NEW_SHEQEL = key("\u20AA", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + private static final ExpectedKey[] RTL_PHONE_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "?", "!", "#", key(")", "("), key("(", ")"), "/", ";", + "'", "@", ":", "-", "\"", "+", "%", "&"); + // Punctuation more keys for tablet form factor. + private static final ExpectedKey[] RTL_TABLET_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "'", "#", key(")", "("), key("(", ")"), "/", ";", + "@", ":", "-", "\"", "+", "%", "&"); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + return null; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("'", joinMoreKeys("1", "\"")), + key("-", joinMoreKeys("2", "_")), + // U+05E7: "ק" HEBREW LETTER QOF + key("\u05E7", moreKey("3")), + // U+05E8: "ר" HEBREW LETTER RESH + key("\u05E8", moreKey("4")), + // U+05D0: "א" HEBREW LETTER ALEF + key("\u05D0", moreKey("5")), + // U+05D8: "ט" HEBREW LETTER TET + key("\u05D8", moreKey("6")), + // U+05D5: "ו" HEBREW LETTER VAV + key("\u05D5", moreKey("7")), + // U+05DF: "ן" HEBREW LETTER FINAL NUN + key("\u05DF", moreKey("8")), + // U+05DD: "ם" HEBREW LETTER FINAL MEM + key("\u05DD", moreKey("9")), + // U+05E4: "פ" HEBREW LETTER PE + key("\u05E4", moreKey("0"))) + .setKeysOfRow(2, + // U+05E9: "ש" HEBREW LETTER SHIN + // U+05D3: "ד" HEBREW LETTER DALET + "\u05E9", "\u05D3", + // U+05D2: "ג" HEBREW LETTER GIMEL + // U+05D2 U+05F3: "ג׳" HEBREW LETTER GIMEL + HEBREW PUNCTUATION GERESH + key("\u05D2", moreKey("\u05D2\u05F3")), + // U+05DB: "כ" HEBREW LETTER KAF + // U+05E2: "ע" HEBREW LETTER AYIN + "\u05DB", "\u05E2", + // U+05D9: "י" HEBREW LETTER YOD + // U+05F2 U+05B7: "ײַ" HEBREW LIGATURE YIDDISH DOUBLE YOD + HEBREW POINT PATAH + key("\u05D9", moreKey("\u05F2\u05B7")), + // U+05D7: "ח" HEBREW LETTER HET + // U+05D7 U+05F3: "ח׳" HEBREW LETTER HET + HEBREW PUNCTUATION GERESH + key("\u05D7", moreKey("\u05D7\u05F3")), + // U+05DC: "ל" HEBREW LETTER LAMED + // U+05DA: "ך" HEBREW LETTER FINAL KAF + // U+05E3: "ף" HEBREW LETTER FINAL PE + "\u05DC", "\u05DA", "\u05E3") + .setKeysOfRow(3, + // U+05D6: "ז" HEBREW LETTER ZAYIN + // U+05D6 U+05F3: "ז׳" HEBREW LETTER ZAYIN + HEBREW PUNCTUATION GERESH + key("\u05D6", moreKey("\u05D6\u05F3")), + // U+05E1: "ס" HEBREW LETTER SAMEKH + // U+05D1: "ב" HEBREW LETTER BET + // U+05D4: "ה" HEBREW LETTER HE + // U+05E0: "נ" HEBREW LETTER NUN + // U+05DE: "מ" HEBREW LETTER MEM + "\u05E1", "\u05D1", "\u05D4", "\u05E0", "\u05DE", + // U+05E6: "צ" HEBREW LETTER TSADI + // U+05E6 U+05F3: "צ׳" HEBREW LETTER TSADI + HEBREW PUNCTUATION GERESH + key("\u05E6", moreKey("\u05E6\u05F3")), + // U+05EA: "ת" HEBREW LETTER TAV + // U+05EA U+05F3: "ת׳" HEBREW LETTER TAV + HEBREW PUNCTUATION GERESH + key("\u05EA", moreKey("\u05EA\u05F3")), + // U+05E5: "ץ" HEBREW LETTER FINAL TSADI + // U+05E5 U+05F3: "ץ׳" HEBREW LETTER FINAL TSADI + HEBREW PUNCTUATION GERESH + key("\u05E5", moreKey("\u05E5\u05F3"))) + .build(); + + private static class HebrewSymbols extends RtlSymbols { + public HebrewSymbols(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+00B1: "±" PLUS-MINUS SIGN + // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN + .setMoreKeysOf("+", "\u00B1", "\uFB29") + // U+2605: "★" BLACK STAR + .setMoreKeysOf("*", "\u2605") + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Hindi.java b/tests/src/com/android/inputmethod/keyboard/layout/Hindi.java new file mode 100644 index 000000000..b12b8be64 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Hindi.java @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2014 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.layout; + +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.*; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Hindi keyboard. + */ +public final class Hindi extends LayoutBase { + private static final String LAYOUT_NAME = "hindi"; + + public Hindi(final LayoutCustomizer customizer) { + super(customizer, HindiSymbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class HindiCustomizer extends LayoutCustomizer { + public HindiCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return HINDI_ALPHABET_KEY; } + + @Override + public ExpectedKey getSymbolsKey() { return HINDI_SYMBOLS_KEY; } + + @Override + public ExpectedKey getBackToSymbolsKey() { return HINDI_BACK_TO_SYMBOLS_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS; + } + + // U+0915: "क" DEVANAGARI LETTER KA + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0917: "ग" DEVANAGARI LETTER GA + private static final ExpectedKey HINDI_ALPHABET_KEY = key( + "\u0915\u0916\u0917", Constants.CODE_SWITCH_ALPHA_SYMBOL); + // U+0967: "१" DEVANAGARI DIGIT ONE + // U+0968: "२" DEVANAGARI DIGIT TWO + // U+0969: "३" DEVANAGARI DIGIT THREE + private static final String HINDI_SYMBOLS_LABEL = "?\u0967\u0968\u0969"; + private static final ExpectedKey HINDI_SYMBOLS_KEY = key(HINDI_SYMBOLS_LABEL, + Constants.CODE_SWITCH_ALPHA_SYMBOL); + private static final ExpectedKey HINDI_BACK_TO_SYMBOLS_KEY = key(HINDI_SYMBOLS_LABEL, + Constants.CODE_SHIFT); + + // U+20B9: "₹" INDIAN RUPEE SIGN + private static final ExpectedKey CURRENCY_RUPEE = key("\u20B9", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { return ALPHABET_COMMON; } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+094C: "ौ" DEVANAGARI VOWEL SIGN AU + // U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA + // U+0967: "१" DEVANAGARI DIGIT ONE + key(VOWEL_SIGN_AU, "\u094C", joinMoreKeys( + moreKey(VOWEL_SIGN_AU + "\u0902", "\u094C\u0902"), + "\u0967", "1")), + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + // U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA + // U+0968: "२" DEVANAGARI DIGIT TWO + key(VOWEL_SIGN_AI, "\u0948", joinMoreKeys( + moreKey(VOWEL_SIGN_AI + "\u0902", "\u0948\u0902"), + "\u0968", "2")), + // U+093E: "ा" DEVANAGARI VOWEL SIGN AA + // U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA + // U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU + // U+0969: "३" DEVANAGARI DIGIT THREE + key(VOWEL_SIGN_AA, "\u093E", joinMoreKeys( + moreKey(VOWEL_SIGN_AA + "\u0902", "\u093E\u0902"), + moreKey(VOWEL_SIGN_AA + "\u0901", "\u093E\u0901"), + "\u0969", "3")), + // U+0940: "ी" DEVANAGARI VOWEL SIGN II + // U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA + // U+096A: "४" DEVANAGARI DIGIT FOUR + key(VOWEL_SIGN_II, "\u0940", joinMoreKeys( + moreKey(VOWEL_SIGN_II + "\u0902", "\u0940\u0902"), + "\u096A", "4")), + // U+0942: "ू" DEVANAGARI VOWEL SIGN UU + // U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA + // U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU + // U+096B: "५" DEVANAGARI DIGIT FIVE + key(VOWEL_SIGN_UU, "\u0942", joinMoreKeys( + moreKey(VOWEL_SIGN_UU + "\u0902", "\u0942\u0902"), + moreKey(VOWEL_SIGN_UU + "\u0901", "\u0942\u0901"), + "\u096B", "5")), + // U+092C: "ब" DEVANAGARI LETTER BA + // U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA + // U+096C: "६" DEVANAGARI DIGIT SIX + key("\u092C", joinMoreKeys("\u092C\u0952", "\u096C", "6")), + // U+0939: "ह" DEVANAGARI LETTER HA + // U+096D: "७" DEVANAGARI DIGIT SEVEN + key("\u0939", joinMoreKeys("\u096D", "7")), + // U+0917: "ग" DEVANAGARI LETTER GA + // U+091C/U+094D/U+091E: + // "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA + // U+0917/U+093C: "ग़" DEVANAGARI LETTER GA/DEVANAGARI SIGN NUKTA + // U+0917/U+0952: "ग॒" DEVANAGARI LETTER GA/DEVANAGARI STRESS SIGN ANUDATTA + // U+096E: "८" DEVANAGARI DIGIT EIGHT + key("\u0917", joinMoreKeys("\u091C\u094D\u091E", "\u0917\u093C", "\u0917\u0952", + "\u096E", "8")), + // U+0926: "द" DEVANAGARI LETTER DA + // U+096F: "९" DEVANAGARI DIGIT NINE + key("\u0926", joinMoreKeys("\u096F", "9")), + // U+091C: "ज" DEVANAGARI LETTER JA + // U+091C/U+0952: "ज॒" DEVANAGARI LETTER JA/DEVANAGARI STRESS SIGN ANUDATTA + // U+091C/U+094D/U+091E: + // "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA + // U+091C/U+093C: "ज़" DEVANAGARI LETTER JA/DEVANAGARI SIGN NUKTA + // U+0966: "०" DEVANAGARI DIGIT ZERO + key("\u091C", joinMoreKeys("\u091C\u0952", "\u091C\u094D\u091E", "\u091C\u093C", + "\u0966", "0")), + // U+0921: "ड" DEVANAGARI LETTER DDA + // U+0921/U+0952: "ड॒" DEVANAGARI LETTER DDA/DEVANAGARI STRESS SIGN ANUDATTA + // U+0921/U+093C: "ड़" DEVANAGARI LETTER DDA/DEVANAGARI SIGN NUKTA + key("\u0921", joinMoreKeys("\u0921\u0952", "\u0921\u093C"))) + .setKeysOfRow(2, + // U+094B: "ो" DEVANAGARI VOWEL SIGN O + // U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA + // U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O + // U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O + key(VOWEL_SIGN_O, "\u094B", joinMoreKeys( + moreKey(VOWEL_SIGN_O + "\u0902", "\u094B\u0902"), + moreKey(VOWEL_SIGN_CANDRA_O, "\u0949"), + moreKey(VOWEL_SIGN_SHORT_O, "\u094A"))), + // U+0947: "े" DEVANAGARI VOWEL SIGN E + // U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA + key(VOWEL_SIGN_E, "\u0947", + moreKey(VOWEL_SIGN_E + "\u0902", "\u0947\u0902")), + // U+094D: "्" DEVANAGARI SIGN VIRAMA + key(SIGN_VIRAMA, "\u094D"), + // U+093F: "ि" DEVANAGARI VOWEL SIGN I + // U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA + key(VOWEL_SIGN_I, "\u093F", + moreKey("\u093F" + SIGN_ANUSVARA, "\u093F\u0902")), + // U+0941: "ु" DEVANAGARI VOWEL SIGN U + // U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA + // U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU + key(VOWEL_SIGN_U, "\u0941", joinMoreKeys( + moreKey(VOWEL_SIGN_U + "\u0902", "\u0941\u0902"), + moreKey(VOWEL_SIGN_U + "\u0901", "\u0941\u0901"))), + // U+092A: "प" DEVANAGARI LETTER PA + "\u092A", + // U+0930: "र" DEVANAGARI LETTER RA + // U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + // U+0930/U+093C: "ऱ" DEVANAGARI LETTER RA/DEVANAGARI SIGN NUKTA + // U+0960: "ॠ" DEVANAGARI LETTER VOCALIC RR + key("\u0930", joinMoreKeys("\u090B", "\u0930\u093C", "\u0960")), + // U+0915: "क" DEVANAGARI LETTER KA + // U+0915/U+093C: "क़" DEVANAGARI LETTER KA/DEVANAGARI SIGN NUKTA + key("\u0915", moreKey("\u0915\u093C")), + // U+0924: "त" DEVANAGARI LETTER TA + // U+0924/U+094D/U+0930: + // "त्र" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key("\u0924", moreKey("\u0924\u094D\u0930")), + // U+091A: "च" DEVANAGARI LETTER CA + // U+091F: "ट" DEVANAGARI LETTER TTA + "\u091A","\u091F") + .setKeysOfRow(3, + // U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O + key(VOWEL_SIGN_CANDRA_O, "\u0949"), + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + key(SIGN_ANUSVARA, "\u0902"), + // U+092E: "म" DEVANAGARI LETTER MA + // U+0950: "ॐ" DEVANAGARI OM + key("\u092E", moreKey("\u0950")), + // U+0928: "न" DEVANAGARI LETTER NA + // U+091E: "ञ" DEVANAGARI LETTER NYA + // U+0919: "ङ" DEVANAGARI LETTER NGA + // U+0928/U+093C: "ऩ" DEVANAGARI LETTER NA/DEVANAGARI SIGN NUKTA + key("\u0928", joinMoreKeys("\u091E", "\u0919", "\u0928\u093C")), + // U+0935: "व" DEVANAGARI LETTER VA + "\u0935", + // U+0932: "ल" DEVANAGARI LETTER LA + // U+090C: "ऌ" DEVANAGARI LETTER VOCALIC L + // U+0961: "ॡ" DEVANAGARI LETTER VOCALIC LL + key("\u0932", joinMoreKeys("\u090C", "\u0961")), + // U+0938: "स" DEVANAGARI LETTER SA + "\u0938", + // U+092F: "य" DEVANAGARI LETTER YA + // U+095F: "य़" DEVANAGARI LETTER YYA + key("\u092F", moreKey("\u095F")), + // U+093C: "़" DEVANAGARI SIGN NUKTA + // U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP + // U+0970: "॰" DEVANAGARI ABBREVIATION SIGN + // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA + key(SIGN_NUKTA, "\u093C", joinMoreKeys( + moreKey(LETTER_GLOTTAL_STOP, "\u097D"), + moreKey(ABBREVIATION_SIGN, "\u0970"), + moreKey(SIGN_AVAGRAHA, "\u093D")))) + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0914: "औ" DEVANAGARI LETTER AU + // U+0912/U+0902: "ऒं" DEVANAGARI LETTER SHORT O//DEVANAGARI SIGN ANUSVARA + key("\u0914", moreKey("\u0912\u0902")), + // U+0910: "ऐ" DEVANAGARI LETTER AI + // U+0910/U+0902: "ऐं" DEVANAGARI LETTER AI/DEVANAGARI SIGN ANUSVARA + key("\u0910", moreKey("\u0910\u0902")), + // U+0906: "आ" DEVANAGARI LETTER AA + // U+0906/U+0902: "आं" DEVANAGARI LETTER AA/DEVANAGARI SIGN ANUSVARA + // U+0906/U+0901: "आँ" DEVANAGARI LETTER AA/DEVANAGARI SIGN CANDRABINDU + key("\u0906", joinMoreKeys("\u0906\u0902", "\u0906\u0901")), + // U+0908: "ई" DEVANAGARI LETTER II + // U+0908/U+0902: "ईं" DEVANAGARI LETTER II/DEVANAGARI SIGN ANUSVARA + key("\u0908", moreKey("\u0908\u0902")), + // U+090A: "ऊ" DEVANAGARI LETTER UU + // U+090A/U+0902: "ऊं" DEVANAGARI LETTER UU/DEVANAGARI SIGN ANUSVARA + // U+090A/U+0901: "ऊँ" DEVANAGARI LETTER UU/DEVANAGARI SIGN CANDRABINDU + key("\u090A", joinMoreKeys("\u090A\u0902", "\u090A\u0901")), + // U+092D: "भ" DEVANAGARI LETTER BHA + // U+0903: "ः" DEVANAGARI SIGN VISARGA + // U+0918: "घ" DEVANAGARI LETTER GHA + "\u092D", key(SIGN_VISARGA, "\u0903"), "\u0918", + // U+0927: "ध" DEVANAGARI LETTER DHA + // U+0915/U+094D/U+0937: + // "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA + // U+0936/U+094D/U+0930: + // "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key("\u0927", joinMoreKeys("\u0915\u094D\u0937", "\u0936\u094D\u0930")), + // U+091D: "झ" DEVANAGARI LETTER JHA + // U+0922: "ढ" DEVANAGARI LETTER DDHA + "\u091D", "\u0922") + .setKeysOfRow(2, + // U+0913: "ओ" DEVANAGARI LETTER O + // U+0913/U+0902: "ओं" DEVANAGARI LETTER O/DEVANAGARI SIGN ANUSVARA + // U+0911: "ऑ" DEVANAGARI LETTER CANDRA O + // U+0912: "ऒ" DEVANAGARI LETTER SHORT O + key("\u0913", joinMoreKeys("\u0913\u0902", "\u0911", "\u0912")), + // U+090F: "ए" DEVANAGARI LETTER E + // U+090F/U+0902: "एं" DEVANAGARI LETTER E/DEVANAGARI SIGN ANUSVARA + // U+090F/U+0901: "एँ" DEVANAGARI LETTER E/DEVANAGARI SIGN CANDRABINDU + // U+090D: "ऍ" DEVANAGARI LETTER CANDRA E + // U+090E: "ऎ" DEVANAGARI LETTER SHORT E + key("\u090F", joinMoreKeys("\u090F\u0902", "\u090F\u0901", "\u090D", "\u090E")), + // U+0905: "अ" DEVANAGARI LETTER A + // U+0905/U+0902: "अं" DEVANAGARI LETTER A/DEVANAGARI SIGN ANUSVARA + // U+0905/U+0901: "अँ" DEVANAGARI LETTER A/DEVANAGARI SIGN CANDRABINDU + key("\u0905", joinMoreKeys("\u0905\u0902", "\u0905\u0901")), + // U+0907: "इ" DEVANAGARI LETTER I + // U+0907/U+0902: "इं" DEVANAGARI LETTER I/DEVANAGARI SIGN ANUSVARA + // U+0907/U+0901: "इं" DEVANAGARI LETTER I/DEVANAGARI SIGN CANDRABINDU + key("\u0907", joinMoreKeys("\u0907\u0902", "\u0907\u0901")), + // U+0909: "उ" DEVANAGARI LETTER U + // U+0909/U+0902: "उं" DEVANAGARI LETTER U/DEVANAGARI SIGN ANUSVARA + // U+0909/U+0901: "उँ" DEVANAGARI LETTER U/DEVANAGARI SIGN CANDRABINDU + key("\u0909", joinMoreKeys("\u0909\u0902", "\u0909\u0901")), + // U+092B: "फ" DEVANAGARI LETTER PHA + // U+092B/U+093C: "फ़" DEVANAGARI LETTER PHA/DEVANAGARI SIGN NUKTA + key("\u092B", moreKey("\u092B\u093C")), + // U+0931: "ऱ" DEVANAGARI LETTER RRA + // U+094D/U+0930: "्र" DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + // U+0930/U+094D: "र्" DEVANAGARI LETTER RA/DEVANAGARI SIGN VIRAMA + key("\u0931", joinMoreKeys("\u094D\u0930", "\u0930\u094D")), + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0916/U+093C: "ख़" DEVANAGARI LETTER KHA/DEVANAGARI SIGN NUKTA + key("\u0916", moreKey("\u0916\u093C")), + // U+0925: "थ" DEVANAGARI LETTER THA + // U+091B: "छ" DEVANAGARI LETTER CHA + // U+0920: "ठ" DEVANAGARI LETTER TTHA + "\u0925", "\u091B", "\u0920") + .setKeysOfRow(3, + // U+0911: "ऑ" DEVANAGARI LETTER CANDRA O + "\u0911", + // U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + // U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E + key(SIGN_CANDRABINDU, "\u0901", moreKey(VOWEL_SIGN_CANDRA_E, "\u0945")), + // U+0923: "ण" DEVANAGARI LETTER NNA + // U+0929: "ऩ" DEVANAGARI LETTER NNNA + "\u0923", "\u0929", + // U+0933: "ळ" DEVANAGARI LETTER LLA + // U+0934: "ऴ" DEVANAGARI LETTER LLLA + key("\u0933", moreKey("\u0934")), + // U+0936: "श" DEVANAGARI LETTER SHA + // U+0937: "ष" DEVANAGARI LETTER SSA + "\u0936", "\u0937", + // U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R + // U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR + key(VOWEL_SIGN_VOCALIC_R, "\u0943", moreKey(VOWEL_SIGN_VOCALIC_RR, "\u0944")), + // U+091E: "ञ" DEVANAGARI LETTER NYA + "\u091E") + .build(); + + static class HindiSymbols extends Symbols { + public HindiSymbols(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + // U+0967: "१" DEVANAGARI DIGIT ONE + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + .replaceKeyOfLabel("1", key("\u0967", + joinMoreKeys("1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B"))) + // U+0968: "२" DEVANAGARI DIGIT TWO + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + .replaceKeyOfLabel("2", key("\u0968", joinMoreKeys("2", "\u00B2", "\u2154"))) + // U+0969: "३" DEVANAGARI DIGIT THREE + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + .replaceKeyOfLabel("3", key("\u0969", + joinMoreKeys("3", "\u00B3", "\u00BE","\u215C"))) + // U+096A: "४" DEVANAGARI DIGIT FOUR + // U+2074: "⁴" SUPERSCRIPT FOUR + .replaceKeyOfLabel("4", key("\u096A", joinMoreKeys("4", "\u2074"))) + // U+096B: "५" DEVANAGARI DIGIT FIVE + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + .replaceKeyOfLabel("5", key("\u096B", joinMoreKeys("5", "\u215D"))) + // U+096C: "६" DEVANAGARI DIGIT SIX + .replaceKeyOfLabel("6", key("\u096C", moreKey("6"))) + // U+096D: "७" DEVANAGARI DIGIT SEVEN + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + .replaceKeyOfLabel("7", key("\u096D", joinMoreKeys("7", "\u215E"))) + // U+096E: "८" DEVANAGARI DIGIT EIGHT + .replaceKeyOfLabel("8", key("\u096E", moreKey("8"))) + // U+096F: "९" DEVANAGARI DIGIT NINE + .replaceKeyOfLabel("9", key("\u096F", moreKey("9"))) + // U+0966: "०" DEVANAGARI DIGIT ZERO + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + .replaceKeyOfLabel("0", key("\u0966", joinMoreKeys("0", "\u207F", "\u2205"))) + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java new file mode 100644 index 000000000..afd26e428 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2014 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.layout; + +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_ANUSVARA; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_CANDRABINDU; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_NUKTA; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_VIRAMA; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_VISARGA; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AA; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AI; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AU; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_CANDRA_E; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_CANDRA_O; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_E; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_I; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_II; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_O; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_U; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_UU; +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_VOCALIC_R; + +import com.android.inputmethod.keyboard.layout.Hindi.HindiCustomizer; +import com.android.inputmethod.keyboard.layout.Hindi.HindiSymbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Hindi Compact keyboard. + */ +public final class HindiCompact extends LayoutBase { + private static final String LAYOUT_NAME = "hindi_compact"; + + public HindiCompact(final LayoutCustomizer customizer) { + super(customizer, HindiSymbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class HindiCompactCustomizer extends HindiCustomizer { + public HindiCompactCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return EMPTY_KEYS; + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + // U+0964: "।" DEVANAGARI DANDA + final ExpectedKey periodKey = key("\u0964", getPunctuationMoreKeys(isPhone)); + return isPhone ? joinKeys(periodKey) : joinKeys(",", periodKey); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? HINDI_PHONE_PUNCTUATION_MORE_KEYS : HINDI_TABLET_PUNCTUATION_MORE_KEYS; + } + + // Punctuation more keys for phone form factor. + private static final ExpectedKey[] HINDI_PHONE_PUNCTUATION_MORE_KEYS = joinKeys( + ",", ".", "?", "!", "#", ")", "(", "/", ";", + "'", "@", ":", "-", "\"", "+", "%", "&"); + // Punctuation more keys for tablet form factor. + private static final ExpectedKey[] HINDI_TABLET_PUNCTUATION_MORE_KEYS = joinKeys( + ",", ".", "'", "#", ")", "(", "/", ";", + "@", ":", "-", "\"", "+", "%", "&"); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { return ALPHABET_COMMON; } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) { + return null; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0914: "औ" DEVANAGARI LETTER AU + // U+094C: "ौ" DEVANAGARI VOWEL SIGN AU + // U+0967: "१" DEVANAGARI DIGIT ONE + key("\u0914", joinMoreKeys(moreKey(VOWEL_SIGN_AU, "\u094C"), "\u0967", "1")), + // U+0910: "ऐ" DEVANAGARI LETTER AI + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + // U+0968: "२" DEVANAGARI DIGIT TWO + key("\u0910", joinMoreKeys(moreKey(VOWEL_SIGN_AI, "\u0948"), "\u0968", "2")), + // U+0906: "आ" DEVANAGARI LETTER AA + // U+093E: "ा" DEVANAGARI VOWEL SIGN AA + // U+0969: "३" DEVANAGARI DIGIT THREE + key("\u0906", joinMoreKeys(moreKey(VOWEL_SIGN_AA, "\u093E"), "\u0969", "3")), + // U+0908: "ई" DEVANAGARI LETTER II + // U+0940: "ी" DEVANAGARI VOWEL SIGN II + // U+096A: "४" DEVANAGARI DIGIT FOUR + key("\u0908", joinMoreKeys(moreKey(VOWEL_SIGN_II, "\u0940"), "\u096A", "4")), + // U+090A: "ऊ" DEVANAGARI LETTER UU + // U+0942: "ू" DEVANAGARI VOWEL SIGN UU + // U+096B: "५" DEVANAGARI DIGIT FIVE + key("\u090A", joinMoreKeys(moreKey(VOWEL_SIGN_UU, "\u0942"), "\u096B", "5")), + // U+092C: "ब" DEVANAGARI LETTER BA + // U+092D: "भ" DEVANAGARI LETTER BHA + // U+096C: "६" DEVANAGARI DIGIT SIX + key("\u092C", joinMoreKeys("\u092D", "\u096C", "6")), + // U+0939: "ह" DEVANAGARI LETTER HA + // U+096D: "७" DEVANAGARI DIGIT SEVEN + key("\u0939", joinMoreKeys("\u096D", "7")), + // U+0917: "ग" DEVANAGARI LETTER GA + // U+0918: "घ" DEVANAGARI LETTER GHA + // U+096E: "८" DEVANAGARI DIGIT EIGHT + key("\u0917", joinMoreKeys("\u0918", "\u096E", "8")), + // U+0926: "द" DEVANAGARI LETTER DA + // U+0927: "ध" DEVANAGARI LETTER DHA + // U+096F: "९" DEVANAGARI DIGIT NINE + key("\u0926", joinMoreKeys("\u0927", "\u096F", "9")), + // U+091C: "ज" DEVANAGARI LETTER JA + // U+091D: "झ" DEVANAGARI LETTER JHA + // U+091C/U+094D/U+091E: + // "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA + // U+0966: "०" DEVANAGARI DIGIT ZERO + key("\u091C", joinMoreKeys("\u091D", "\u091C\u094D\u091E", "\u0966", "0")), + // U+0921: "ड" DEVANAGARI LETTER DDA + // U+0922: "ढ" DEVANAGARI LETTER DDHA + key("\u0921", moreKey("\u0922"))) + .setKeysOfRow(2, + // U+0913: "ओ" DEVANAGARI LETTER O + // U+094B: "ो" DEVANAGARI VOWEL SIGN O + key("\u0913", moreKey(VOWEL_SIGN_O, "\u094B")), + // U+090F: "ए" DEVANAGARI LETTER E + // U+0947: "े" DEVANAGARI VOWEL SIGN E + key("\u090F", moreKey(VOWEL_SIGN_E, "\u0947")), + // U+0905: "अ" DEVANAGARI LETTER A + // U+094D: "्" DEVANAGARI SIGN VIRAMA + key("\u0905", moreKey(SIGN_VIRAMA, "\u094D")), + // U+0907: "इ" DEVANAGARI LETTER I + // U+093F: "ि" DEVANAGARI VOWEL SIGN I + key("\u0907", moreKey(VOWEL_SIGN_I, "\u093F")), + // U+0909: "उ" DEVANAGARI LETTER U + // U+0941: "ु" DEVANAGARI VOWEL SIGN U + key("\u0909", moreKey(VOWEL_SIGN_U, "\u0941")), + // U+092A: "प" DEVANAGARI LETTER PA + // U+092B: "फ" DEVANAGARI LETTER PHA + key("\u092A", moreKey("\u092B")), + // U+0930: "र" DEVANAGARI LETTER RA + // U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + // U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R + key("\u0930", joinMoreKeys("\u090B", moreKey(VOWEL_SIGN_VOCALIC_R, "\u0943"))), + // U+0915: "क" DEVANAGARI LETTER KA + // U+0916: "ख" DEVANAGARI LETTER KHA + key("\u0915", moreKey("\u0916")), + // U+0924: "त" DEVANAGARI LETTER TA + // U+0925: "थ" DEVANAGARI LETTER THA + // U+0924/U+094D/U+0930: + // "त्र" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key("\u0924", joinMoreKeys("\u0925", "\u0924\u094D\u0930")), + // U+091A: "च" DEVANAGARI LETTER CA + // U+091B: "छ" DEVANAGARI LETTER CHA + key("\u091A", moreKey("\u091B")), + // U+091F: "ट" DEVANAGARI LETTER TTA + // U+0920: "ठ" DEVANAGARI LETTER TTHA + key("\u091F", moreKey("\u0920"))) + .setKeysOfRow(3, + // U+0911: "ऑ" DEVANAGARI LETTER CANDRA O + // U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O + key("\u0911", moreKey(VOWEL_SIGN_CANDRA_O, "\u0949")), + // U+090D: "ऍ" DEVANAGARI LETTER CANDRA E + // U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E + key("\u090D", moreKey(VOWEL_SIGN_CANDRA_E, "\u0945")), + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + // U+0903: "ः" DEVANAGARI SIGN VISARGA + // U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + // U+093C: "़" DEVANAGARI SIGN NUKTA + key(SIGN_ANUSVARA, "\u0902", joinMoreKeys( + moreKey(SIGN_VISARGA, "\u0903"), + moreKey(SIGN_CANDRABINDU, "\u0901"), + moreKey(SIGN_NUKTA, "\u093C"))), + // U+092E: "म" DEVANAGARI LETTER MA + // U+0950: "ॐ" DEVANAGARI OM + key("\u092E", moreKey("\u0950")), + // U+0928: "न" DEVANAGARI LETTER NA + // U+0923: "ण" DEVANAGARI LETTER NNA + // U+091E: "ञ" DEVANAGARI LETTER NYA + // U+0919: "ङ" DEVANAGARI LETTER NGA + key("\u0928", joinMoreKeys("\u0923", "\u091E", "\u0919")), + // U+0935: "व" DEVANAGARI LETTER VA + // U+0932: "ल" DEVANAGARI LETTER LA + "\u0935", "\u0932", + // U+0938: "स" DEVANAGARI LETTER SA + // U+0936: "श" DEVANAGARI LETTER SHA + // U+0937: "ष" DEVANAGARI LETTER SSA + // U+0936/U+094D/U+0930: + // "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key("\u0938", joinMoreKeys("\u0936", "\u0937", "\u0936\u094D\u0930")), + // U+092F: "य" DEVANAGARI LETTER YA + // U+0915/U+094D/U+0937: + // "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA + "\u092F", "\u0915\u094D\u0937") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java b/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java new file mode 100644 index 000000000..e7f6a6552 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Khmer alphabet keyboard. + */ +public final class Khmer extends LayoutBase { + private static final String LAYOUT_NAME = "khmer"; + + public Khmer(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class KhmerCustomizer extends LayoutCustomizer { + public KhmerCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return KHMER_ALPHABET_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_DOLLAR_WITH_RIEL; } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { return EMPTY_KEYS; } + + // U+1780: "ក" KHMER LETTER KA + // U+1781: "ខ" KHMER LETTER KHA + // U+1782: "គ" KHMER LETTER KO + private static final ExpectedKey KHMER_ALPHABET_KEY = key( + "\u1780\u1781\u1782", Constants.CODE_SWITCH_ALPHA_SYMBOL); + + // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL + private static final ExpectedKey CURRENCY_DOLLAR_WITH_RIEL = key(Symbols.DOLLAR_SIGN, + moreKey("\u17DB"), Symbols.CENT_SIGN, Symbols.POUND_SIGN, Symbols.EURO_SIGN, + Symbols.YEN_SIGN, Symbols.PESO_SIGN); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + if (isPhone) { + return ALPHABET_COMMON; + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + builder.addKeysOnTheRightOfRow(4, (Object[])EXCLAMATION_AND_QUESTION_MARKS); + return builder.build(); + } + + @Override + public ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, + final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(4, DELETE_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(5, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+17E1: "១" KHMER DIGIT ONE + // U+17F1: "៱" KHMER SYMBOL LEK ATTAK MUOY + key("\u17E1", joinMoreKeys("1", "\u17F1")), + // U+17E2: "២" KHMER DIGIT TWO + // U+17F2: "៲" KHMER SYMBOL LEK ATTAK PII + key("\u17E2", joinMoreKeys("2", "\u17F2")), + // U+17E3: "៣" KHMER DIGIT THREE + // U+17F3: "៳" KHMER SYMBOL LEK ATTAK BEI + key("\u17E3", joinMoreKeys("3", "\u17F3")), + // U+17E4: "៤" KHMER DIGIT FOUR + // U+17F4: "៴" KHMER SYMBOL LEK ATTAK BUON + key("\u17E4", joinMoreKeys("4", "\u17F4")), + // U+17E5: "៥" KHMER DIGIT FIVE + // U+17F5: "៵" KHMER SYMBOL LEK ATTAK PRAM + key("\u17E5", joinMoreKeys("5", "\u17F5")), + // U+17E6: "៦" KHMER DIGIT SIX + // U+17F6: "៶" KHMER SYMBOL LEK ATTAK PRAM-MUOY + key("\u17E6", joinMoreKeys("6", "\u17F6")), + // U+17E7: "៧" KHMER DIGIT SEVEN + // U+17F7: "៷" KHMER SYMBOL LEK ATTAK PRAM-PII + key("\u17E7", joinMoreKeys("7", "\u17F7")), + // U+17E8: "៨" KHMER DIGIT EIGHT + // U+17F8: "៸" KHMER SYMBOL LEK ATTAK PRAM-BEI + key("\u17E8", joinMoreKeys("8", "\u17F8")), + // U+17E9: "៩" KHMER DIGIT NINE + // U+17F9: "៹" KHMER SYMBOL LEK ATTAK PRAM-BUON + key("\u17E9", joinMoreKeys("9", "\u17F9")), + // U+17E0: "០" KHMER DIGIT ZERO + // U+17F0: "៰" KHMER SYMBOL LEK ATTAK SON + key("\u17E0", joinMoreKeys("0", "\u17F0")), + // U+17A5: "ឥ" KHMER INDEPENDENT VOWEL QI + // U+17A6: "ឦ" KHMER INDEPENDENT VOWEL QII + key("\u17A5", moreKey("\u17A6")), + // U+17B2: "ឲ" KHMER INDEPENDENT VOWEL QOO TYPE TWO + // U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE + key("\u17B2", moreKey("\u17B1"))) + .setKeysOfRow(2, + // U+1786: "ឆ" KHMER LETTER CHA + // U+17B9: "ឹ" KHMER VOWEL SIGN Y + // U+17C1: "េ" KHMER VOWEL SIGN E + // U+179A: "រ" KHMER LETTER RO + // U+178F: "ត" KHMER LETTER TA + // U+1799: "យ" KHMER LETTER YO + // U+17BB: "ុ" KHMER VOWEL SIGN U + // U+17B7: "ិ" KHMER VOWEL SIGN I + // U+17C4: "ោ" KHMER VOWEL SIGN OO + // U+1795: "ផ" KHMER LETTER PHA + // U+17C0: "ៀ" KHMER VOWEL SIGN IE + "\u1786", "\u17B9", "\u17C1", "\u179A", "\u178F", "\u1799", "\u17BB", "\u17B7", + "\u17C4", "\u1795", "\u17C0", + // U+17AA: "ឪ" KHMER INDEPENDENT VOWEL QUUV + // U+17A7: "ឧ" KHMER INDEPENDENT VOWEL QU + // U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE + // U+17B3: "ឳ" KHMER INDEPENDENT VOWEL QAU + // U+17A9: "ឩ" KHMER INDEPENDENT VOWEL QUU + // U+17A8: "ឨ" KHMER INDEPENDENT VOWEL QUK + key("\u17AA", joinMoreKeys("\u17A7", "\u17B1", "\u17B3", "\u17A9", "\u17A8"))) + .setKeysOfRow(3, + // U+17B6: "ា" KHMER VOWEL SIGN AA + // U+179F: "ស" KHMER LETTER SA + // U+178A: "ដ" KHMER LETTER DA + // U+1790: "ថ" KHMER LETTER THA + // U+1784: "ង" KHMER LETTER NGO + // U+17A0: "ហ" KHMER LETTER HA + // U+17D2: "្" KHMER SIGN COENG + // U+1780: "ក" KHMER LETTER KA + // U+179B: "ល" KHMER LETTER LO + // U+17BE: "ើ" KHMER VOWEL SIGN OE + // U+17CB: "់" KHMER SIGN BANTOC + "\u17B6", "\u179F", "\u178A", "\u1790", "\u1784", "\u17A0", "\u17D2", "\u1780", + "\u179B", "\u17BE", "\u17CB", + // U+17AE: "ឮ" KHMER INDEPENDENT VOWEL LYY + // U+17AD: "ឭ" KHMER INDEPENDENT VOWEL LY + // U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI + key("\u17AE", joinMoreKeys("\u17AD", "\u17B0"))) + .setKeysOfRow(4, + // U+178B: "ឋ" KHMER LETTER TTHA + // U+1781: "ខ" KHMER LETTER KHA + // U+1785: "ច" KHMER LETTER CA + // U+179C: "វ" KHMER LETTER VO + // U+1794: "ប" KHMER LETTER BA + // U+1793: "ន" KHMER LETTER NO + // U+1798: "ម" KHMER LETTER MO + // U+17BB/U+17C6: "ុំ" KHMER VOWEL SIGN U/KHMER SIGN NIKAHIT + // U+17D4: "។" KHMER SIGN KHAN + // U+17CA: "៊" KHMER SIGN TRIISAP + "\u178B", "\u1781", "\u1785", "\u179C", "\u1794", "\u1793", "\u1798", + "\u17BB\u17C6", "\u17D4", "\u17CA") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("!", ZWJ_KEY), + // U+17D7: "ៗ" KHMER SIGN LEK TOO + key("\u17D7", ZWNJ_KEY), + // U+17D1: "៑" KHMER SIGN VIRIAM + key("\"", moreKey("\u17D1")), + // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL + key("\u17DB", joinMoreKeys(Symbols.DOLLAR_SIGN, Symbols.EURO_SIGN)), + // U+17D6: "៖" KHMER SIGN CAMNUC PII KUUH + key("%", moreKey("\u17D6")), + // U+17CD: "៍" KHMER SIGN TOANDAKHIAT + // U+17D9: "៙" KHMER SIGN PHNAEK MUAN + key("\u17CD", moreKey("\u17D9")), + // U+17D0: "័" KHMER SIGN SAMYOK SANNYA + // U+17DA: "៚" KHMER SIGN KOOMUUT + key("\u17D0", moreKey("\u17DA")), + // U+17CF: "៏" KHMER SIGN AHSDA + key("\u17CF", moreKey("*")), + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + key("(", joinMoreKeys("{", "\u00AB")), + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + key(")", joinMoreKeys("}", "\u00BB")), + // U+17CC: "៌" KHMER SIGN ROBAT + // U+00D7: "×" MULTIPLICATION SIGN + key("\u17CC", moreKey("\u00D7")), + // U+17CE: "៎" KHMER SIGN KAKABAT + "\u17CE") + .setKeysOfRow(2, + // U+1788: "ឈ" KHMER LETTER CHO + // U+17DC: "ៜ" KHMER SIGN AVAKRAHASANYA + key("\u1788", moreKey("\u17DC")), + // U+17BA: "ឺ" KHMER VOWEL SIGN YY + // U+17DD: "៝" KHMER SIGN ATTHACAN + key("\u17BA", moreKey("\u17DD")), + // U+17C2: "ែ" KHMER VOWEL SIGN AE + "\u17C2", + // U+17AC: "ឬ" KHMER INDEPENDENT VOWEL RYY + // U+17AB: "ឫ" KHMER INDEPENDENT VOWEL RY + key("\u17AC", moreKey("\u17AB")), + // U+1791: "ទ" KHMER LETTER TO + // U+17BD: "ួ" KHMER VOWEL SIGN UA + // U+17BC: "ូ" KHMER VOWEL SIGN UU + // U+17B8: "ី" KHMER VOWEL SIGN II + // U+17C5: "ៅ" KHMER VOWEL SIGN AU + // U+1797: "ភ" KHMER LETTER PHO + // U+17BF: "ឿ" KHMER VOWEL SIGN YA + // U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI + "\u1791", "\u17BD", "\u17BC", "\u17B8", "\u17C5", "\u1797", "\u17BF", "\u17B0") + .setKeysOfRow(3, + // U+17B6/U+17C6: "ាំ" KHMER VOWEL SIGN AA/KHMER SIGN NIKAHIT + // U+17C3: "ៃ" KHMER VOWEL SIGN AI + // U+178C: "ឌ" KHMER LETTER DO + // U+1792: "ធ" KHMER LETTER THO + // U+17A2: "អ" KHMER LETTER QAE + "\u17B6\u17C6", "\u17C3", "\u178C", "\u1792", "\u17A2", + // U+17C7: "ះ" KHMER SIGN REAHMUK + // U+17C8: "ៈ" KHMER SIGN YUUKALEAPINTU + key("\u17C7", moreKey("\u17C8")), + // U+1789: "ញ" KHMER LETTER NYO + "\u1789", + // U+1782: "គ" KHMER LETTER KO + // U+179D: "ឝ" KHMER LETTER SHA + key("\u1782", moreKey("\u179D")), + // U+17A1: "ឡ" KHMER LETTER LA + // U+17C4/U+17C7: "ោះ" KHMER VOWEL SIGN OO/KHMER SIGN REAHMUK + // U+17C9: "៉" KHMER SIGN MUUSIKATOAN + // U+17AF: "ឯ" KHMER INDEPENDENT VOWEL QE + "\u17A1", "\u17C4\u17C7", "\u17C9", "\u17AF") + .setKeysOfRow(4, + // U+178D: "ឍ" KHMER LETTER TTHO + // U+1783: "ឃ" KHMER LETTER KHO + // U+1787: "ជ" KHMER LETTER CO + // U+17C1/U+17C7: "េះ" KHMER VOWEL SIGN E/KHMER SIGN REAHMUK + "\u178D", "\u1783", "\u1787", "\u17C1\u17C7", + // U+1796: "ព" KHMER LETTER PO + // U+179E: "ឞ" KHMER LETTER SSO + key("\u1796", moreKey("\u179E")), + // U+178E: "ណ" KHMER LETTER NNO + // U+17C6: "ំ" KHMER SIGN NIKAHIT + // U+17BB/U+17C7: "ុះ" KHMER VOWEL SIGN U/KHMER SIGN REAHMUK + // U+17D5: "៕" KHMER SIGN BARIYOOSAN + "\u178E", "\u17C6", "\u17BB\u17C7", "\u17D5", "?") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Lao.java b/tests/src/com/android/inputmethod/keyboard/layout/Lao.java new file mode 100644 index 000000000..6f2ef216f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Lao.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Khmer alphabet keyboard. + */ +public final class Lao extends LayoutBase { + private static final String LAYOUT_NAME = "lao"; + + public Lao(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class LaoCustomizer extends LayoutCustomizer { + public LaoCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return LAO_ALPHABET_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_KIP; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { return EMPTY_KEYS; } + + // U+0E81: "ກ" LAO LETTER KO + // U+0E82: "ຂ" LAO LETTER KHO SUNG + // U+0E84: "ຄ" LAO LETTER KHO TAM + private static final ExpectedKey LAO_ALPHABET_KEY = key( + "\u0E81\u0E82\u0E84", Constants.CODE_SWITCH_ALPHA_SYMBOL); + + // U+20AD: "₭" KIP SIGN + private static final ExpectedKey CURRENCY_KIP = key("\u20AD", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + if (isPhone) { + return ALPHABET_COMMON; + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + builder.addKeysOnTheRightOfRow(4, (Object[])EXCLAMATION_AND_QUESTION_MARKS); + return builder.build(); + } + + @Override + public ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, + final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(4, DELETE_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(5, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0EA2: "ຢ" LAO LETTER YO + // U+0ED1: "໑" LAO DIGIT ONE + key("\u0EA2", joinMoreKeys("1", "\u0ED1")), + // U+0E9F: "ຟ" LAO LETTER FO SUNG + // U+0ED2: "໒" LAO DIGIT TWO + key("\u0E9F", joinMoreKeys("2", "\u0ED2")), + // U+0EC2: "ໂ" LAO VOWEL SIGN O + // U+0ED3: "໓" LAO DIGIT THREE + key("\u0EC2", joinMoreKeys("3", "\u0ED3")), + // U+0E96: "ຖ" LAO LETTER THO SUNG + // U+0ED4: "໔" LAO DIGIT FOUR + key("\u0E96", joinMoreKeys("4", "\u0ED4")), + // U+0EB8: "ຸ" LAO VOWEL SIGN U + // U+0EB9: "ູ" LAO VOWEL SIGN UU + "\u0EB8", "\u0EB9", + // U+0E84: "ຄ" LAO LETTER KHO TAM + // U+0ED5: "໕" LAO DIGIT FIVE + key("\u0E84", joinMoreKeys("5", "\u0ED5")), + // U+0E95: "ຕ" LAO LETTER TO + // U+0ED6: "໖" LAO DIGIT SIX + key("\u0E95", joinMoreKeys("6", "\u0ED6")), + // U+0E88: "ຈ" LAO LETTER CO + // U+0ED7: "໗" LAO DIGIT SEVEN + key("\u0E88", joinMoreKeys("7", "\u0ED7")), + // U+0E82: "ຂ" LAO LETTER KHO SUNG + // U+0ED8: "໘" LAO DIGIT EIGHT + key("\u0E82", joinMoreKeys("8", "\u0ED8")), + // U+0E8A: "ຊ" LAO LETTER SO TAM + // U+0ED9: "໙" LAO DIGIT NINE + key("\u0E8A", joinMoreKeys("9", "\u0ED9")), + // U+0ECD: "ໍ" LAO NIGGAHITA + "\u0ECD") + .setKeysOfRow(2, + // U+0EBB: "ົ" LAO VOWEL SIGN MAI KON + "\u0EBB", + // U+0EC4: "ໄ" LAO VOWEL SIGN AI + // U+0ED0: "໐" LAO DIGIT ZERO + key("\u0EC4", joinMoreKeys("0", "\u0ED0")), + // U+0EB3: "ຳ" LAO VOWEL SIGN AM + // U+0E9E: "ພ" LAO LETTER PHO TAM + // U+0EB0: "ະ" LAO VOWEL SIGN A + // U+0EB4: "ິ" LAO VOWEL SIGN I + // U+0EB5: "ີ" LAO VOWEL SIGN II + // U+0EAE: "ຮ" LAO LETTER HO TAM + // U+0E99: "ນ" LAO LETTER NO + // U+0E8D: "ຍ" LAO LETTER NYO + // U+0E9A: "ບ" LAO LETTER BO + // U+0EA5: "ລ" LAO LETTER LO LOOT + "\u0EB3", "\u0E9E", "\u0EB0", "\u0EB4", "\u0EB5", "\u0EAE", "\u0E99", "\u0E8D", + "\u0E9A", "\u0EA5") + .setKeysOfRow(3, + // U+0EB1: "ັ" LAO VOWEL SIGN MAI KAN + // U+0EAB: "ຫ" LAO LETTER HO SUNG + // U+0E81: "ກ" LAO LETTER KO + // U+0E94: "ດ" LAO LETTER DO + // U+0EC0: "ເ" LAO VOWEL SIGN E + // U+0EC9: "້" LAO TONE MAI THO + // U+0EC8: "່" LAO TONE MAI EK + // U+0EB2: "າ" LAO VOWEL SIGN AA + // U+0EAA: "ສ" LAO LETTER SO SUNG + // U+0EA7: "ວ" LAO LETTER WO + // U+0E87: "ງ" LAO LETTER NGO + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + "\u0EB1", "\u0EAB", "\u0E81", "\u0E94", "\u0EC0", "\u0EC9", "\u0EC8", "\u0EB2", + "\u0EAA", "\u0EA7", "\u0E87", "\u201C") + .setKeysOfRow(4, + // U+0E9C: "ຜ" LAO LETTER PHO SUNG + // U+0E9B: "ປ" LAO LETTER PO + // U+0EC1: "ແ" LAO VOWEL SIGN EI + // U+0EAD: "ອ" LAO LETTER O + // U+0EB6: "ຶ" LAO VOWEL SIGN Y + // U+0EB7: "ື" LAO VOWEL SIGN YY + // U+0E97: "ທ" LAO LETTER THO TAM + // U+0EA1: "ມ" LAO LETTER MO + // U+0EC3: "ໃ" LAO VOWEL SIGN AY + // U+0E9D: "ຝ" LAO LETTER FO TAM + "\u0E9C", "\u0E9B", "\u0EC1", "\u0EAD", "\u0EB6", "\u0EB7", "\u0E97", "\u0EA1", + "\u0EC3", "\u0E9D") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0ED1: "໑" LAO DIGIT ONE + // U+0ED2: "໒" LAO DIGIT TWO + // U+0ED3: "໓" LAO DIGIT THREE + // U+0ED4: "໔" LAO DIGIT FOUR + // U+0ECC: "໌" LAO CANCELLATION MARK + // U+0EBC: "ຼ" LAO SEMIVOWEL SIGN LO + // U+0ED5: "໕" LAO DIGIT FIVE + // U+0ED6: "໖" LAO DIGIT SIX + // U+0ED7: "໗" LAO DIGIT SEVEN + // U+0ED8: "໘" LAO DIGIT EIGHT + // U+0ED9: "໙" LAO DIGIT NINE + // U+0ECD/U+0EC8: "ໍ່" LAO NIGGAHITA/LAO TONE MAI EK + "\u0ED1", "\u0ED2", "\u0ED3", "\u0ED4", "\u0ECC", "\u0EBC", "\u0ED5", "\u0ED6", + "\u0ED7", "\u0ED8", "\u0ED9", "\u0ECD\u0EC8") + .setKeysOfRow(2, + // U+0EBB/U+0EC9: "" LAO VOWEL SIGN MAI KON/LAO TONE MAI THO + // U+0ED0: "໐" LAO DIGIT ZERO + // U+0EB3/U+0EC9: "ຳ້" LAO VOWEL SIGN AM/LAO TONE MAI THO + // U+0EB4/U+0EC9: "ິ້" LAO VOWEL SIGN I/LAO TONE MAI THO + // U+0EB5/U+0EC9: "ີ້" LAO VOWEL SIGN II/LAO TONE MAI THO + // U+0EA3: "ຣ" LAO LETTER LO LING + // U+0EDC: "ໜ" LAO HO NO + // U+0EBD: "ຽ" LAO SEMIVOWEL SIGN NYO + // U+0EAB/U+0EBC: "" LAO LETTER HO SUNG/LAO SEMIVOWEL SIGN LO + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + "\u0EBB\u0EC9", "\u0ED0", "\u0EB3\u0EC9", "_", "+", "\u0EB4\u0EC9", + "\u0EB5\u0EC9", "\u0EA3", "\u0EDC", "\u0EBD", "\u0EAB\u0EBC", "\u201D") + .setKeysOfRow(3, + // U+0EB1/U+0EC9: "ັ້" LAO VOWEL SIGN MAI KAN/LAO TONE MAI THO + // U+0ECA: "໊" LAO TONE MAI TI + // U+0ECB: "໋" LAO TONE MAI CATAWA + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + "\u0EB1\u0EC9", ";", ".", ",", ":", "\u0ECA", "\u0ECB", "!", "?", "%", "=", + "\u201C") + .setKeysOfRow(4, + // U+20AD: "₭" KIP SIGN + // U+0EAF: "ຯ" LAO ELLIPSIS + // U+0EB6/U+0EC9: "ຶ້" LAO VOWEL SIGN Y/LAO TONE MAI THO + // U+0EB7/U+0EC9: "ື້" LAO VOWEL SIGN YY/LAO TONE MAI THO + // U+0EC6: "ໆ" LAO KO LA + // U+0EDD: "ໝ" LAO HO MO + "\u20AD", "(", "\u0EAF", "@", "\u0EB6\u0EC9", "\u0EB7\u0EC9", "\u0EC6", + "\u0EDD", "$", ")") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java new file mode 100644 index 000000000..4123a22ef --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The base class of keyboard layout. + */ +public abstract class LayoutBase extends AbstractLayoutBase { + + /** + * This class is used to customize common keyboard layout to language specific layout. + */ + public static class LayoutCustomizer { + private final Locale mLocale; + + // Empty keys definition to remove keys by adding this. + protected static final ExpectedKey[] EMPTY_KEYS = joinKeys(); + + public LayoutCustomizer(final Locale locale) { + mLocale = locale; + } + + public final Locale getLocale() { + return mLocale; + } + + /** + * Set accented letters to common layout. + * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard + * layout. + * @return the {@link ExpectedKeyboardBuilder} object that contains accented letters as + * "more keys". + */ + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder; + } + + /** + * Get the function key to switch to alphabet layout. + * @return the {@link ExpectedKey} of the alphabet key. + */ + public ExpectedKey getAlphabetKey() { return ALPHABET_KEY; } + + /** + * Get the function key to switch to symbols layout. + * @return the {@link ExpectedKey} of the symbols key. + */ + public ExpectedKey getSymbolsKey() { return SYMBOLS_KEY; } + + /** + * Get the function key to switch to symbols shift layout. + * @param isPhone true if requesting phone's key. + * @return the {@link ExpectedKey} of the symbols shift key. + */ + public ExpectedKey getSymbolsShiftKey(boolean isPhone) { + return isPhone ? SYMBOLS_SHIFT_KEY : TABLET_SYMBOLS_SHIFT_KEY; + } + + /** + * Get the function key to switch from symbols shift to symbols layout. + * @return the {@link ExpectedKey} of the back to symbols key. + */ + public ExpectedKey getBackToSymbolsKey() { return BACK_TO_SYMBOLS_KEY; } + + /** + * Get the currency key. + * @return the {@link ExpectedKey} of the currency key. + */ + public ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_DOLLAR; } + + /** + * Get other currencies keys. + * @return the array of {@link ExpectedKey} that represents other currency keys. + */ + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_THAN_DOLLAR; + } + + /** + * Get "more keys" of double quotation mark. + * @return the array of {@link ExpectedKey} of more double quotation marks in natural order. + */ + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_9LR; } + + /** + * Get "more keys" of single quotation mark. + * @return the array of {@link ExpectedKey} of more single quotation marks in natural order. + */ + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_9LR; } + + /** + * Get double angle quotation marks in natural order. + * @return the array of {@link ExpectedKey} of double angle quotation marks in natural + * order. + */ + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_LR; } + + /** + * Get single angle quotation marks in natural order. + * @return the array of {@link ExpectedKey} of single angle quotation marks in natural + * order. + */ + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_LR; } + + /** + * Get the left shift keys. + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that should be placed at left edge of the + * keyboard. + */ + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return joinKeys(SHIFT_KEY); + } + + /** + * Get the right shift keys. + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that should be placed at right edge of the + * keyboard. + */ + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : joinKeys(EXCLAMATION_AND_QUESTION_MARKS, SHIFT_KEY); + } + + /** + * Get the space keys. + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that should be placed at the center of the + * keyboard. + */ + public ExpectedKey[] getSpaceKeys(final boolean isPhone) { + return joinKeys(SPACE_KEY); + } + + /** + * Get the keys left to the spacebar. + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that should be placed at left of the spacebar. + */ + public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { + return isPhone ? joinKeys(key(",", SETTINGS_KEY)) : joinKeys("/"); + } + + /** + * Get the keys right to the spacebar. + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that should be placed at right of the spacebar. + */ + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone)); + return isPhone ? joinKeys(periodKey) : joinKeys(",", periodKey); + } + + /** + * Get "more keys" for the punctuation key (usually the period key). + * @param isPhone true if requesting phone's keys. + * @return the array of {@link ExpectedKey} that are "more keys" of the punctuation key. + */ + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? PHONE_PUNCTUATION_MORE_KEYS : TABLET_PUNCTUATION_MORE_KEYS; + } + } + + /** + * The layout customize class for countries that use Euro. + */ + public static class EuroCustomizer extends LayoutCustomizer { + public EuroCustomizer(final Locale locale) { + super(locale); + } + + @Override + public final ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_EURO; } + + @Override + public final ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_THAN_EURO; + } + } + + private final LayoutCustomizer mCustomizer; + private final Symbols mSymbols; + private final SymbolsShifted mSymbolsShifted; + + LayoutBase(final LayoutCustomizer customizer, final Class<? extends Symbols> symbolsClass, + final Class<? extends SymbolsShifted> symbolsShiftedClass) { + mCustomizer = customizer; + try { + mSymbols = symbolsClass.getDeclaredConstructor(LayoutCustomizer.class) + .newInstance(customizer); + mSymbolsShifted = symbolsShiftedClass.getDeclaredConstructor(LayoutCustomizer.class) + .newInstance(customizer); + } catch (final Exception e) { + throw new RuntimeException("Unknown Symbols/SymbolsShifted class", e); + } + } + + /** + * The layout name. + * @return the name of this layout. + */ + public abstract String getName(); + + /** + * The locale of this layout. + * @return the locale of this layout. + */ + public final Locale getLocale() { return mCustomizer.getLocale(); } + + /** + * The layout customizer for this layout. + * @return the layout customizer; + */ + public final LayoutCustomizer getCustomizer() { return mCustomizer; } + + // Icon id. + private static final int ICON_SHIFT = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_SHIFT_KEY); + private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_SHIFT_KEY_SHIFTED); + private static final int ICON_ZWNJ = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_ZWNJ_KEY); + private static final int ICON_ZWJ = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_ZWJ_KEY); + + // Functional key. + static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK); + static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT, + Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY); + static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT, + Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY); + static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL); + static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL); + static final ExpectedKey BACK_TO_SYMBOLS_KEY = key("?123", Constants.CODE_SHIFT); + static final ExpectedKey SYMBOLS_SHIFT_KEY = key("= \\ <", Constants.CODE_SHIFT); + static final ExpectedKey TABLET_SYMBOLS_SHIFT_KEY = key("~ [ <", Constants.CODE_SHIFT); + + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + static final ExpectedKey[] EXCLAMATION_AND_QUESTION_MARKS = joinKeys( + key("!", moreKey("\u00A1")), key("?", moreKey("\u00BF"))); + // U+200C: ZERO WIDTH NON-JOINER + // U+200D: ZERO WIDTH JOINER + static final ExpectedKey ZWNJ_KEY = key(ICON_ZWNJ, "\u200C"); + static final ExpectedKey ZWJ_KEY = key(ICON_ZWJ, "\u200D"); + + // Punctuation more keys for phone form factor. + public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "?", "!", "#", ")", "(", "/", ";", + "'", "@", ":", "-", "\"", "+", "%", "&"); + // Punctuation more keys for tablet form factor. + public static final ExpectedKey[] TABLET_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "'", "#", ")", "(", "/", ";", + "@", ":", "-", "\"", "+", "%", "&"); + + /** + * Helper method to create alphabet layout adding special function keys. + * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard + * layout + * @param isPhone true if requesting phone's layout. + * @return the {@link ExpectedKeyboardBuilder} object that is customized and have special keys. + */ + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(4, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(4, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(3, DELETE_KEY) + .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(2, ENTER_KEY) + .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(4, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(3, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(3, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + /** + * Get common alphabet layout. This layout doesn't contain any special keys. + * @param isPhone true if requesting phone's layout. + * @return the common alphabet keyboard layout. + */ + abstract ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone); + + /** + * Get common alphabet shifted layout. This layout doesn't contain any special keys. + * @param isPhone true if requesting phone's layout. + * @param elementId the element id of the requesting shifted mode. + * @return the common alphabet shifted keyboard layout. + */ + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( + getCommonAlphabetLayout(isPhone)); + getCustomizer().setAccentedLetters(builder); + builder.toUpperCase(getLocale()); + return builder.build(); + } + + /** + * Get the complete expected keyboard layout. + * @param isPhone true if requesting phone's layout. + * @param elementId the element id of the requesting keyboard mode. + * @return + */ + public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_SYMBOLS) { + return mSymbols.getLayout(isPhone); + } + if (elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { + return mSymbolsShifted.getLayout(isPhone); + } + final ExpectedKeyboardBuilder builder; + if (elementId == KeyboardId.ELEMENT_ALPHABET) { + builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone)); + getCustomizer().setAccentedLetters(builder); + } else { + final ExpectedKey[][] commonLayout = getCommonAlphabetShiftLayout(isPhone, elementId); + if (commonLayout == null) { + return null; + } + builder = new ExpectedKeyboardBuilder(commonLayout); + } + convertCommonLayoutToKeyboard(builder, isPhone); + if (elementId != KeyboardId.ELEMENT_ALPHABET) { + builder.replaceKeysOfAll(SHIFT_KEY, SHIFTED_SHIFT_KEY); + } + return builder.build(); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Mongolian.java b/tests/src/com/android/inputmethod/keyboard/layout/Mongolian.java new file mode 100644 index 000000000..3c6c05841 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Mongolian.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +public final class Mongolian extends LayoutBase { + private static final String LAYOUT_NAME = "mongolian"; + + public Mongolian(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class MongolianMNCustomizer extends EastSlavicCustomizer { + public MongolianMNCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_TUGRIK; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + // U+20AE: "₮" TUGRIK SIGN + private static final ExpectedKey CURRENCY_TUGRIK = key("\u20AE", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0444: "ф" CYRILLIC SMALL LETTER EF + key("\u0444", moreKey("1")), + // U+0446: "ц" CYRILLIC SMALL LETTER TSE + key("\u0446", moreKey("2")), + // U+0443: "у" CYRILLIC SMALL LETTER U + key("\u0443", moreKey("3")), + // U+0436: "ж" CYRILLIC SMALL LETTER ZHE + key("\u0436", moreKey("4")), + // U+044D: "э" CYRILLIC SMALL LETTER E + key("\u044D", moreKey("5")), + // U+043D: "н" CYRILLIC SMALL LETTER EN + key("\u043D", moreKey("6")), + // U+0433: "г" CYRILLIC SMALL LETTER GHE + key("\u0433", moreKey("7")), + // U+0448: "ш" CYRILLIC SMALL LETTER SHA + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + key("\u0448", joinMoreKeys("8", "\u0449")), + // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U + key("\u04AF", moreKey("9")), + // U+0437: "з" CYRILLIC SMALL LETTER ZE + key("\u0437", moreKey("0")), + // U+043A: "к" CYRILLIC SMALL LETTER KA + "\u043A") + .setKeysOfRow(2, + // U+0439: "й" CYRILLIC SMALL LETTER SHORT I + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + // U+0431: "б" CYRILLIC SMALL LETTER BE + // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+0445: "х" CYRILLIC SMALL LETTER HA + // U+0440: "р" CYRILLIC SMALL LETTER ER + // U+043E: "о" CYRILLIC SMALL LETTER O + // U+043B: "л" CYRILLIC SMALL LETTER EL + // U+0434: "д" CYRILLIC SMALL LETTER DE + // U+043F: "п" CYRILLIC SMALL LETTER PE + "\u0439", "\u044B", "\u0431", "\u04E9", "\u0430", "\u0445", "\u0440", "\u043E", + "\u043B", "\u0434", "\u043F") + .setKeysOfRow(3, + // U+044F: "я" CYRILLIC SMALL LETTER YA + // U+0447: "ч" CYRILLIC SMALL LETTER CHE + "\u044F", "\u0447", + // U+0451: "ё" CYRILLIC SMALL LETTER IO + // U+0435: "е" CYRILLIC SMALL LETTER IE + key("\u0451", moreKey("\u0435")), + // U+0441: "с" CYRILLIC SMALL LETTER ES + // U+043C: "м" CYRILLIC SMALL LETTER EM + // U+0438: "и" CYRILLIC SMALL LETTER I + // U+0442: "т" CYRILLIC SMALL LETTER TE + "\u0441", "\u043C", "\u0438", "\u0442", + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + key("\u044C", moreKey("\u044A")), + // U+0432: "в" CYRILLIC SMALL LETTER VE + // U+044E: "ю" CYRILLIC SMALL LETTER YU + key("\u0432", moreKey("\u044E"))) + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java new file mode 100644 index 000000000..2d1c901b9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Myanmar alphabet keyboard. + */ +public final class Myanmar extends LayoutBase { + private static final String LAYOUT_NAME = "myanmar"; + + public Myanmar(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class MyanmarCustomizer extends LayoutCustomizer { + public MyanmarCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return MYANMAR_ALPHABET_KEY; } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS; + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + // U+104B: "။" MYANMAR SIGN SECTION + // U+104A: "၊" MYANMAR SIGN LITTLE SECTION + final ExpectedKey periodKey = key("\u104B", getPunctuationMoreKeys(isPhone)); + final ExpectedKey commaKey = key("\u104A", moreKey(",")); + return isPhone ? joinKeys(periodKey) : joinKeys(commaKey, periodKey); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? MYANMAR_PHONE_PUNCTUATION_MORE_KEYS + : MYANMAR_TABLET_PUNCTUATION_MORE_KEYS; + } + + // U+1000: "က" MYANMAR LETTER KA + // U+1001: "ခ" MYANMAR LETTER KHA + // U+1002: "ဂ" MYANMAR LETTER GA + private static final ExpectedKey MYANMAR_ALPHABET_KEY = key( + "\u1000\u1001\u1002", Constants.CODE_SWITCH_ALPHA_SYMBOL); + + // U+104A: "၊" MYANMAR SIGN LITTLE SECTION + // Punctuation more keys for phone form factor. + private static final ExpectedKey[] MYANMAR_PHONE_PUNCTUATION_MORE_KEYS = joinKeys( + "\u104A", ".", "?", "!", "#", ")", "(", "/", ";", + "...", "'", "@", ":", "-", "\"", "+", "%", "&"); + // Punctuation more keys for tablet form factor. + private static final ExpectedKey[] MYANMAR_TABLET_PUNCTUATION_MORE_KEYS = joinKeys( + ".", "'", "#", ")", "(", "/", ";", "@", + "...", ":", "-", "\"", "+", "%", "&"); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + @Override + public ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, + final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(4, DELETE_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(5, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+1041: "၁" MYANMAR DIGIT ONE + key("\u1041", moreKey("1")), + // U+1042: "၂" MYANMAR DIGIT TWO + key("\u1042", moreKey("2")), + // U+1043: "၃" MYANMAR DIGIT THREE + key("\u1043", moreKey("3")), + // U+1044: "၄" MYANMAR DIGIT FOUR + key("\u1044", moreKey("4")), + // U+1045: "၅" MYANMAR DIGIT FIVE + key("\u1045", moreKey("5")), + // U+1046: "၆" MYANMAR DIGIT SIX + key("\u1046", moreKey("6")), + // U+1047: "၇" MYANMAR DIGIT SEVEN + key("\u1047", moreKey("7")), + // U+1048: "၈" MYANMAR DIGIT EIGHT + key("\u1048", moreKey("8")), + // U+1049: "၉" MYANMAR DIGIT NINE + key("\u1049", moreKey("9")), + // U+1040: "၀" MYANMAR DIGIT ZERO + key("\u1040", moreKey("0"))) + .setKeysOfRow(2, + // U+1006: "ဆ" MYANMAR LETTER CHA + // U+1010: "တ" MYANMAR LETTER TA + // U+1014: "န" MYANMAR LETTER NA + // U+1019: "မ" MYANMAR LETTER MA + // U+1021: "အ" MYANMAR LETTER A + // U+1015: "ပ" MYANMAR LETTER PA + // U+1000: "က" MYANMAR LETTER KA + // U+1004: "င" MYANMAR LETTER NGA + // U+101E: "သ" MYANMAR LETTER SA + // U+1005: "စ" MYANMAR LETTER CA + "\u1006", "\u1010", "\u1014", "\u1019", "\u1021", "\u1015", "\u1000", "\u1004", + "\u101E", "\u1005") + .setKeysOfRow(3, + // U+1031: "ေ" MYANMAR VOWEL SIGN E + // U+103B: "ျ" MYANMAR CONSONANT SIGN MEDIAL YA + // U+103C: "ြ" MYANMAR CONSONANT SIGN MEDIAL RA + "\u1031", "\u103B", "\u103C", + // U+103D: "ွ" MYANMAR CONSONANT SIGN MEDIAL WA + // U+103E: "ှ" MYANMAR CONSONANT SIGN MEDIAL HA + // U+103D/U+103E: + // "ွှ" MYANMAR CONSONANT SIGN MEDIAL WA/MYANMAR CONSONANT SIGN MEDIAL HA + key("\u103D", joinMoreKeys("\u103E", "\u103D\u103E")), + // U+102D: "ိ" MYANMAR VOWEL SIGN I + // U+102E: "ီ" MYANMAR VOWEL SIGN II + key("\u102D", moreKey("\u102E")), + // U+102F: "ု" MYANMAR VOWEL SIGN U + // U+1030: "ူ" MYANMAR VOWEL SIGN UU + key("\u102F", moreKey("\u1030")), + // U+102C: "ာ" MYANMAR VOWEL SIGN AA + "\u102C", + // U+103A: "်" MYANMAR SIGN ASAT + // U+1032: "ဲ" MYANMAR VOWEL SIGN AI + key("\u103A", moreKey("\u1032")), + // U+1037: "့" MYANMAR SIGN DOT BELOW + // U+1036: "ံ" MYANMAR SIGN ANUSVARA + key("\u1037", moreKey("\u1036")), + // U+1038: "း" MYANMAR SIGN VISARGA + "\u1038") + .setKeysOfRow(4, + // U+1016: "ဖ" MYANMAR LETTER PHA + // U+1011: "ထ" MYANMAR LETTER THA + // U+1001: "ခ" MYANMAR LETTER KHA + // U+101C: "လ" MYANMAR LETTER LA + // U+1018: "ဘ" MYANMAR LETTER BHA + "\u1016", "\u1011", "\u1001", "\u101C", "\u1018", + // U+100A: "ည" MYANMAR LETTER NNYA + // U+1009: "ဉ" MYANMAR LETTER NYA + key("\u100A", moreKey("\u1009")), + // U+101B: "ရ" MYANMAR LETTER RA + // U+101D: "ဝ" MYANMAR LETTER WA + "\u101B", "\u101D") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+1027: "ဧ" MYANMAR LETTER E + // U+104F: "၏" MYANMAR SYMBOL GENITIVE + // U+1024: "ဤ" MYANMAR LETTER II + // U+1023: "ဣ" MYANMAR LETTER I + // U+104E: "၎" MYANMAR SYMBOL AFOREMENTIONED + // U+1000/U+103B/U+1015/U+103A: "ကျပ်" MYANMAR LETTER KA + // /MYANMAR CONSONANT SIGN MEDIAL YA/MYANMAR LETTER PA/MYANMAR SIGN ASAT + // U+1029: "ဩ" MYANMAR LETTER O + // U+102A: "ဪ" MYANMAR LETTER AU + // U+104D: "၍" MYANMAR SYMBOL COMPLETED + // U+104C: "၌" MYANMAR SYMBOL LOCATIVE + "\u1027", "\u104F", "\u1024", "\u1023", "\u104E", "\u1000\u103B\u1015\u103A", + "\u1029", "\u102A", "\u104D", "\u104C") + .setKeysOfRow(2, + // U+1017: "ဗ" MYANMAR LETTER BA + // U+1012: "ဒ" MYANMAR LETTER DA + // U+1013: "ဓ" MYANMAR LETTER DHA + // U+1003: "ဃ" MYANMAR LETTER GHA + // U+100E: "ဎ" MYANMAR LETTER DDHA + // U+103F: "ဿ" MYANMAR LETTER GREAT SA + // U+100F: "ဏ" MYANMAR LETTER NNA + // U+1008: "ဈ" MYANMAR LETTER JHA + // U+1007: "ဇ" MYANMAR LETTER JA + // U+1002: "ဂ" MYANMAR LETTER GA + "\u1017", "\u1012", "\u1013", "\u1003", "\u100E", "\u103F", "\u100F", "\u1008", + "\u1007", "\u1002") + .setKeysOfRow(3, + // U+101A: "ယ" MYANMAR LETTER YA + // U+1039: "္" MYANMAR SIGN VIRAMA + // U+1004/U+103A/U+1039: "င်္င" MYANMAR LETTER NGA + // /MYANMAR SIGN ASAT/MYANMAR SIGN VIRAMA + // U+103E: "ှ" MYANMAR CONSONANT SIGN MEDIAL HA + // U+102E: "ီ" MYANMAR VOWEL SIGN II + // U+1030: "ူ" MYANMAR VOWEL SIGN UU + // U+102B: "ါ" MYANMAR VOWEL SIGN TALL AA + // U+1032: "ဲ" MYANMAR VOWEL SIGN AI + // U+1036: "ံ" MYANMAR SIGN ANUSVARA + // U+101F: "ဟ" MYANMAR LETTER HA + "\u101A", "\u1039", "\u1004\u103A\u1039", "\u103E", "\u102E", "\u1030", + "\u102B", "\u1032", "\u1036", "\u101F") + .setKeysOfRow(4, + // U+1025: "ဥ" MYANMAR LETTER U + // U+1026: "ဦ" MYANMAR LETTER UU + // U+100C: "ဌ" MYANMAR LETTER TTHA + // U+100B: "ဋ" MYANMAR LETTER TTA + // U+100D: "ဍ" MYANMAR LETTER DDA + // U+1020: "ဠ" MYANMAR LETTER LLA + // U+100B/U+1039/U+100C: "ဋ္ဌ" MYANMAR LETTER TTA + // /MYANMAR SIGN VIRAMA/MYANMAR LETTER TTHA + "\u1025", "\u1026", "\u100C", "\u100B", "\u100D", "\u1020", + "\u100B\u1039\u100C", + // U+100F/U+1039/U+100D: "ဏ္ဍ" MYANMAR LETTER NNA + // /MYANMAR SIGN VIRAMA/MYANMAR LETTER DDA + // U+100F/U+1039/U+100C: "ဏ္ဌ" MYANMAR LETTER NNA + // /MYANMAR SIGN VIRAMA/MYANMAR LETTER TTHA + key("\u100F\u1039\u100D", moreKey("\u100F\u1039\u100C"))) + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java new file mode 100644 index 000000000..7048dbb73 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2014 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.layout; + +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.*; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.Hindi.HindiCustomizer; +import com.android.inputmethod.keyboard.layout.Hindi.HindiSymbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * The nepali_romanized layout + */ +public final class NepaliRomanized extends LayoutBase { + private static final String LAYOUT_NAME = "nepali_romanized"; + + public NepaliRomanized(final LayoutCustomizer customizer) { + super(customizer, HindiSymbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class NepaliRomanizedCustomizer extends HindiCustomizer { + public NepaliRomanizedCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_NEPALI; } + + @Override + public ExpectedKey[] getSpaceKeys(final boolean isPhone) { + return joinKeys(SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY)); + } + + // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN + private static final ExpectedKey CURRENCY_NEPALI = key("\u0930\u0941\u002E", + Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.POUND_SIGN, + Symbols.YEN_SIGN, Symbols.PESO_SIGN); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { return ALPHABET_COMMON; } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + return ALPHABET_SHIFTED_COMMON; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+091F: "ट" DEVANAGARI LETTER TTA + // U+0967: "१" DEVANAGARI DIGIT ONE + // U+093C: "़" DEVANAGARI SIGN NUKTA + key("\u091F", joinMoreKeys("\u0967", "1", key(SIGN_NUKTA, "\u093C"))), + // U+094C: "ौ" DEVANAGARI VOWEL SIGN AU + // U+0968: "२" DEVANAGARI DIGIT TWO + key(VOWEL_SIGN_AU, "\u094C", joinMoreKeys("\u0968", "2")), + // U+0947: "े" DEVANAGARI VOWEL SIGN E + // U+0969: "३" DEVANAGARI DIGIT THREE + key(VOWEL_SIGN_E, "\u0947", joinMoreKeys("\u0969", "3")), + // U+0930: "र" DEVANAGARI LETTER RA + // U+096A: "४" DEVANAGARI DIGIT FOUR + key("\u0930", joinMoreKeys("\u096A", "4")), + // U+0924: "त" DEVANAGARI LETTER TA + // U+096B: "५" DEVANAGARI DIGIT FIVE + key("\u0924", joinMoreKeys("\u096B", "5")), + // U+092F: "य" DEVANAGARI LETTER YA + // U+096C: "६" DEVANAGARI DIGIT SIX + key("\u092F", joinMoreKeys("\u096C", "6")), + // U+0941: "ु" DEVANAGARI VOWEL SIGN U + // U+096D: "७" DEVANAGARI DIGIT SEVEN + key(VOWEL_SIGN_U, "\u0941", joinMoreKeys("\u096D", "7")), + // U+093F: "ि" DEVANAGARI VOWEL SIGN I + // U+096E: "८" DEVANAGARI DIGIT EIGHT + key(VOWEL_SIGN_I, "\u093F", joinMoreKeys("\u096E", "8")), + // U+094B: "ो" DEVANAGARI VOWEL SIGN O + // U+096F: "९" DEVANAGARI DIGIT NINE + key(VOWEL_SIGN_O, "\u094B", joinMoreKeys("\u096F", "9")), + // U+092A: "प" DEVANAGARI LETTER PA + // U+0966: "०" DEVANAGARI DIGIT ZERO + key("\u092A", joinMoreKeys("\u0966", "0")), + // U+0907: "इ" DEVANAGARI LETTER I + "\u0907") + .setKeysOfRow(2, + // U+093E: "ा" DEVANAGARI VOWEL SIGN AA + key(VOWEL_SIGN_AA, "\u093E"), + // U+0938: "स" DEVANAGARI LETTER SA + // U+0926: "द" DEVANAGARI LETTER DA + // U+0909: "उ" DEVANAGARI LETTER U + // U+0917: "ग" DEVANAGARI LETTER GA + // U+0939: "ह" DEVANAGARI LETTER HA + // U+091C: "ज" DEVANAGARI LETTER JA + // U+0915: "क" DEVANAGARI LETTER KA + // U+0932: "ल" DEVANAGARI LETTER LA + // U+090F: "ए" DEVANAGARI LETTER E + // U+0950: "ॐ" DEVANAGARI OM + "\u0938", "\u0926", "\u0909", "\u0917", "\u0939", "\u091C", "\u0915", "\u0932", + "\u090F", "\u0950") + .setKeysOfRow(3, + // U+0937: "ष" DEVANAGARI LETTER SSA + // U+0921: "ड" DEVANAGARI LETTER DDA + // U+091A: "च" DEVANAGARI LETTER CA + // U+0935: "व" DEVANAGARI LETTER VA + // U+092C: "ब" DEVANAGARI LETTER BHA + // U+0928: "न" DEVANAGARI LETTER NA + // U+092E: "म" DEVANAGARI LETTER MA + "\u0937", "\u0921", "\u091A", "\u0935", "\u092C", "\u0928", "\u092E", + // U+0964: "।" DEVANAGARI DANDA + // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA + key("\u0964", moreKey("\u093D")), + // U+094D: "्" DEVANAGARI SIGN VIRAMA + key(SIGN_VIRAMA, "\u094D")) + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0920: "ठ" DEVANAGARI LETTER TTHA + // U+0914: "औ" DEVANAGARI LETTER AU + "\u0920", "\u0914", + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + key(VOWEL_SIGN_AI, "\u0948"), + // U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R + key(VOWEL_SIGN_VOCALIC_R, "\u0943"), + // U+0925: "थ" DEVANAGARI LETTER THA + // U+091E: "ञ" DEVANAGARI LETTER NYA + "\u0925", "\u091E", + // U+0942: "ू" DEVANAGARI VOWEL SIGN UU + key(VOWEL_SIGN_UU, "\u0942"), + // U+0940: "ी" DEVANAGARI VOWEL SIGN II + key(VOWEL_SIGN_II, "\u0940"), + // U+0913: "ओ" DEVANAGARI LETTER O + // U+092B: "फ" DEVANAGARI LETTER PHA + // U+0908: "ई" DEVANAGARI LETTER II + "\u0913", "\u092B", "\u0908") + .setKeysOfRow(2, + // U+0906: "आ" DEVANAGARI LETTER AA + // U+0936: "श" DEVANAGARI LETTER SHA + // U+0927: "ध" DEVANAGARI LETTER DHA + // U+090A: "ऊ" DEVANAGARI LETTER UU + // U+0918: "घ" DEVANAGARI LETTER GHA + // U+0905: "अ" DEVANAGARI LETTER A + // U+091D: "झ" DEVANAGARI LETTER JHA + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0965: "॥" DEVANAGARI DOUBLE DANDA + // U+0910: "ऐ" DEVANAGARI LETTER AI + // U+0903: "ः" DEVANAGARI SIGN VISARGA + "\u0906", "\u0936", "\u0927", "\u090A", "\u0918", "\u0905", "\u091D", "\u0916", + "\u0965", "\u0910", key(SIGN_VISARGA, "\u0903")) + .setKeysOfRow(3, + // U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + // U+0922: "ढ" DEVANAGARI LETTER DDHA + // U+091B: "छ" DEVANAGARI LETTER CHA + "\u090B", "\u0922", "\u091B", + // U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + key(SIGN_CANDRABINDU, "\u0901"), + // U+092D: "भ" DEVANAGARI LETTER BHA + // U+0923: "ण" DEVANAGARI LETTER NNA + "\u092D", "\u0923", + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + key(SIGN_ANUSVARA, "\u0902"), + // U+0919: "ङ" DEVANAGARI LETTER NGA + "\u0919", + // U+094D: "्" DEVANAGARI SIGN VIRAMA + key(SIGN_VIRAMA, "\u094D")) + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java b/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java new file mode 100644 index 000000000..4d6cdedbf --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/NepaliTraditional.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2014 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.layout; + +import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.*; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.Hindi.HindiSymbols; +import com.android.inputmethod.keyboard.layout.NepaliRomanized.NepaliRomanizedCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * The nepali_traditional keyboard. + */ +public final class NepaliTraditional extends LayoutBase { + private static final String LAYOUT_NAME = "nepali_traditional"; + + public NepaliTraditional(final LayoutCustomizer customizer) { + super(customizer, HindiSymbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class NepaliTraditionalCustomizer extends NepaliRomanizedCustomizer { + public NepaliTraditionalCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { return EMPTY_KEYS; } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + if (isPhone) { + // U+094D: "्" DEVANAGARI SIGN VIRAMA + return joinKeys(key(SIGN_VIRAMA, "\u094D", PHONE_PUNCTUATION_MORE_KEYS)); + } + return super.getKeysRightToSpacebar(isPhone); + } + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + if (isPhone) { + builder.addKeysOnTheRightOfRow(3, + // U+0947: "े" DEVANAGARI VOWEL SIGN E + // U+0903: "ः" DEVANAGARI SIGN VISARGA + // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA + key(VOWEL_SIGN_E, "\u0947", joinMoreKeys( + moreKey(SIGN_VISARGA, "\u0903"), "\u093D")), + // U+0964: "।" DEVANAGARI DANDA + "\u0964", + // U+0930: "र" DEVANAGARI LETTER RA + // U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U + key("\u0930", moreKey("\u0930\u0941"))); + } else { + builder.addKeysOnTheRightOfRow(3, + // U+0903: "ः" DEVANAGARI SIGN VISARGA + // U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA + key(SIGN_VISARGA, "\u0903", moreKey("\u093D")), + // U+0947: "े" DEVANAGARI VOWEL SIGN E + key(VOWEL_SIGN_E, "\u0947"), + // U+0964: "।" DEVANAGARI DANDA + "\u0964", + // U+0930: "र" DEVANAGARI LETTER RA + key("\u0930", moreKey("!")), + // U+094D: "्" DEVANAGARI SIGN VIRAMA + key(SIGN_VIRAMA, "\u094D", moreKey("?"))); + } + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( + ALPHABET_SHIFTED_COMMON); + if (isPhone) { + builder.addKeysOnTheRightOfRow(3, + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + key(SIGN_ANUSVARA, "\u0902"), + // U+0919: "ङ" DEVANAGARI LETTER NGA + "\u0919", + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + // U+0936/U+094D/U+0930: + // "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key(VOWEL_SIGN_AI, "\u0948", moreKey("\u0936\u094D\u0930"))); + } else { + builder.addKeysOnTheRightOfRow(3, + // U+0902: "ं" DEVANAGARI SIGN ANUSVARA + key(SIGN_ANUSVARA, "\u0902"), + // U+0919: "ङ" DEVANAGARI LETTER NGA + "\u0919", + // U+0948: "ै" DEVANAGARI VOWEL SIGN AI + // U+0936/U+094D/U+0930: + // "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA + key(VOWEL_SIGN_AI, "\u0948", moreKey("\u0936\u094D\u0930")), + // U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U + key("\u0930\u0941", moreKey("!")), + "?"); + } + return builder.build(); + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+091F: "ट" DEVANAGARI LETTER TTA + // U+0967: "१" DEVANAGARI DIGIT ONE + key("\u091F", joinMoreKeys("\u0967", "1")), + // U+0927: "ध" DEVANAGARI LETTER DHA + // U+0968: "२" DEVANAGARI DIGIT TWO + key("\u0927", joinMoreKeys("\u0968", "2")), + // U+092D: "भ" DEVANAGARI LETTER BHA + // U+0969: "३" DEVANAGARI DIGIT THREE + key("\u092D", joinMoreKeys("\u0969", "3")), + // U+091A: "च" DEVANAGARI LETTER CA + // U+096A: "४" DEVANAGARI DIGIT FOUR + key("\u091A", joinMoreKeys("\u096A", "4")), + // U+0924: "त" DEVANAGARI LETTER TA + // U+096B: "५" DEVANAGARI DIGIT FIVE + key("\u0924", joinMoreKeys("\u096B", "5")), + // U+0925: "थ" DEVANAGARI LETTER THA + // U+096C: "६" DEVANAGARI DIGIT SIX + key("\u0925", joinMoreKeys("\u096C", "6")), + // U+0917: "ग" DEVANAGARI LETTER G + // U+096D: "७" DEVANAGARI DIGIT SEVEN + key("\u0917", joinMoreKeys("\u096D", "7")), + // U+0937: "ष" DEVANAGARI LETTER SSA + // U+096E: "८" DEVANAGARI DIGIT EIGHT + key("\u0937", joinMoreKeys("\u096E", "8")), + // U+092F: "य" DEVANAGARI LETTER YA + // U+096F: "९" DEVANAGARI DIGIT NINE + key("\u092F", joinMoreKeys("\u096F", "9")), + // U+0909: "उ" DEVANAGARI LETTER U + // U+0966: "०" DEVANAGARI DIGIT ZERO + key("\u0909", joinMoreKeys("\u0966", "0")), + // U+0907: "इ" DEVANAGARI LETTER I + // U+0914: "औ" DEVANAGARI LETTER AU + key("\u0907", moreKey("\u0914"))) + .setKeysOfRow(2, + // U+092C: "ब" DEVANAGARI LETTER BA + // U+0915: "क" DEVANAGARI LETTER KA + // U+092E: "म" DEVANAGARI LETTER MA + "\u092C", "\u0915", "\u092E", + // U+093E: "ा" DEVANAGARI VOWEL SIGN AA + key(VOWEL_SIGN_AA, "\u093E"), + // U+0928: "न" DEVANAGARI LETTER NA + // U+091C: "ज" DEVANAGARI LETTER JA + // U+0935: "व" DEVANAGARI LETTER VA + // U+092A: "प" DEVANAGARI LETTER PA + "\u0928", "\u091C", "\u0935", "\u092A", + // U+093F: "ि" DEVANAGARI VOWEL SIGN I + key(VOWEL_SIGN_I, "\u093F"), + // U+0938: "स" DEVANAGARI LETTER SA + "\u0938", + // U+0941: "ु" DEVANAGARI VOWEL SIGN U + key(VOWEL_SIGN_U, "\u0941")) + .setKeysOfRow(3, + // U+0936: "श" DEVANAGARI LETTER SHA + // U+0939: "ह" DEVANAGARI LETTER HA + // U+0905: "अ" DEVANAGARI LETTER A + // U+0916: "ख" DEVANAGARI LETTER KHA + // U+0926: "द" DEVANAGARI LETTER DA + // U+0932: "ल" DEVANAGARI LETTER LA + "\u0936", "\u0939", "\u0905", "\u0916", "\u0926", "\u0932") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0924/U+094D/U+0924: + // "त्त" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TA + // U+091E: "ञ" DEVANAGARI LETTER NYA + // U+091C/U+094D/U+091E: "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN + // VIRAMA/DEVANAGARI LETTER NYA + // U+0965: "॥" DEVANAGARI DOUBLE DANDA + key("\u0924\u094D\u0924", + joinMoreKeys("\u091E", "\u091C\u094D\u091E", "\u0965")), + // U+0921/U+094D/U+0922: + // "ड्ढ" DEVANAGARI LETTER DDA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DDHA + // U+0908: "ई" DEVANAGARI LETTER II + key("\u0921\u094D\u0922", moreKey("\u0908")), + // U+0910: "ऐ" DEVANAGARI LETTER AI + // U+0918: "घ" DEVANAGARI LETTER GHA + key("\u0910", moreKey("\u0918")), + // U+0926/U+094D/U+0935: + // "द्व" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER VA + // U+0926/U+094D/U+0927: + // "द्ध" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DHA + key("\u0926\u094D\u0935", moreKey("\u0926\u094D\u0927")), + // U+091F/U+094D/U+091F: + // "ट्ट" DEVANAGARI LETTER TTA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTA + // U+091B: "छ" DEVANAGARI LETTER CHA + key("\u091F\u094D\u091F", moreKey("\u091B")), + // U+0920/U+094D/U+0920: + // "ठ्ठ" DEVANAGARI LETTER TTHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTHA + // U+091F: "ट" DEVANAGARI LETTER TTA + key("\u0920\u094D\u0920", moreKey("\u091F")), + // U+090A: "ऊ" DEVANAGARI LETTER UU + // U+0920: "ठ" DEVANAGARI LETTER TTHA + key("\u090A", moreKey("\u0920")), + // U+0915/U+094D/U+0937: + // "क्ष" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER SSA + // U+0921: "ड" DEVANAGARI LETTER DDA + key("\u0915\u094D\u0937", moreKey("\u0921")), + // U+0907: "इ" DEVANAGARI LETTER I + // U+0922: "ढ" DEVANAGARI LETTER DDHA + key("\u0907", moreKey("\u0922")), + // U+090F: "ए" DEVANAGARI LETTER E + // U+0923: "ण" DEVANAGARI LETTER NNA + key("\u090F", moreKey("\u0923")), + // U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R + // U+0913: "ओ" DEVANAGARI LETTER O + key(VOWEL_SIGN_VOCALIC_R, "\u0943", moreKey("\u0913"))) + .setKeysOfRow(2, + // U+0906: "आ" DEVANAGARI LETTER AA + // U+0919/U+094D: "ङ्" DEVANAGARI LETTER NGA/DEVANAGARI SIGN VIRAMA + // U+0921/U+094D/U+0921: + // "ड्ड" DEVANAGARI LETTER DDA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DDA + "\u0906", "\u0919\u094D", "\u0921\u094D\u0921", + // U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU + key(SIGN_CANDRABINDU, "\u0901"), + // U+0926/U+094D/U+0926: + // "द्द" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DA + // U+091D: "झ" DEVANAGARI LETTER JHA + "\u0926\u094D\u0926", "\u091D", + // U+094B: "ो" DEVANAGARI VOWEL SIGN O + key(VOWEL_SIGN_O, "\u094B"), + // U+092B: "फ" DEVANAGARI LETTER PHA + "\u092B", + // U+0940: "ी" DEVANAGARI VOWEL SIGN II + key(VOWEL_SIGN_II, "\u0940"), + // U+091F/U+094D/U+0920: + // "ट्ठ" DEVANAGARI LETTER TTA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTHA + "\u091F\u094D\u0920", + // U+0942: "ू" DEVANAGARI VOWEL SIGN UU + key(VOWEL_SIGN_UU, "\u0942")) + .setKeysOfRow(3, + // U+0915/U+094D: "क्" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA + // U+0939/U+094D/U+092E: + // "ह्म" DEVANAGARI LETTER HA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER MA + // U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R + // U+0950: "ॐ" DEVANAGARI OM + "\u0915\u094D", "\u0939\u094D\u092E", "\u090B", "\u0950", + // U+094C: "ौ" DEVANAGARI VOWEL SIGN AU + key(VOWEL_SIGN_AU, "\u094C"), + // U+0926/U+094D/U+092F: + // "द्य" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER YA + "\u0926\u094D\u092F") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Nordic.java b/tests/src/com/android/inputmethod/keyboard/layout/Nordic.java new file mode 100644 index 000000000..c791c404d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Nordic.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +/** + * The Nordic alphabet keyboard. + */ +public final class Nordic extends LayoutBase { + private static final String LAYOUT_NAME = "nordic"; + + public Nordic(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + public static final String ROW1_11 = "ROW1_11"; + public static final String ROW2_10 = "ROW2_10"; + public static final String ROW2_11 = "ROW2_11"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("y", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0")), + ROW1_11) + .setKeysOfRow(2, "a", "s", "d", "f", "g", "h", "j", "k", "l", ROW2_10, ROW2_11) + .setKeysOfRow(3, "z", "x", "c", "v", "b", "n", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java new file mode 100644 index 000000000..9da6dcc44 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * The PC QWERTY alphabet keyboard. + */ +public final class PcQwerty extends LayoutBase { + private static final String LAYOUT_NAME = "pcqwerty"; + + public PcQwerty(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class PcQwertyCustomizer extends LayoutCustomizer { + public PcQwertyCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) { + return joinKeys(SHIFT_KEY); + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return joinKeys(SHIFT_KEY); + } + + @Override + public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) { + return joinKeys(SETTINGS_KEY); + } + + @Override + public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) { + return isPhone ? joinKeys(key(ENTER_KEY, EMOJI_KEY)) : joinKeys(EMOJI_KEY); + } + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + customizer.setAccentedLetters(builder); + builder.replaceKeyOfLabel(ROW1_1, key("`", moreKey("~"))) + .replaceKeyOfLabel(ROW2_11, key("[", moreKey("{"))) + .replaceKeyOfLabel(ROW2_12, key("]", moreKey("}"))) + .replaceKeyOfLabel(ROW2_13, key("\\", moreKey("|"))) + .replaceKeyOfLabel(ROW3_10, key(";", moreKey(":"))) + .replaceKeyOfLabel(ROW3_11, key("'", joinMoreKeys(additionalMoreKey("\""), + customizer.getDoubleQuoteMoreKeys(), + customizer.getSingleQuoteMoreKeys()))) + .setAdditionalMoreKeysPositionOf("'", 4) + .replaceKeyOfLabel(ROW4_8, key(",", moreKey("<"))) + .replaceKeyOfLabel(ROW4_9, key(".", moreKey(">"))) + // U+00BF: "¿" INVERTED QUESTION MARK + .replaceKeyOfLabel(ROW4_10, key("/", joinMoreKeys("?", "\u00BF"))); + if (isPhone) { + // U+221E: "∞" INFINITY + // U+2260: "≠" NOT EQUAL TO + // U+2248: "≈" ALMOST EQUAL TO + builder.replaceKeyOfLabel(ROW1_13, key("=", + joinMoreKeys("\u221E", "\u2260", "\u2248", "+"))); + } else { + // U+221E: "∞" INFINITY + // U+2260: "≠" NOT EQUAL TO + // U+2248: "≈" ALMOST EQUAL TO + builder.replaceKeyOfLabel(ROW1_13, key("=", + joinMoreKeys("+", "\u221E", "\u2260", "\u2248"))); + } + return builder.build(); + } + + @Override + ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) { + final ExpectedKeyboardBuilder builder; + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED + || elementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) { + builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone)); + } else { + builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + final LayoutCustomizer customizer = getCustomizer(); + customizer.setAccentedLetters(builder); + builder.setKeysOfRow(1, + "~", + // U+00A1: "¡" INVERTED EXCLAMATION MARK + key("!", moreKey("\u00A1")), + "@", "#", + customizer.getCurrencyKey(), + // U+2030: "‰" PER MILLE SIGN + key("%", moreKey("\u2030")), + "^", "&", + // U+2020: "†" DAGGER + // U+2021: "‡" DOUBLE DAGGER + // U+2605: "★" BLACK STAR + key("*", joinMoreKeys("\u2020", "\u2021", "\u2605")), + "(", ")", "_", + // U+00B1: "±" PLUS-MINUS SIGN + // U+00D7: "×" MULTIPLICATION SIGN + // U+00F7: "÷" DIVISION SIGN + // U+221A: "√" SQUARE ROOT + key("+", joinMoreKeys("\u00B1", "\u00D7", "\u00F7", "\u221A"))) + .replaceKeyOfLabel(ROW2_11, key("{")) + .replaceKeyOfLabel(ROW2_12, key("}")) + .replaceKeyOfLabel(ROW2_13, key("|")) + .replaceKeyOfLabel(ROW3_10, key(":")) + .replaceKeyOfLabel(ROW3_11, key("\"", joinMoreKeys( + customizer.getDoubleQuoteMoreKeys(), + customizer.getSingleQuoteMoreKeys()))) + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + .replaceKeyOfLabel(ROW4_8, key("<", joinMoreKeys("\u2039", "\u2264", "\u00AB"))) + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + .replaceKeyOfLabel(ROW4_9, key(">", joinMoreKeys("\u203A", "\u2265", "\u00BB"))) + // U+00BF: "¿" INVERTED QUESTION MARK + .replaceKeyOfLabel(ROW4_10, key("?", moreKey("\u00BF"))); + } + builder.toUpperCase(getLocale()); + return builder.build(); + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(3, DELETE_KEY); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheLeftOfRow(2, TAB_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) { + if (elementId == KeyboardId.ELEMENT_SYMBOLS + || elementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { + return null; + } + return super.getLayout(isPhone, elementId); + } + + private static final String ROW1_1 = "ROW1_1"; + private static final String ROW1_13 = "ROW1_13"; + private static final String ROW2_11 = "ROW2_11"; + private static final String ROW2_12 = "ROW2_12"; + private static final String ROW2_13 = "ROW2_13"; + private static final String ROW3_10 = "ROW3_10"; + private static final String ROW3_11 = "ROW3_11"; + private static final String ROW4_8 = "ROW4_8"; + private static final String ROW4_9 = "ROW4_9"; + private static final String ROW4_10 = "ROW4_10"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + ROW1_1, + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + key("1", joinMoreKeys( + "!", "\u00A1", "\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B")), + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + key("2", joinMoreKeys("@", "\u00B2", "\u2154")), + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + key("3", joinMoreKeys("#", "\u00B3", "\u00BE", "\u215C")), + // U+2074: "⁴" SUPERSCRIPT FOUR + key("4", joinMoreKeys("$", "\u2074")), + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + key("5", joinMoreKeys("%", "\u215D")), + key("6", moreKey("^")), + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + key("7", joinMoreKeys("&", "\u215E")), + key("8", moreKey("*")), + key("9", moreKey("(")), + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + key("0", joinMoreKeys(")", "\u207F", "\u2205")), + // U+2013: "–" EN DASH + // U+2014: "—" EM DASH + // U+00B7: "·" MIDDLE DOT + key("-", joinMoreKeys("_", "\u2013", "\u2014", "\u00B7")), + ROW1_13) + .setKeysOfRow(2, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", + ROW2_11, ROW2_12, ROW2_13) + .setKeysOfRow(3, "a", "s", "d", "f", "g", "h", "j", "k", "l", ROW3_10, ROW3_11) + .setKeysOfRow(4, "z", "x", "c", "v", "b", "n", "m", ROW4_8, ROW4_9, ROW4_10) + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java new file mode 100644 index 000000000..d790a1e53 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Qwerty.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +/** + * The QWERTY alphabet keyboard. + */ +public final class Qwerty extends LayoutBase { + private static final String LAYOUT_NAME = "qwerty"; + + public Qwerty(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("y", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0"))) + .setKeysOfRow(2, "a", "s", "d", "f", "g", "h", "j", "k", "l") + .setKeysOfRow(3, "z", "x", "c", "v", "b", "n", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Qwertz.java b/tests/src/com/android/inputmethod/keyboard/layout/Qwertz.java new file mode 100644 index 000000000..26ba6cffb --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Qwertz.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +public final class Qwertz extends LayoutBase { + private static final String LAYOUT_NAME = "qwertz"; + + public Qwertz(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("z", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0"))) + .setKeysOfRow(2, "a", "s", "d", "f", "g", "h", "j", "k", "l") + .setKeysOfRow(3, "y", "x", "c", "v", "b", "n", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/SouthSlavic.java b/tests/src/com/android/inputmethod/keyboard/layout/SouthSlavic.java new file mode 100644 index 000000000..be8b435d4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/SouthSlavic.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +public final class SouthSlavic extends LayoutBase { + private static final String LAYOUT_NAME = "south_slavic"; + + public SouthSlavic(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class SouthSlavicLayoutCustomizer extends LayoutCustomizer { + public SouthSlavicLayoutCustomizer(final Locale locale) { + super(locale); + } + + @Override + public final ExpectedKey getAlphabetKey() { return SOUTH_SLAVIC_ALPHABET_KEY; } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { + return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS; + } + + // U+0410: "А" CYRILLIC CAPITAL LETTER A + // U+0411: "Б" CYRILLIC CAPITAL LETTER BE + // U+0412: "В" CYRILLIC CAPITAL LETTER VE + private static final ExpectedKey SOUTH_SLAVIC_ALPHABET_KEY = key( + "\u0410\u0411\u0412", Constants.CODE_SWITCH_ALPHA_SYMBOL); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + public static final String ROW1_6 = "ROW1_6"; + public static final String ROW2_11 = "ROW2_11"; + public static final String ROW3_1 = "ROW3_1"; + public static final String ROW3_8 = "ROW3_8"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0459: "љ" CYRILLIC SMALL LETTER LJE + key("\u0459", additionalMoreKey("1")), + // U+045A: "њ" CYRILLIC SMALL LETTER NJE + key("\u045A", additionalMoreKey("2")), + // U+0435: "е" CYRILLIC SMALL LETTER IE + key("\u0435", additionalMoreKey("3")), + // U+0440: "р" CYRILLIC SMALL LETTER ER + key("\u0440", additionalMoreKey("4")), + // U+0442: "т" CYRILLIC SMALL LETTER TE + key("\u0442", additionalMoreKey("5")), + key(ROW1_6, additionalMoreKey("6")), + // U+0443: "у" CYRILLIC SMALL LETTER U + key("\u0443", additionalMoreKey("7")), + // U+0438: "и" CYRILLIC SMALL LETTER I + key("\u0438", additionalMoreKey("8")), + // U+043E: "о" CYRILLIC SMALL LETTER O + key("\u043E", additionalMoreKey("9")), + // U+043F: "п" CYRILLIC SMALL LETTER PE + key("\u043F", additionalMoreKey("0")), + // U+0448: "ш" CYRILLIC SMALL LETTER SHA + "\u0448") + .setKeysOfRow(2, + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+0441: "с" CYRILLIC SMALL LETTER ES + // U+0434: "д" CYRILLIC SMALL LETTER DE + // U+0444: "ф" CYRILLIC SMALL LETTER EF + // U+0433: "г" CYRILLIC SMALL LETTER GHE + // U+0445: "х" CYRILLIC SMALL LETTER HA + // U+0458: "ј" CYRILLIC SMALL LETTER JE + // U+043A: "к" CYRILLIC SMALL LETTER KA + // U+043B: "л" CYRILLIC SMALL LETTER EL + // U+0447: "ч" CYRILLIC SMALL LETTER CHE + "\u0430", "\u0441", "\u0434", "\u0444", "\u0433", "\u0445", "\u0458", "\u043A", + "\u043B", "\u0447", ROW2_11) + .setKeysOfRow(3, + // U+045F: "џ" CYRILLIC SMALL LETTER DZHE + // U+0446: "ц" CYRILLIC SMALL LETTER TSE + // U+0432: "в" CYRILLIC SMALL LETTER VE + // U+0431: "б" CYRILLIC SMALL LETTER BE + // U+043D: "н" CYRILLIC SMALL LETTER EN + // U+043C: "м" CYRILLIC SMALL LETTER EM + // U+0436: "ж" CYRILLIC SMALL LETTER ZHE + ROW3_1, "\u045F", "\u0446", "\u0432", "\u0431", "\u043D", "\u043C", ROW3_8, + "\u0436") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Spanish.java b/tests/src/com/android/inputmethod/keyboard/layout/Spanish.java new file mode 100644 index 000000000..225b9f604 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Spanish.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +public final class Spanish extends LayoutBase { + private static final String LAYOUT_NAME = "spanish"; + + public Spanish(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + public static final String ROW2_10 = "ROW2_10"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("y", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0"))) + .setKeysOfRow(2, "a", "s", "d", "f", "g", "h", "j", "k", "l", ROW2_10) + .setKeysOfRow(3, "z", "x", "c", "v", "b", "n", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Swiss.java b/tests/src/com/android/inputmethod/keyboard/layout/Swiss.java new file mode 100644 index 000000000..01a602054 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Swiss.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +public final class Swiss extends LayoutBase { + private static final String LAYOUT_NAME = "swiss"; + + public Swiss(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; } + + public static final String ROW1_11 = "ROW1_11"; + public static final String ROW2_10 = "ROW2_10"; + public static final String ROW2_11 = "ROW2_11"; + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + key("q", additionalMoreKey("1")), + key("w", additionalMoreKey("2")), + key("e", additionalMoreKey("3")), + key("r", additionalMoreKey("4")), + key("t", additionalMoreKey("5")), + key("z", additionalMoreKey("6")), + key("u", additionalMoreKey("7")), + key("i", additionalMoreKey("8")), + key("o", additionalMoreKey("9")), + key("p", additionalMoreKey("0")), + ROW1_11) + .setKeysOfRow(2, "a", "s", "d", "f", "g", "h", "j", "k", "l", ROW2_10, ROW2_11) + .setKeysOfRow(3, "y", "x", "c", "v", "b", "n", "m") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java new file mode 100644 index 000000000..726fefc68 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +/** + * The symbols keyboard layout. + */ +public class Symbols extends AbstractLayoutBase { + private final LayoutCustomizer mCustomizer; + + public Symbols(final LayoutCustomizer customizer) { + mCustomizer = customizer; + } + + public ExpectedKey[][] getLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(SYMBOLS_COMMON); + final LayoutCustomizer customizer = mCustomizer; + builder.replaceKeyOfLabel(CURRENCY, customizer.getCurrencyKey()); + builder.replaceKeyOfLabel(DOUBLE_QUOTE, key("\"", joinMoreKeys( + customizer.getDoubleQuoteMoreKeys(), customizer.getDoubleAngleQuoteKeys()))); + builder.replaceKeyOfLabel(SINGLE_QUOTE, key("'", joinMoreKeys( + customizer.getSingleQuoteMoreKeys(), customizer.getSingleAngleQuoteKeys()))); + if (isPhone) { + builder.addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone)) + .addKeysOnTheRightOfRow(3, DELETE_KEY) + .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey()) + .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)); + } else { + // Tablet symbols keyboard has extra two keys at the left edge of the 3rd row. + builder.addKeysOnTheLeftOfRow(3, (Object[])joinKeys("\\", "=")); + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(2, ENTER_KEY) + .addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone)) + .addKeysOnTheRightOfRow(3, customizer.getSymbolsShiftKey(isPhone)) + .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey()) + .addKeysOnTheRightOfRow(4, EMOJI_KEY); + } + return builder.build(); + } + + // Variations of the "currency" key on the 2nd row. + public static final String CURRENCY = "CURRENCY"; + // U+00A2: "¢" CENT SIGN + // U+00A3: "£" POUND SIGN + // U+00A5: "¥" YEN SIGN + // U+20AC: "€" EURO SIGN + // U+20B1: "₱" PESO SIGN + public static final ExpectedKey DOLLAR_SIGN = key("$"); + public static final ExpectedKey CENT_SIGN = key("\u00A2"); + public static final ExpectedKey POUND_SIGN = key("\u00A3"); + public static final ExpectedKey YEN_SIGN = key("\u00A5"); + public static final ExpectedKey EURO_SIGN = key("\u20AC"); + public static final ExpectedKey PESO_SIGN = key("\u20B1"); + public static final ExpectedKey CURRENCY_DOLLAR = key("$", + CENT_SIGN, POUND_SIGN, EURO_SIGN, YEN_SIGN, PESO_SIGN); + public static final ExpectedKey CURRENCY_EURO = key("\u20AC", + CENT_SIGN, POUND_SIGN, DOLLAR_SIGN, YEN_SIGN, PESO_SIGN); + public static final ExpectedKey[] CURRENCY_GENERIC_MORE_KEYS = joinMoreKeys( + Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.POUND_SIGN, + Symbols.YEN_SIGN, Symbols.PESO_SIGN); + + // Variations of the "double quote" key's "more keys" on the 3rd row. + public static final String DOUBLE_QUOTE = "DOUBLE_QUOTE"; + // U+201C: "“" LEFT DOUBLE QUOTATION MARK + // U+201D: "”" RIGHT DOUBLE QUOTATION MARK + // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK + private static final ExpectedKey DQUOTE_LEFT = key("\u201C"); + private static final ExpectedKey DQUOTE_RIGHT = key("\u201D"); + private static final ExpectedKey DQUOTE_LOW9 = key("\u201E"); + public static ExpectedKey[] DOUBLE_QUOTES_9LR = { DQUOTE_LOW9, DQUOTE_LEFT, DQUOTE_RIGHT }; + public static ExpectedKey[] DOUBLE_QUOTES_R9L = { DQUOTE_RIGHT, DQUOTE_LOW9, DQUOTE_LEFT }; + public static ExpectedKey[] DOUBLE_QUOTES_L9R = { DQUOTE_LEFT, DQUOTE_LOW9, DQUOTE_RIGHT }; + public static ExpectedKey[] DOUBLE_QUOTES_LR9 = { DQUOTE_LEFT, DQUOTE_RIGHT, DQUOTE_LOW9 }; + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + private static final ExpectedKey DAQUOTE_LEFT = key("\u00AB"); + private static final ExpectedKey DAQUOTE_RIGHT = key("\u00BB"); + public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR = { DAQUOTE_LEFT, DAQUOTE_RIGHT }; + public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_RL = { DAQUOTE_RIGHT, DAQUOTE_LEFT }; + + // Variations of the "single quote" key's "more keys" on the 3rd row. + public static final String SINGLE_QUOTE = "SINGLE_QUOTE"; + // U+2018: "‘" LEFT SINGLE QUOTATION MARK + // U+2019: "’" RIGHT SINGLE QUOTATION MARK + // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK + private static final ExpectedKey SQUOTE_LEFT = key("\u2018"); + private static final ExpectedKey SQUOTE_RIGHT = key("\u2019"); + private static final ExpectedKey SQUOTE_LOW9 = key("\u201A"); + public static ExpectedKey[] SINGLE_QUOTES_9LR = { SQUOTE_LOW9, SQUOTE_LEFT, SQUOTE_RIGHT }; + public static ExpectedKey[] SINGLE_QUOTES_R9L = { SQUOTE_RIGHT, SQUOTE_LOW9, SQUOTE_LEFT }; + public static ExpectedKey[] SINGLE_QUOTES_L9R = { SQUOTE_LEFT, SQUOTE_LOW9, SQUOTE_RIGHT }; + public static ExpectedKey[] SINGLE_QUOTES_LR9 = { SQUOTE_LEFT, SQUOTE_RIGHT, SQUOTE_LOW9 }; + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + private static final ExpectedKey SAQUOTE_LEFT = key("\u2039"); + private static final ExpectedKey SAQUOTE_RIGHT = key("\u203A"); + public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR = { SAQUOTE_LEFT, SAQUOTE_RIGHT }; + public static ExpectedKey[] SINGLE_ANGLE_QUOTES_RL = { SAQUOTE_RIGHT, SAQUOTE_LEFT }; + + // Common symbols keyboard layout. + private static final ExpectedKey[][] SYMBOLS_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+00B9: "¹" SUPERSCRIPT ONE + // U+00BD: "½" VULGAR FRACTION ONE HALF + // U+2153: "⅓" VULGAR FRACTION ONE THIRD + // U+00BC: "¼" VULGAR FRACTION ONE QUARTER + // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH + key("1", joinMoreKeys("\u00B9", "\u00BD", "\u2153", "\u00BC", "\u215B")), + // U+00B2: "²" SUPERSCRIPT TWO + // U+2154: "⅔" VULGAR FRACTION TWO THIRDS + key("2", joinMoreKeys("\u00B2", "\u2154")), + // U+00B3: "³" SUPERSCRIPT THREE + // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS + // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS + key("3", joinMoreKeys("\u00B3", "\u00BE", "\u215C")), + // U+2074: "⁴" SUPERSCRIPT FOUR + key("4", moreKey("\u2074")), + // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS + key("5", moreKey("\u215D")), + "6", + // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS + key("7", moreKey("\u215E")), + "8", "9", + // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N + // U+2205: "∅" EMPTY SET + key("0", joinMoreKeys("\u207F", "\u2205"))) + .setKeysOfRow(2, + key("@"), key("#"), key(CURRENCY), + // U+2030: "‰" PER MILLE SIGN + key("%", moreKey("\u2030")), + "&", + // U+2013: "–" EN DASH + // U+2014: "—" EM DASH + // U+00B7: "·" MIDDLE DOT + key("-", joinMoreKeys("_", "\u2013", "\u2014", "\u00B7")), + // U+00B1: "±" PLUS-MINUS SIGN + key("+", moreKey("\u00B1")), + key("(", joinMoreKeys("<", "{", "[")), + key(")", joinMoreKeys(">", "}", "]"))) + .setKeysOfRow(3, + // U+2020: "†" DAGGER + // U+2021: "‡" DOUBLE DAGGER + // U+2605: "★" BLACK STAR + key("*", joinMoreKeys("\u2020", "\u2021", "\u2605")), + key(DOUBLE_QUOTE), key(SINGLE_QUOTE), key(":"), key(";"), + // U+00A1: "¡" INVERTED EXCLAMATION MARK + key("!", moreKey("\u00A1")), + // U+00BF: "¿" INVERTED QUESTION MARK + key("?", moreKey("\u00BF"))) + .setKeysOfRow(4, + key("_"), key("/"), SPACE_KEY, key(","), + // U+2026: "…" HORIZONTAL ELLIPSIS + key(".", moreKey("\u2026"))) + .build(); + + public static class RtlSymbols extends Symbols { + public RtlSymbols(final LayoutCustomizer customizer) { + super(customizer); + } + + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + private static final ExpectedKey DAQUOTE_LEFT_RTL = key("\u00AB", "\u00BB"); + private static final ExpectedKey DAQUOTE_RIGHT_RTL = key("\u00BB", "\u00AB"); + public static ExpectedKey[] DOUBLE_ANGLE_QUOTES_LR_RTL = { + DAQUOTE_LEFT_RTL, DAQUOTE_RIGHT_RTL + }; + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + private static final ExpectedKey SAQUOTE_LEFT_RTL = key("\u2039", "\u203A"); + private static final ExpectedKey SAQUOTE_RIGHT_RTL = key("\u203A", "\u2039"); + public static ExpectedKey[] SINGLE_ANGLE_QUOTES_LR_RTL = { + SAQUOTE_LEFT_RTL, SAQUOTE_RIGHT_RTL + }; + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + .replaceKeyOfLabel("(", key("(", ")", + moreKey("<", ">"), moreKey("{", "}"), moreKey("[", "]"))) + .replaceKeyOfLabel(")", key(")", "(", + moreKey(">", "<"), moreKey("}", "{"), moreKey("]", "["))) + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java new file mode 100644 index 000000000..f611310af --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; + +/** + * The symbols shifted keyboard layout. + */ +public class SymbolsShifted extends AbstractLayoutBase { + private final LayoutCustomizer mCustomizer; + + public SymbolsShifted(final LayoutCustomizer customizer) { + mCustomizer = customizer; + } + + public ExpectedKey[][] getLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(SYMBOLS_SHIFTED_COMMON); + final LayoutCustomizer customizer = mCustomizer; + builder.replaceKeyOfLabel(OTHER_CURRENCIES, (Object[])customizer.getOtherCurrencyKeys()); + if (isPhone) { + builder.addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey()) + .addKeysOnTheRightOfRow(3, DELETE_KEY) + .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey()) + .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY)); + } else { + // Tablet symbols shifted keyboard has extra two keys at the right edge of the 3rd row. + // U+00BF: "¿" INVERTED QUESTION MARK + // U+00A1: "¡" INVERTED EXCLAMATION MARK + builder.addKeysOnTheRightOfRow(3, (Object[])joinKeys("\u00A1", "\u00BF")); + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(2, ENTER_KEY) + .addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey()) + .addKeysOnTheRightOfRow(3, customizer.getBackToSymbolsKey()) + .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey()) + .addKeysOnTheRightOfRow(4, EMOJI_KEY); + } + return builder.build(); + } + + // Variations of the "other currencies" keys on the 2rd row. + public static final String OTHER_CURRENCIES = "OTHER_CURRENCY"; + public static final ExpectedKey[] CURRENCIES_OTHER_THAN_DOLLAR = { + Symbols.POUND_SIGN, Symbols.CENT_SIGN, Symbols.EURO_SIGN, Symbols.YEN_SIGN + }; + public static final ExpectedKey[] CURRENCIES_OTHER_THAN_EURO = { + Symbols.POUND_SIGN, Symbols.YEN_SIGN, key(Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN), + Symbols.CENT_SIGN + }; + public static final ExpectedKey[] CURRENCIES_OTHER_GENERIC = { + Symbols.POUND_SIGN, Symbols.EURO_SIGN, key(Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN), + Symbols.CENT_SIGN + }; + + // Common symbols shifted keyboard layout. + private static final ExpectedKey[][] SYMBOLS_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0060: "`" GRAVE ACCENT + "~", "\u0060", "|", + // U+2022: "•" BULLET + // U+266A: "♪" EIGHTH NOTE + // U+2665: "♥" BLACK HEART SUIT + // U+2660: "♠" BLACK SPADE SUIT + // U+2666: "♦" BLACK DIAMOND SUIT + // U+2663: "♣" BLACK CLUB SUIT + key("\u2022", joinMoreKeys("\u266A", "\u2665", "\u2660", "\u2666", "\u2663")), + // U+221A: "√" SQUARE ROOT + "\u221A", + // U+03C0: "π" GREEK SMALL LETTER PI + // U+03A0: "Π" GREEK CAPITAL LETTER PI + key("\u03C0", moreKey("\u03A0")), + // U+00F7: "÷" DIVISION SIGN + // U+00D7: "×" MULTIPLICATION SIGN + "\u00F7", "\u00D7", + // U+00B6: "¶" PILCROW SIGN + // U+00A7: "§" SECTION SIGN + key("\u00B6", moreKey("\u00A7")), + // U+2206: "∆" INCREMENT + "\u2206") + .setKeysOfRow(2, + OTHER_CURRENCIES, + // U+2191: "↑" UPWARDS ARROW + // U+2193: "↓" DOWNWARDS ARROW + // U+2190: "←" LEFTWARDS ARROW + // U+2192: "→" RIGHTWARDS ARROW + key("^", joinMoreKeys("\u2191", "\u2193", "\u2190", "\u2192")), + // U+00B0: "°" DEGREE SIGN + // U+2032: "′" PRIME + // U+2033: "″" DOUBLE PRIME + key("\u00B0", joinMoreKeys("\u2032", "\u2033")), + // U+2260: "≠" NOT EQUAL TO + // U+2248: "≈" ALMOST EQUAL TO + // U+221E: "∞" INFINITY + key("=", joinMoreKeys("\u2260", "\u2248", "\u221E")), + "{", "}") + .setKeysOfRow(3, + // U+00A9: "©" COPYRIGHT SIGN + // U+00AE: "®" REGISTERED SIGN + // U+2122: "™" TRADE MARK SIGN + // U+2105: "℅" CARE OF + "\\", "\u00A9", "\u00AE", "\u2122", "\u2105", "[", "]") + .setKeysOfRow(4, + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + key("<", joinMoreKeys("\u2039", "\u2264", "\u00AB")), + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + key(">", joinMoreKeys("\u203A", "\u2265", "\u00BB")), + SPACE_KEY, ",", + // U+2026: "…" HORIZONTAL ELLIPSIS + key(".", moreKey("\u2026"))) + .build(); + + public static class RtlSymbolsShifted extends SymbolsShifted { + public RtlSymbolsShifted(final LayoutCustomizer customizer) { + super(customizer); + } + + @Override + public ExpectedKey[][] getLayout(final boolean isPhone) { + return new ExpectedKeyboardBuilder(super.getLayout(isPhone)) + .replaceKeyOfLabel("{", key("{", "}")) + .replaceKeyOfLabel("}", key("}", "{")) + .replaceKeyOfLabel("[", key("[", "]")) + .replaceKeyOfLabel("]", key("]", "[")) + // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + // U+2264: "≤" LESS-THAN OR EQUAL TO + // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + .replaceKeyOfLabel("<", key("<", ">", + moreKey("\u2039", "\u203A"), moreKey("\u2264", "\u2265"), + moreKey("\u00AB", "\u00BB"))) + // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + // U+2265: "≥" GREATER-THAN EQUAL TO + // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + .replaceKeyOfLabel(">", key(">", "<", + moreKey("\u203A", "\u2039"), moreKey("\u2265", "\u2264"), + moreKey("\u00BB", "\u00AB"))) + .build(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Thai.java b/tests/src/com/android/inputmethod/keyboard/layout/Thai.java new file mode 100644 index 000000000..253c93b83 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/Thai.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2014 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.layout; + +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.Constants; + +import java.util.Locale; + +/** + * The Thai alphabet keyboard. + */ +public final class Thai extends LayoutBase { + private static final String LAYOUT_NAME = "thai"; + + public Thai(final LayoutCustomizer customizer) { + super(customizer, Symbols.class, SymbolsShifted.class); + } + + @Override + public String getName() { return LAYOUT_NAME; } + + public static class ThaiCustomizer extends LayoutCustomizer { + public ThaiCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getAlphabetKey() { return THAI_ALPHABET_KEY; } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_BAHT; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getRightShiftKeys(final boolean isPhone) { return EMPTY_KEYS; } + + // U+0E01: "ก" THAI CHARACTER KO KAI + // U+0E02: "ข" THAI CHARACTER KHO KHAI + // U+0E04: "ค" THAI CHARACTER KHO KHWAI + private static final ExpectedKey THAI_ALPHABET_KEY = key( + "\u0E01\u0E02\u0E04", Constants.CODE_SWITCH_ALPHA_SYMBOL); + + // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT + private static final ExpectedKey CURRENCY_BAHT = key("\u0E3F", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + } + + @Override + ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(ALPHABET_COMMON); + if (isPhone) { + // U+0E03: "ฃ" THAI CHARACTER KHO KHUAT + builder.addKeysOnTheRightOfRow(3, "\u0E03"); + } else { + // U+0E03: "ฃ" THAI CHARACTER KHO KHUAT + builder.addKeysOnTheRightOfRow(2, "\u0E03") + .addKeysOnTheRightOfRow(4, (Object[])EXCLAMATION_AND_QUESTION_MARKS); + } + return builder.build(); + } + + @Override + public ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, + final int elementId) { + if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) { + return getCommonAlphabetLayout(isPhone); + } + final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder( + ALPHABET_SHIFTED_COMMON); + if (isPhone) { + // U+0E05: "ฅ" THAI CHARACTER KHO KHON + builder.addKeysOnTheRightOfRow(3, "\u0E05"); + } else { + // U+0E05: "ฅ" THAI CHARACTER KHO KHON + builder.addKeysOnTheRightOfRow(2, "\u0E05"); + } + return builder.build(); + } + + // Helper method to create alphabet layout by adding special function keys. + @Override + ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder, + final boolean isPhone) { + final LayoutCustomizer customizer = getCustomizer(); + builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone)); + builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone)); + builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone)); + if (isPhone) { + builder.addKeysOnTheRightOfRow(4, DELETE_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey()) + .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY)); + } else { + builder.addKeysOnTheRightOfRow(1, DELETE_KEY) + .addKeysOnTheRightOfRow(3, ENTER_KEY) + .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey(), SETTINGS_KEY) + .addKeysOnTheRightOfRow(5, EMOJI_KEY); + } + builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone)) + .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone)); + return builder; + } + + private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0E45: "ๅ" THAI CHARACTER LAKKHANGYAO + "\u0E45", + // U+0E51: "๑" THAI DIGIT ONE + key("/", joinMoreKeys("1", "\u0E51")), + // U+0E52: "๒" THAI DIGIT TWO + key("_", joinMoreKeys("2", "\u0E52")), + // U+0E20: "ภ" THAI CHARACTER PHO SAMPHAO + // U+0E53: "๓" THAI DIGIT THREE + key("\u0E20", joinMoreKeys("3", "\u0E53")), + // U+0E16: "ถ" THAI CHARACTER THO THUNG + // U+0E54: "๔" THAI DIGIT FOUR + key("\u0E16", joinMoreKeys("4", "\u0E54")), + // U+0E38: " ุ" THAI CHARACTER SARA U + key(" \u0E38", "\u0E38"), + // U+0E36: " ึ" THAI CHARACTER SARA UE + key(" \u0E36", "\u0E36"), + // U+0E04: "ค" THAI CHARACTER KHO KHWAI + // U+0E55: "๕" THAI DIGIT FIVE + key("\u0E04", joinMoreKeys("5", "\u0E55")), + // U+0E15: "ต" THAI CHARACTER TO TAO + // U+0E56: "๖" THAI DIGIT SIX + key("\u0E15", joinMoreKeys("6", "\u0E56")), + // U+0E08: "จ" THAI CHARACTER CHO CHAN + // U+0E57: "๗" THAI DIGIT SEVEN + key("\u0E08", joinMoreKeys("7", "\u0E57")), + // U+0E02: "ข" THAI CHARACTER KHO KHAI + // U+0E58: "๘" THAI DIGIT EIGHT + key("\u0E02", joinMoreKeys("8", "\u0E58")), + // U+0E0A: "ช" THAI CHARACTER CHO CHANG + // U+0E59: "๙" THAI DIGIT NINE + key("\u0E0A", joinMoreKeys("9", "\u0E59"))) + .setKeysOfRow(2, + // U+0E46: "ๆ" THAI CHARACTER MAIYAMOK + // U+0E50: "๐" THAI DIGIT ZERO + key("\u0E46", joinMoreKeys("0", "\u0E50")), + // U+0E44: "ไ" THAI CHARACTER SARA AI MAIMALAI + // U+0E33: "ำ" THAI CHARACTER SARA AM + // U+0E1E: "พ" THAI CHARACTER PHO PHAN + // U+0E30: "ะ" THAI CHARACTER SARA A + "\u0E44", "\u0E33", "\u0E1E", "\u0E30", + // U+0E31: " ั" THAI CHARACTER MAI HAN-AKAT + key(" \u0E31", "\u0E31"), + // U+0E35: " ี" HAI CHARACTER SARA II + key(" \u0E35", "\u0E35"), + // U+0E23: "ร" THAI CHARACTER RO RUA + // U+0E19: "น" THAI CHARACTER NO NU + // U+0E22: "ย" THAI CHARACTER YO YAK + // U+0E1A: "บ" THAI CHARACTER BO BAIMAI + // U+0E25: "ล" THAI CHARACTER LO LING + "\u0E23", "\u0E19", "\u0E22", "\u0E1A", "\u0E25") + .setKeysOfRow(3, + // U+0E1F: "ฟ" THAI CHARACTER FO FAN + // U+0E2B: "ห" THAI CHARACTER HO HIP + // U+0E01: "ก" THAI CHARACTER KO KAI + // U+0E14: "ด" THAI CHARACTER DO DEK + // U+0E40: "เ" THAI CHARACTER SARA E + "\u0E1F", "\u0E2B", "\u0E01", "\u0E14", "\u0E40", + // U+0E49: " ้" THAI CHARACTER MAI THO + key(" \u0E49", "\u0E49"), + // U+0E48: " ่" THAI CHARACTER MAI EK + key(" \u0E48", "\u0E48"), + // U+0E32: "า" THAI CHARACTER SARA AA + // U+0E2A: "ส" THAI CHARACTER SO SUA + // U+0E27: "ว" THAI CHARACTER WO WAEN + // U+0E07: "ง" THAI CHARACTER NGO NGU + "\u0E32", "\u0E2A", "\u0E27", "\u0E07") + .setKeysOfRow(4, + // U+0E1C: "ผ" THAI CHARACTER PHO PHUNG + // U+0E1B: "ป" THAI CHARACTER PO PLA + // U+0E41: "แ" THAI CHARACTER SARA AE + // U+0E2D: "อ" THAI CHARACTER O ANG + "\u0E1C", "\u0E1B", "\u0E41", "\u0E2D", + // U+0E34: " ิ" THAI CHARACTER SARA I + key(" \u0E34", "\u0E34"), + // U+0E37: " ื" THAI CHARACTER SARA UEE + key(" \u0E37", "\u0E37"), + // U+0E17: "ท" THAI CHARACTER THO THAHAN + // U+0E21: "ม" THAI CHARACTER MO MA + // U+0E43: "ใ" THAI CHARACTER SARA AI MAIMUAN + // U+0E1D: "ฝ" THAI CHARACTER FO FA + "\u0E17", "\u0E21", "\u0E43", "\u0E1D") + .build(); + + private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder() + .setKeysOfRow(1, + // U+0E51: "๑" THAI DIGIT ONE + // U+0E52: "๒" THAI DIGIT TWO + // U+0E53: "๓" THAI DIGIT THREE + // U+0E54: "๔" THAI DIGIT FOUR + // U+0E39: " ู" THAI CHARACTER SARA UU + "+", "\u0E51", "\u0E52", "\u0E53", "\u0E54", + key(" \u0E39", "\u0E39"), + // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT + // U+0E55: "๕" THAI DIGIT FIVE + // U+0E56: "๖" THAI DIGIT SIX + // U+0E57: "๗" THAI DIGIT SEVEN + // U+0E58: "๘" THAI DIGIT EIGHT + // U+0E59: "๙" THAI DIGIT NINE + "\u0E3F", "\u0E55", "\u0E56", "\u0E57", "\u0E58", "\u0E59") + .setKeysOfRow(2, + // U+0E50: "๐" THAI DIGIT ZERO + // U+0E0E: "ฎ" THAI CHARACTER DO CHADA + // U+0E11: "ฑ" THAI CHARACTER THO NANGMONTHO + // U+0E18: "ธ" THAI CHARACTER THO THONG + "\u0E50", "\"", "\u0E0E", "\u0E11", "\u0E18", + // U+0E4D: " ํ" THAI CHARACTER THANTHAKHAT + key(" \u0E4D", "\u0E4D"), + // U+0E4A: " ๊" THAI CHARACTER MAI TRI + key(" \u0E4A", "\u0E4A"), + // U+0E13: "ณ" THAI CHARACTER NO NEN + // U+0E2F: "ฯ" THAI CHARACTER PAIYANNOI + // U+0E0D: "ญ" THAI CHARACTER YO YING + // U+0E10: "ฐ" THAI CHARACTER THO THAN + "\u0E13", "\u0E2F", "\u0E0D", "\u0E10", ",") + .setKeysOfRow(3, + // U+0E24: "ฤ" THAI CHARACTER RU + // U+0E06: "ฆ" THAI CHARACTER KHO RAKHANG + // U+0E0F: "ฏ" THAI CHARACTER TO PATAK + // U+0E42: "โ" THAI CHARACTER SARA O + // U+0E0C: "ฌ" THAI CHARACTER CHO CHOE + "\u0E24", "\u0E06", "\u0E0F", "\u0E42", "\u0E0C", + // U+0E47: " ็" THAI CHARACTER MAITAIKHU + key(" \u0E47", "\u0E47"), + // U+0E4B: " ๋" THAI CHARACTER MAI CHATTAWA + key(" \u0E4B", "\u0E4B"), + // U+0E29: "ษ" THAI CHARACTER SO RUSI + // U+0E28: "ศ" THAI CHARACTER SO SALA + // U+0E0B: "ซ" THAI CHARACTER SO SO + "\u0E29", "\u0E28", "\u0E0B", ".") + .setKeysOfRow(4, + // U+0E09: "ฉ" THAI CHARACTER CHO CHING + // U+0E2E: "ฮ" THAI CHARACTER HO NOKHUK + "(", ")", "\u0E09", "\u0E2E", + // U+0E3A: " ฺ" THAI CHARACTER PHINTHU + key(" \u0E3A", "\u0E3A"), + // U+0E4C: " ์" THAI CHARACTER THANTHAKHAT + key(" \u0E4C", "\u0E4C"), + // U+0E12: "ฒ" THAI CHARACTER THO PHUTHAO + // U+0E2C: "ฬ" THAI CHARACTER LO CHULA + // U+0E26: "ฦ" THAI CHARACTER LU + "?", "\u0E12", "\u0E2C", "\u0E26") + .build(); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java new file mode 100644 index 000000000..3365b92ec --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import java.util.Arrays; + +/** + * This class builds a keyboard that is a two dimensional array of elements <code>E</code>. + * + * A keyboard consists of array of rows, and a row consists of array of elements. Each row may have + * different number of elements. A element of a keyboard can be specified by a row number and a + * column number, both numbers starts from 1. + * + * @param <E> the type of a keyboard element. A keyboard element must be an immutable object. + */ +abstract class AbstractKeyboardBuilder<E> { + // A building array of rows. + private E[][] mRows; + + // Returns an instance of default element. + abstract E defaultElement(); + // Returns an <code>E</code> array instance of the <code>size</code>. + abstract E[] newArray(final int size); + // Returns an <code>E[]</code> array instance of the <code>size</code>. + abstract E[][] newArrayOfArray(final int size); + + /** + * Construct a builder filled with the default element. + * @param dimensions the integer array of each row's size. + */ + AbstractKeyboardBuilder() { + mRows = newArrayOfArray(0); + } + + /** + * Construct a builder from template keyboard. This builder has the same dimensions and + * elements of <code>rows</rows>. + * @param rows the template keyboard rows. The elements of the <code>rows</code> will be + * shared with this builder. Therefore a element must be an immutable object. + */ + AbstractKeyboardBuilder(final E[][] rows) { + mRows = newArrayOfArray(rows.length); + for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) { + final E[] row = rows[rowIndex]; + mRows[rowIndex] = Arrays.copyOf(row, row.length); + } + } + + /** + * Return current constructing keyboard. + * @return the array of the array of the element being constructed. + */ + E[][] build() { + return mRows; + } + + /** + * Return the number of rows. + * @return the number of rows being constructed. + */ + int getRowCount() { + return mRows.length; + } + + /** + * Get the current contents of the specified row. + * @param row the row number to get the contents. + * @return the array of elements at row number <code>row</code>. + * @throws {@link RuntimeException} if <code>row</code> is illegal. + */ + E[] getRowAt(final int row) { + final int rowIndex = row - 1; + if (rowIndex < 0 || rowIndex >= mRows.length) { + throw new RuntimeException("Illegal row number: " + row); + } + return mRows[rowIndex]; + } + + /** + * Set an array of elements to the specified row. + * @param row the row number to set <code>elements</code>. + * @param elements the array of elements to set at row number <code>row</code>. + * @throws {@link RuntimeException} if <code>row</code> is illegal. + */ + void setRowAt(final int row, final E[] elements) { + final int rowIndex = row - 1; + if (rowIndex < 0) { + throw new RuntimeException("Illegal row number: " + row); + } + final E[][] newRows = (rowIndex < mRows.length) ? mRows + : Arrays.copyOf(mRows, rowIndex + 1); + newRows[rowIndex] = elements; + mRows = newRows; + } + + /** + * Set or insert an element at specified position. + * @param row the row number to set or insert the <code>element</code>. + * @param column the column number to set or insert the <code>element</code>. + * @param element the element to set or insert at <code>row,column</code>. + * @param insert if true, the <code>element</code> is inserted at <code>row,column</code>. + * Otherwise the <code>element</code> replace the element at <code>row,column</code>. + * @throws {@link RuntimeException} if <code>row</code> or <code>column</code> is illegal. + */ + void setElementAt(final int row, final int column, final E element, final boolean insert) { + final E[] elements = getRowAt(row); + final int columnIndex = column - 1; + if (columnIndex < 0) { + throw new RuntimeException("Illegal column number: " + column); + } + if (insert) { + if (columnIndex >= elements.length + 1) { + throw new RuntimeException("Illegal column number: " + column); + } + final E[] newElements = Arrays.copyOf(elements, elements.length + 1); + // Shift the remaining elements. + System.arraycopy(newElements, columnIndex, newElements, columnIndex + 1, + elements.length - columnIndex); + // Insert the element at <code>row,column</code>. + newElements[columnIndex] = element; + // Replace the current row with one. + setRowAt(row, newElements); + return; + } + final E[] newElements = (columnIndex < elements.length) ? elements + : Arrays.copyOf(elements, columnIndex + 1); + newElements[columnIndex] = element; + setRowAt(row, newElements); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java new file mode 100644 index 000000000..6176f6a3e --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.StringUtils; + +/** + * Base class to create an expected keyboard for unit test. + */ +public abstract class AbstractLayoutBase { + // Those helper methods have a lower case name to be readable when defining expected keyboard + // layouts. + + // Helper method to create an {@link ExpectedKey} object that has the label. + public static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(label, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has the label and the output text. + public static ExpectedKey key(final String label, final String outputText, + final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(label, outputText, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has the label and the output code. + public static ExpectedKey key(final String label, final int code, + final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(label, code, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has the icon and the output text. + public static ExpectedKey key(final int iconId, final String outputText, + final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(iconId, outputText, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has the icon and the output code. + public static ExpectedKey key(final int iconId, final int code, + final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(iconId, code, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has new "more keys". + public static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) { + return ExpectedKey.newInstance(key.getVisual(), key.getOutput(), moreKeys); + } + + // Helper method to create an {@link ExpectedAdditionalMoreKey} object for an + // "additional more key" that has the label. + // The additional more keys can be defined independently from other more keys. The position of + // the additional more keys in the long press popup keyboard can be controlled by specifying + // special marker "%" in the usual more keys definitions. + public static ExpectedAdditionalMoreKey additionalMoreKey(final String label) { + return ExpectedAdditionalMoreKey.newInstance(label); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label. + public static ExpectedKey moreKey(final String label) { + return ExpectedKey.newInstance(label); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label + // and the output text. + public static ExpectedKey moreKey(final String label, final String outputText) { + return ExpectedKey.newInstance(label, outputText); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label + // and the output code. + public static ExpectedKey moreKey(final String label, final int code) { + return ExpectedKey.newInstance(label, code); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the icon + // and the output text. + public static ExpectedKey moreKey(final int iconId, final String outputText) { + return ExpectedKey.newInstance(iconId, outputText); + } + + // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, + // {@link ExpectedKey} array, and {@link String}. + public static ExpectedKey[] joinMoreKeys(final Object ... moreKeys) { + return joinKeys(moreKeys); + } + + // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, + // {@link ExpectedKey} array, and {@link String}. + public static ExpectedKey[] joinKeys(final Object ... keys) { + return ExpectedKeyboardBuilder.joinKeys(keys); + } + + // Icon ids. + private static final int ICON_DELETE = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_DELETE_KEY); + private static final int ICON_TAB = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_TAB_KEY); + private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_SHORTCUT_KEY); + private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_SETTINGS_KEY); + private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY); + private static final int ICON_ENTER = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_ENTER_KEY); + private static final int ICON_EMOJI = KeyboardIconsSet.getIconId( + KeyboardIconsSet.NAME_EMOJI_KEY); + + // Functional keys. + public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE); + public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB); + public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT); + public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS); + public static final ExpectedKey LANGUAGE_SWITCH_KEY = key( + ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH); + public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER); + public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI); + public static final ExpectedKey SPACE_KEY = key( + StringUtils.newSingleCodePointString(Constants.CODE_SPACE)); +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java new file mode 100644 index 000000000..26d2e2ad2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.internal.MoreKeySpec; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class builds an actual keyboard for unit test. + */ +public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { + private static ArrayList<Key> filterOutSpacer(final List<Key> keys) { + final ArrayList<Key> filteredKeys = CollectionUtils.newArrayList(); + for (final Key key : keys) { + if (key.isSpacer()) { + continue; + } + filteredKeys.add(key); + } + return filteredKeys; + } + + /** + * Create the keyboard that consists of the array of rows of the actual keyboard's keys. + * @param sortedKeys the sorted list of keys of the actual keyboard. + * @return the actual keyboard grouped with rows. + */ + public static Key[][] buildKeyboard(final List<Key> sortedKeys) { + // Filter out spacer to prepare to create rows. + final ArrayList<Key> filteredSortedKeys = filterOutSpacer(sortedKeys); + + // Grouping keys into rows. + final ArrayList<ArrayList<Key>> rows = CollectionUtils.newArrayList(); + ArrayList<Key> elements = CollectionUtils.newArrayList(); + int lastY = filteredSortedKeys.get(0).getY(); + for (final Key key : filteredSortedKeys) { + if (lastY != key.getY()) { + // A new row is starting. + lastY = key.getY(); + rows.add(elements); + elements = CollectionUtils.newArrayList(); + } + elements.add(key); + } + rows.add(elements); // Add the last row. + + // Calculate each dimension of rows and create a builder. + final int[] dimensions = new int[rows.size()]; + for (int rowIndex = 0; rowIndex < dimensions.length; rowIndex++) { + dimensions[rowIndex] = rows.get(rowIndex).size(); + } + final ActualKeyboardBuilder builder = new ActualKeyboardBuilder(); + + for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) { + final int row = rowIndex + 1; + final ArrayList<Key> rowKeys = rows.get(rowIndex); + builder.setRowAt(row, rowKeys.toArray(new Key[rowKeys.size()])); + } + return builder.build(); + } + + @Override + Key defaultElement() { return null; } + + @Override + Key[] newArray(final int size) { return new Key[size]; } + + @Override + Key[][] newArrayOfArray(final int size) { return new Key[size][]; } + + // Helper class to create concise representation from the key specification. + static class MoreKeySpecStringizer extends StringUtils.Stringizer<MoreKeySpec> { + static final MoreKeySpecStringizer STRINGIZER = new MoreKeySpecStringizer(); + + @Override + public String stringize(final MoreKeySpec spec) { + return toString(spec.mLabel, spec.mIconId, spec.mOutputText, spec.mCode); + } + + static String toString(final String label, final int iconId, final String outputText, + final int code) { + final String visual = (iconId != KeyboardIconsSet.ICON_UNDEFINED) + ? KeyboardIconsSet.getIconName(iconId) : label; + final String output; + if (code == Constants.CODE_OUTPUT_TEXT) { + output = outputText; + } else if (code < Constants.CODE_SPACE) { + output = Constants.printableCode(code); + } else { + output = StringUtils.newSingleCodePointString(code); + } + if (visual.equals(output)) { + return visual; + } + return visual + "|" + output; + } + } + + // Helper class to create concise representation from the key. + static class KeyStringizer extends StringUtils.Stringizer<Key> { + static final KeyStringizer STRINGIZER = new KeyStringizer(); + + @Override + public String stringize(final Key key) { + if (key == null) { + return "NULL"; + } + if (key.isSpacer()) { + return "SPACER"; + } + final StringBuilder sb = new StringBuilder(); + sb.append(MoreKeySpecStringizer.toString( + key.getLabel(), key.getIconId(), key.getOutputText(), key.getCode())); + final MoreKeySpec[] moreKeys = key.getMoreKeys(); + if (moreKeys == null) { + return sb.toString(); + } + sb.append("^"); + sb.append(MoreKeySpecStringizer.STRINGIZER.join(moreKeys)); + return sb.toString(); + } + } + + /** + * Convert the key to human readable string. + * @param key the key to be converted to string. + * @return the human readable representation of <code>key</code>. + */ + public static String toString(final Key key) { + return KeyStringizer.STRINGIZER.stringize(key); + } + + /** + * Convert the keyboard row to human readable string. + * @param keys the keyboard row to be converted to string. + * @return the human readable representation of <code>keys</code>. + */ + public static String toString(final Key[] keys) { + return KeyStringizer.STRINGIZER.join(keys); + } + + // Helper class to create concise representation from the array of the key. + static class KeyArrayStringizer extends StringUtils.Stringizer<Key[]> { + static final KeyArrayStringizer STRINGIZER = new KeyArrayStringizer(); + + @Override + public String stringize(final Key[] keyArray) { + return KeyStringizer.STRINGIZER.join(keyArray); + } + } + + /** + * Convert the keyboard to human readable string. + * @param rows the keyboard to be converted to string. + * @return the human readable representation of <code>rows</code>. + */ + public static String toString(final Key[][] rows) { + return KeyArrayStringizer.STRINGIZER.join(rows, "\n" /* delimiter */); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java new file mode 100644 index 000000000..ad08ba5a6 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.internal.MoreKeySpec; +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Locale; + +/** + * This class represents an expected key. + */ +public class ExpectedKey { + static ExpectedKey EMPTY_KEY = newInstance(""); + + // A key that has a string label and may have "more keys". + static ExpectedKey newInstance(final String label, final ExpectedKey... moreKeys) { + return newInstance(label, label, moreKeys); + } + + // A key that has a string label and a different output text and may have "more keys". + static ExpectedKey newInstance(final String label, final String outputText, + final ExpectedKey... moreKeys) { + return newInstance(ExpectedKeyVisual.newInstance(label), + ExpectedKeyOutput.newInstance(outputText), moreKeys); + } + + // A key that has a string label and a code point output and may have "more keys". + static ExpectedKey newInstance(final String label, final int code, + final ExpectedKey... moreKeys) { + return newInstance(ExpectedKeyVisual.newInstance(label), + ExpectedKeyOutput.newInstance(code), moreKeys); + } + + // A key that has an icon and an output text and may have "more keys". + static ExpectedKey newInstance(final int iconId, final String outputText, + final ExpectedKey... moreKeys) { + return newInstance(ExpectedKeyVisual.newInstance(iconId), + ExpectedKeyOutput.newInstance(outputText), moreKeys); + } + + // A key that has an icon and a code point output and may have "more keys". + static ExpectedKey newInstance(final int iconId, final int code, + final ExpectedKey... moreKeys) { + return newInstance(ExpectedKeyVisual.newInstance(iconId), + ExpectedKeyOutput.newInstance(code), moreKeys); + } + + static ExpectedKey newInstance(final ExpectedKeyVisual visual, final ExpectedKeyOutput output, + final ExpectedKey... moreKeys) { + if (moreKeys.length == 0) { + return new ExpectedKey(visual, output); + } + // The more keys are the extra keys that the main keyboard key may have in its long press + // popup keyboard. + // The additional more keys can be defined independently from other more keys. + // The position of the additional more keys in the long press popup keyboard can be + // controlled by specifying special marker "%" in the usual more keys definitions. + final ArrayList<ExpectedKey> moreKeysList = CollectionUtils.newArrayList(); + final ArrayList<ExpectedAdditionalMoreKey> additionalMoreKeys = + CollectionUtils.newArrayList(); + int firstAdditionalMoreKeyIndex = -1; + for (int index = 0; index < moreKeys.length; index++) { + final ExpectedKey moreKey = moreKeys[index]; + if (moreKey instanceof ExpectedAdditionalMoreKey) { + additionalMoreKeys.add((ExpectedAdditionalMoreKey) moreKey); + if (firstAdditionalMoreKeyIndex < 0) { + firstAdditionalMoreKeyIndex = index; + } + } else { + moreKeysList.add(moreKey); + } + } + if (additionalMoreKeys.isEmpty()) { + return new ExpectedKeyWithMoreKeys(visual, output, moreKeys); + } + final ExpectedKey[] moreKeysArray = moreKeysList.toArray( + new ExpectedKey[moreKeysList.size()]); + final ExpectedAdditionalMoreKey[] additionalMoreKeysArray = additionalMoreKeys.toArray( + new ExpectedAdditionalMoreKey[additionalMoreKeys.size()]); + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + visual, output, moreKeysArray, firstAdditionalMoreKeyIndex, + additionalMoreKeysArray); + } + + private static final ExpectedKey[] EMPTY_KEYS = new ExpectedKey[0]; + + // The expected visual outlook of this key. + private final ExpectedKeyVisual mVisual; + // The expected output of this key. + private final ExpectedKeyOutput mOutput; + + public final ExpectedKeyVisual getVisual() { + return mVisual; + } + + public final ExpectedKeyOutput getOutput() { + return mOutput; + } + + public ExpectedKey[] getMoreKeys() { + // This key has no "more keys". + return EMPTY_KEYS; + } + + public ExpectedKey setMoreKeys(final ExpectedKey... moreKeys) { + return newInstance(mVisual, mOutput, moreKeys); + } + + public ExpectedKey setAdditionalMoreKeys( + final ExpectedAdditionalMoreKey... additionalMoreKeys) { + if (additionalMoreKeys.length == 0) { + return this; + } + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + mVisual, mOutput, EMPTY_KEYS, 0 /* additionalMoreKeysIndex */, additionalMoreKeys); + } + + public ExpectedKey setAdditionalMoreKeysIndex(final int additionalMoreKeysIndex) { + if (additionalMoreKeysIndex == 0) { + return this; + } + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + mVisual, mOutput, EMPTY_KEYS, additionalMoreKeysIndex); + } + + protected ExpectedKey(final ExpectedKeyVisual visual, final ExpectedKeyOutput output) { + mVisual = visual; + mOutput = output; + } + + public ExpectedKey toUpperCase(Locale locale) { + return newInstance(mVisual.toUpperCase(locale), mOutput.toUpperCase(locale)); + } + + public boolean equalsTo(final Key key) { + // This key has no "more keys". + return mVisual.equalsTo(key) && mOutput.equalsTo(key) && key.getMoreKeys() == null; + } + + public boolean equalsTo(final MoreKeySpec moreKeySpec) { + return mVisual.equalsTo(moreKeySpec) && mOutput.equalsTo(moreKeySpec); + } + + @Override + public boolean equals(final Object object) { + if (object instanceof ExpectedKey) { + final ExpectedKey key = (ExpectedKey) object; + return mVisual.equalsTo(key.mVisual) && mOutput.equalsTo(key.mOutput) + && Arrays.equals(getMoreKeys(), key.getMoreKeys()); + } + return false; + } + + private static int hashCode(final Object... objects) { + return Arrays.hashCode(objects); + } + + @Override + public int hashCode() { + return hashCode(mVisual, mOutput, getMoreKeys()); + } + + @Override + public String toString() { + if (mVisual.equalsTo(mOutput)) { + return mVisual.toString(); + } + return mVisual + "|" + mOutput; + } + + /** + * This class represents an expected "additional more key". + * + * The additional more keys can be defined independently from other more keys. The position of + * the additional more keys in the long press popup keyboard can be controlled by specifying + * special marker "%" in the usual more keys definitions. + */ + public static class ExpectedAdditionalMoreKey extends ExpectedKey { + public static ExpectedAdditionalMoreKey newInstance(final String label) { + return new ExpectedAdditionalMoreKey(ExpectedKeyVisual.newInstance(label), + ExpectedKeyOutput.newInstance(label)); + } + + public static ExpectedAdditionalMoreKey newInstance(final ExpectedKey key) { + return new ExpectedAdditionalMoreKey(key.getVisual(), key.getOutput()); + } + + ExpectedAdditionalMoreKey(final ExpectedKeyVisual visual, final ExpectedKeyOutput output) { + super(visual, output); + } + + @Override + public ExpectedAdditionalMoreKey toUpperCase(final Locale locale) { + final ExpectedKey upperCaseKey = super.toUpperCase(locale); + return new ExpectedAdditionalMoreKey( + upperCaseKey.getVisual(), upperCaseKey.getOutput()); + } + } + + /** + * This class represents an expected key that has "more keys". + */ + private static class ExpectedKeyWithMoreKeys extends ExpectedKey { + private final ExpectedKey[] mMoreKeys; + + ExpectedKeyWithMoreKeys(final ExpectedKeyVisual visual, final ExpectedKeyOutput output, + final ExpectedKey... moreKeys) { + super(visual, output); + mMoreKeys = moreKeys; + } + + @Override + public ExpectedKey toUpperCase(final Locale locale) { + final ExpectedKey[] upperCaseMoreKeys = new ExpectedKey[mMoreKeys.length]; + for (int i = 0; i < mMoreKeys.length; i++) { + upperCaseMoreKeys[i] = mMoreKeys[i].toUpperCase(locale); + } + return newInstance(getVisual().toUpperCase(locale), getOutput().toUpperCase(locale), + upperCaseMoreKeys); + } + + @Override + public ExpectedKey[] getMoreKeys() { + return mMoreKeys; + } + + @Override + public ExpectedKey setAdditionalMoreKeys( + final ExpectedAdditionalMoreKey... additionalMoreKeys) { + if (additionalMoreKeys.length == 0) { + return this; + } + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual(), getOutput(), mMoreKeys, 0 /* additionalMoreKeysIndex */, + additionalMoreKeys); + } + + @Override + public ExpectedKey setAdditionalMoreKeysIndex(final int additionalMoreKeysIndex) { + if (additionalMoreKeysIndex == 0) { + return this; + } + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual(), getOutput(), mMoreKeys, additionalMoreKeysIndex); + } + + @Override + public boolean equalsTo(final Key key) { + if (getVisual().equalsTo(key) && getOutput().equalsTo(key)) { + final MoreKeySpec[] moreKeySpecs = key.getMoreKeys(); + final ExpectedKey[] moreKeys = getMoreKeys(); + // This key should have at least one "more key". + if (moreKeySpecs == null || moreKeySpecs.length != moreKeys.length) { + return false; + } + for (int index = 0; index < moreKeySpecs.length; index++) { + if (!moreKeys[index].equalsTo(moreKeySpecs[index])) { + return false; + } + } + return true; + } + return false; + } + + @Override + public boolean equalsTo(final MoreKeySpec moreKeySpec) { + // MoreKeySpec has no "more keys". + return false; + } + + @Override + public String toString() { + return super.toString() + "^" + Arrays.toString(getMoreKeys()); + } + } + + /** + * This class represents an expected key that has "more keys" and "additional more keys". + */ + private static final class ExpectedKeyWithMoreKeysAndAdditionalMoreKeys + extends ExpectedKeyWithMoreKeys { + private final ExpectedAdditionalMoreKey[] mAdditionalMoreKeys; + private final int mAdditionalMoreKeysIndex; + + ExpectedKeyWithMoreKeysAndAdditionalMoreKeys(final ExpectedKeyVisual visual, + final ExpectedKeyOutput output, final ExpectedKey[] moreKeys, + final int additionalMoreKeysIndex, + final ExpectedAdditionalMoreKey... additionalMoreKeys) { + super(visual, output, moreKeys); + mAdditionalMoreKeysIndex = additionalMoreKeysIndex; + mAdditionalMoreKeys = additionalMoreKeys; + } + + @Override + public ExpectedKey setMoreKeys(final ExpectedKey... moreKeys) { + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual(), getOutput(), moreKeys, mAdditionalMoreKeysIndex, + mAdditionalMoreKeys); + } + + @Override + public ExpectedKey setAdditionalMoreKeys( + final ExpectedAdditionalMoreKey... additionalMoreKeys) { + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual(), getOutput(), super.getMoreKeys(), mAdditionalMoreKeysIndex, + additionalMoreKeys); + } + + @Override + public ExpectedKey setAdditionalMoreKeysIndex(final int additionalMoreKeysIndex) { + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual(), getOutput(), super.getMoreKeys(), additionalMoreKeysIndex, + mAdditionalMoreKeys); + } + + @Override + public ExpectedKey toUpperCase(final Locale locale) { + final ExpectedKey[] moreKeys = super.getMoreKeys(); + final ExpectedKey[] upperCaseMoreKeys = new ExpectedKey[moreKeys.length]; + for (int i = 0; i < moreKeys.length; i++) { + upperCaseMoreKeys[i] = moreKeys[i].toUpperCase(locale); + } + final ExpectedAdditionalMoreKey[] upperCaseAdditionalMoreKeys = + new ExpectedAdditionalMoreKey[mAdditionalMoreKeys.length]; + for (int i = 0; i < mAdditionalMoreKeys.length; i++) { + upperCaseAdditionalMoreKeys[i] = mAdditionalMoreKeys[i].toUpperCase(locale); + } + return new ExpectedKeyWithMoreKeysAndAdditionalMoreKeys( + getVisual().toUpperCase(locale), getOutput().toUpperCase(locale), + upperCaseMoreKeys, mAdditionalMoreKeysIndex, upperCaseAdditionalMoreKeys); + } + + @Override + public ExpectedKey[] getMoreKeys() { + final ExpectedKey[] moreKeys = super.getMoreKeys(); + final ExpectedKey[] edittedMoreKeys = Arrays.copyOf( + moreKeys, moreKeys.length + mAdditionalMoreKeys.length); + System.arraycopy(edittedMoreKeys, mAdditionalMoreKeysIndex, + edittedMoreKeys, mAdditionalMoreKeysIndex + mAdditionalMoreKeys.length, + moreKeys.length - mAdditionalMoreKeysIndex); + System.arraycopy(mAdditionalMoreKeys, 0, edittedMoreKeys, mAdditionalMoreKeysIndex, + mAdditionalMoreKeys.length); + return edittedMoreKeys; + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java new file mode 100644 index 000000000..1be51e60b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.internal.MoreKeySpec; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.StringUtils; + +import java.util.Locale; + +/** + * This class represents an expected output of a key. + * + * There are two types of expected output, an integer code point and a string output text. + */ +abstract class ExpectedKeyOutput { + static ExpectedKeyOutput newInstance(final int code) { + return new Code(code); + } + + static ExpectedKeyOutput newInstance(final String outputText) { + // If the <code>outputText</code> is one code point string, use {@link CodePoint} object. + if (StringUtils.codePointCount(outputText) == 1) { + return new Code(outputText.codePointAt(0)); + } + return new Text(outputText); + } + + abstract ExpectedKeyOutput toUpperCase(final Locale locale); + abstract boolean equalsTo(final String text); + abstract boolean equalsTo(final Key key); + abstract boolean equalsTo(final MoreKeySpec moreKeySpec); + abstract boolean equalsTo(final ExpectedKeyOutput output); + + /** + * This class represents an integer code point. + */ + private static class Code extends ExpectedKeyOutput { + // UNICODE code point or a special negative value defined in {@link Constants}. + private final int mCode; + + Code(final int code) { mCode = code; } + + @Override + ExpectedKeyOutput toUpperCase(final Locale locale) { + if (Constants.isLetterCode(mCode)) { + final String codeString = StringUtils.newSingleCodePointString(mCode); + // A letter may have an upper case counterpart that consists of multiple code + // points, for instance the upper case of "ß" is "SS". + return newInstance(codeString.toUpperCase(locale)); + } + // A special negative value has no upper case. + return this; + } + + @Override + boolean equalsTo(final String text) { + return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode; + } + + @Override + boolean equalsTo(final Key key) { + return mCode == key.getCode(); + } + + @Override + boolean equalsTo(final MoreKeySpec moreKeySpec) { + return mCode == moreKeySpec.mCode; + } + + @Override + boolean equalsTo(final ExpectedKeyOutput output) { + return (output instanceof Code) && mCode == ((Code)output).mCode; + } + + @Override + public String toString() { + return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode) + : Constants.printableCode(mCode); + } + } + + /** + * This class represents a string output text. + */ + private static class Text extends ExpectedKeyOutput { + private final String mText; + + Text(final String text) { mText = text; } + + @Override + ExpectedKeyOutput toUpperCase(final Locale locale) { + return newInstance(mText.toUpperCase(locale)); + } + + @Override + boolean equalsTo(final String text) { + return text.equals(text); + } + + @Override + boolean equalsTo(final Key key) { + return key.getCode() == Constants.CODE_OUTPUT_TEXT + && mText.equals(key.getOutputText()); + } + + @Override + boolean equalsTo(final MoreKeySpec moreKeySpec) { + return moreKeySpec.mCode == Constants.CODE_OUTPUT_TEXT + && mText.equals(moreKeySpec.mOutputText); + } + + @Override + boolean equalsTo(final ExpectedKeyOutput output) { + return (output instanceof Text) && mText == ((Text)output).mText; + } + + @Override + public String toString() { + return mText; + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java new file mode 100644 index 000000000..0a0da32b6 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.internal.MoreKeySpec; + +import java.util.Locale; + +/** + * This class represents an expected visual outlook of a key. + * + * There are two types of expected visual, an integer icon id and a string label. + */ +abstract class ExpectedKeyVisual { + static ExpectedKeyVisual newInstance(final String label) { + return new Label(label); + } + + static ExpectedKeyVisual newInstance(final int iconId) { + return new Icon(iconId); + } + + abstract ExpectedKeyVisual toUpperCase(final Locale locale); + abstract boolean equalsTo(final String text); + abstract boolean equalsTo(final Key key); + abstract boolean equalsTo(final MoreKeySpec moreKeySpec); + abstract boolean equalsTo(final ExpectedKeyOutput output); + abstract boolean equalsTo(final ExpectedKeyVisual visual); + + /** + * This class represents an integer icon id. + */ + private static class Icon extends ExpectedKeyVisual { + private final int mIconId; + + Icon(final int iconId) { + mIconId = iconId; + } + + @Override + ExpectedKeyVisual toUpperCase(final Locale locale) { + return this; + } + + @Override + boolean equalsTo(final String text) { + return false; + } + + @Override + boolean equalsTo(final Key key) { + return mIconId == key.getIconId(); + } + + @Override + boolean equalsTo(final MoreKeySpec moreKeySpec) { + return mIconId == moreKeySpec.mIconId; + } + + @Override + boolean equalsTo(final ExpectedKeyOutput output) { + return false; + } + + @Override + boolean equalsTo(final ExpectedKeyVisual visual) { + return (visual instanceof Icon) && mIconId == ((Icon)visual).mIconId; + } + + @Override + public String toString() { + return KeyboardIconsSet.getIconName(mIconId); + } + } + + /** + * This class represents a string label. + */ + private static class Label extends ExpectedKeyVisual { + private final String mLabel; + + Label(final String label) { mLabel = label; } + + @Override + ExpectedKeyVisual toUpperCase(final Locale locale) { + return new Label(mLabel.toUpperCase(locale)); + } + + @Override + boolean equalsTo(final String text) { + return mLabel.equals(text); + } + + @Override + boolean equalsTo(final Key key) { + return mLabel.equals(key.getLabel()); + } + + @Override + boolean equalsTo(final MoreKeySpec moreKeySpec) { + return mLabel.equals(moreKeySpec.mLabel); + } + + @Override + boolean equalsTo(final ExpectedKeyOutput output) { + return output.equalsTo(mLabel); + } + + @Override + boolean equalsTo(final ExpectedKeyVisual visual) { + return (visual instanceof Label) && mLabel.equals(((Label)visual).mLabel); + } + + @Override + public String toString() { + return mLabel; + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java new file mode 100644 index 000000000..f068ad11d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2014 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.layout.expected; + +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Locale; + +/** + * This class builds an expected keyboard for unit test. + */ +public final class ExpectedKeyboardBuilder extends AbstractKeyboardBuilder<ExpectedKey> { + public ExpectedKeyboardBuilder() { + super(); + } + + public ExpectedKeyboardBuilder(final ExpectedKey[][] rows) { + super(rows); + } + + @Override + protected ExpectedKey defaultElement() { + return ExpectedKey.EMPTY_KEY; + } + + @Override + ExpectedKey[] newArray(final int size) { + return new ExpectedKey[size]; + } + + @Override + ExpectedKey[][] newArrayOfArray(final int size) { + return new ExpectedKey[size][]; + } + + @Override + public ExpectedKey[][] build() { + return super.build(); + } + + // A replacement job to be performed. + private interface ReplaceJob { + // Returns a {@link ExpectedKey} objects to replace. + ExpectedKey[] replacingKeys(final ExpectedKey oldKey); + // Return true if replacing should be stopped at first occurrence. + boolean stopAtFirstOccurrence(); + } + + private static ExpectedKey[] replaceKeyAt(final ExpectedKey[] keys, final int columnIndex, + final ExpectedKey[] replacingKeys) { + // Optimization for replacing a key with another key. + if (replacingKeys.length == 1) { + keys[columnIndex] = replacingKeys[0]; + return keys; + } + final int newLength = keys.length - 1 + replacingKeys.length; + // Remove the key at columnIndex. + final ExpectedKey[] newKeys = Arrays.copyOf(keys, newLength); + System.arraycopy(keys, columnIndex + 1, newKeys, columnIndex + replacingKeys.length, + keys.length - 1 - columnIndex); + // Insert replacing keys at columnIndex. + System.arraycopy(replacingKeys, 0, newKeys, columnIndex, replacingKeys.length); + return newKeys; + + } + + // Replace key(s) that has the specified visual. + private void replaceKeyOf(final ExpectedKeyVisual visual, final ReplaceJob job) { + int replacedCount = 0; + final int rowCount = getRowCount(); + for (int row = 1; row <= rowCount; row++) { + ExpectedKey[] keys = getRowAt(row); + for (int columnIndex = 0; columnIndex < keys.length; /* nothing */) { + final ExpectedKey currentKey = keys[columnIndex]; + if (!currentKey.getVisual().equalsTo(visual)) { + columnIndex++; + continue; + } + final ExpectedKey[] replacingKeys = job.replacingKeys(currentKey); + keys = replaceKeyAt(keys, columnIndex, replacingKeys); + columnIndex += replacingKeys.length; + setRowAt(row, keys); + replacedCount++; + if (job.stopAtFirstOccurrence()) { + return; + } + } + } + if (replacedCount == 0) { + throw new RuntimeException( + "Can't find key that has visual: " + visual + " in\n" + this); + } + } + + // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, + // {@link ExpectedKey} array, and {@link String}. + static ExpectedKey[] joinKeys(final Object ... keys) { + final ArrayList<ExpectedKey> list = CollectionUtils.newArrayList(); + for (final Object key : keys) { + if (key instanceof ExpectedKey) { + list.add((ExpectedKey)key); + } else if (key instanceof ExpectedKey[]) { + list.addAll(Arrays.asList((ExpectedKey[])key)); + } else if (key instanceof String) { + list.add(ExpectedKey.newInstance((String)key)); + } else { + throw new RuntimeException("Unknown expected key type: " + key); + } + } + return list.toArray(new ExpectedKey[list.size()]); + } + + /** + * Set the row with specified keys. + * @param row the row number to set keys. + * @param keys the keys to be set at <code>row</code>. Each key can be {@link ExpectedKey}, + * {@link ExpectedKey} array, and {@link String}. + * @return this builder. + */ + public ExpectedKeyboardBuilder setKeysOfRow(final int row, final Object ... keys) { + setRowAt(row, joinKeys(keys)); + return this; + } + + /** + * Set the "more keys" of the key that has the specified label. + * @param label the label of the key to set the "more keys". + * @param moreKeys the array of "more key" to be set. Each "more key" can be + * {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}. + * @return this builder. + */ + public ExpectedKeyboardBuilder setMoreKeysOf(final String label, final Object ... moreKeys) { + setMoreKeysOf(ExpectedKeyVisual.newInstance(label), joinKeys(moreKeys)); + return this; + } + + /** + * Set the "more keys" of the key that has the specified icon. + * @param iconId the icon id of the key to set the "more keys". + * @param moreKeys the array of "more key" to be set. Each "more key" can be + * {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}. + * @return this builder. + */ + public ExpectedKeyboardBuilder setMoreKeysOf(final int iconId, final Object ... moreKeys) { + setMoreKeysOf(ExpectedKeyVisual.newInstance(iconId), joinKeys(moreKeys)); + return this; + } + + private void setMoreKeysOf(final ExpectedKeyVisual visual, final ExpectedKey[] moreKeys) { + replaceKeyOf(visual, new ReplaceJob() { + @Override + public ExpectedKey[] replacingKeys(final ExpectedKey oldKey) { + return new ExpectedKey[] { oldKey.setMoreKeys(moreKeys) }; + } + @Override + public boolean stopAtFirstOccurrence() { + return true; + } + }); + } + + /** + * Set the "additional more keys position" of the key that has the specified label. + * @param label the label of the key to set the "additional more keys". + * @param additionalMoreKeysPosition the position in the "more keys" where + * "additional more keys" will be merged. The position starts from 1. + * @return this builder. + */ + public ExpectedKeyboardBuilder setAdditionalMoreKeysPositionOf(final String label, + final int additionalMoreKeysPosition) { + final int additionalMoreKeysIndex = additionalMoreKeysPosition - 1; + if (additionalMoreKeysIndex < 0) { + throw new RuntimeException("Illegal additional more keys position: " + + additionalMoreKeysPosition); + } + final ExpectedKeyVisual visual = ExpectedKeyVisual.newInstance(label); + replaceKeyOf(visual, new ReplaceJob() { + @Override + public ExpectedKey[] replacingKeys(final ExpectedKey oldKey) { + return new ExpectedKey[] { + oldKey.setAdditionalMoreKeysIndex(additionalMoreKeysIndex) + }; + } + @Override + public boolean stopAtFirstOccurrence() { + return true; + } + }); + return this; + } + + /** + * Insert the keys at specified position. + * @param row the row number to insert the <code>keys</code>. + * @param column the column number to insert the <code>keys</code>. + * @param keys the array of keys to insert at <code>row,column</code>. Each key can be + * {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}. + * @return this builder. + * @throws {@link RuntimeException} if <code>row</code> or <code>column</code> is illegal. + */ + public ExpectedKeyboardBuilder insertKeysAtRow(final int row, final int column, + final Object ... keys) { + final ExpectedKey[] expectedKeys = joinKeys(keys); + for (int index = 0; index < keys.length; index++) { + setElementAt(row, column + index, expectedKeys[index], true /* insert */); + } + return this; + } + + /** + * Add the keys on the left most of the row. + * @param row the row number to add the <code>keys</code>. + * @param keys the array of keys to add on the left most of the row. Each key can be + * {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}. + * @return this builder. + * @throws {@link RuntimeException} if <code>row</code> is illegal. + */ + public ExpectedKeyboardBuilder addKeysOnTheLeftOfRow(final int row, + final Object ... keys) { + final ExpectedKey[] expectedKeys = joinKeys(keys); + // Keys should be inserted from the last to preserve the order. + for (int index = keys.length - 1; index >= 0; index--) { + setElementAt(row, 1, expectedKeys[index], true /* insert */); + } + return this; + } + + /** + * Add the keys on the right most of the row. + * @param row the row number to add the <code>keys</code>. + * @param keys the array of keys to add on the right most of the row. Each key can be + * {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}. + * @return this builder. + * @throws {@link RuntimeException} if <code>row</code> is illegal. + */ + public ExpectedKeyboardBuilder addKeysOnTheRightOfRow(final int row, + final Object ... keys) { + final int rightEnd = getRowAt(row).length + 1; + insertKeysAtRow(row, rightEnd, keys); + return this; + } + + /** + * Replace the most top-left key that has the specified label with the new keys. + * @param label the label of the key to set <code>newKeys</code>. + * @param newKeys the keys to be set. Each key can be {@link ExpectedKey}, {@link ExpectedKey} + * array, and {@link String}. + * @return this builder. + */ + public ExpectedKeyboardBuilder replaceKeyOfLabel(final String label, + final Object ... newKeys) { + final ExpectedKeyVisual visual = ExpectedKeyVisual.newInstance(label); + replaceKeyOf(visual, new ReplaceJob() { + @Override + public ExpectedKey[] replacingKeys(final ExpectedKey oldKey) { + return joinKeys(newKeys); + } + @Override + public boolean stopAtFirstOccurrence() { + return true; + } + }); + return this; + } + + /** + * Replace the all specified keys with the new keys. + * @param key the key to be replaced by <code>newKeys</code>. + * @param newKeys the keys to be set. Each key can be {@link ExpectedKey}, {@link ExpectedKey} + * array, and {@link String}. + * @return this builder. + */ + public ExpectedKeyboardBuilder replaceKeysOfAll(final ExpectedKey key, + final Object ... newKeys) { + replaceKeyOf(key.getVisual(), new ReplaceJob() { + @Override + public ExpectedKey[] replacingKeys(final ExpectedKey oldKey) { + return joinKeys(newKeys); + } + @Override + public boolean stopAtFirstOccurrence() { + return false; + } + }); + return this; + } + + /** + * Convert all keys of this keyboard builder to upper case keys. + * @param locale the locale used to convert cases. + * @return this builder + */ + public ExpectedKeyboardBuilder toUpperCase(final Locale locale) { + final int rowCount = getRowCount(); + for (int row = 1; row <= rowCount; row++) { + final ExpectedKey[] lowerCaseKeys = getRowAt(row); + final ExpectedKey[] upperCaseKeys = new ExpectedKey[lowerCaseKeys.length]; + for (int columnIndex = 0; columnIndex < lowerCaseKeys.length; columnIndex++) { + upperCaseKeys[columnIndex] = lowerCaseKeys[columnIndex].toUpperCase(locale); + } + setRowAt(row, upperCaseKeys); + } + return this; + } + + @Override + public String toString() { + return toString(build()); + } + + /** + * Convert the keyboard to human readable string. + * @param rows the keyboard to be converted to string. + * @return the human readable representation of <code>rows</code>. + */ + public static String toString(final ExpectedKey[][] rows) { + final StringBuilder sb = new StringBuilder(); + for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) { + if (rowIndex > 0) { + sb.append("\n"); + } + sb.append(Arrays.toString(rows[rowIndex])); + } + return sb.toString(); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishCustomizer.java new file mode 100644 index 000000000..29264ff3b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/EnglishCustomizer.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class EnglishCustomizer extends LayoutCustomizer { + EnglishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113") + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B") + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + .setMoreKeysOf("i", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC") + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + .setMoreKeysOf("o", + "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8", "\u014D", + "\u00F5") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + .setMoreKeysOf("s", "\u00DF") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + .setMoreKeysOf("c", "\u00E7") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + .setMoreKeysOf("n", "\u00F1"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/FrenchCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/FrenchCustomizer.java new file mode 100644 index 000000000..ab90267d0 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/FrenchCustomizer.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class FrenchCustomizer extends LayoutCustomizer { + FrenchCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setAdditionalMoreKeysPositionOf("a", 3) + .setMoreKeysOf("a", + "\u00E0", "\u00E2", "\u00E6", "\u00E1", "\u00E4", "\u00E3", "\u00E5", + "\u0101", "\u00AA") + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setAdditionalMoreKeysPositionOf("e", 5) + .setMoreKeysOf("e", + "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", "\u0113") + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FF") + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setAdditionalMoreKeysPositionOf("u", 3) + .setMoreKeysOf("u", "\u00F9", "\u00FB", "\u00FC", "\u00FA", "\u016B") + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setAdditionalMoreKeysPositionOf("i", 2) + .setMoreKeysOf("i", "\u00EE", "\u00EF", "\u00EC", "\u00ED", "\u012F", "\u012B") + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setAdditionalMoreKeysPositionOf("o", 3) + .setMoreKeysOf("o", + "\u00F4", "\u0153", "\u00F6", "\u00F2", "\u00F3", "\u00F5", "\u00F8", + "\u014D", "\u00BA") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D") + .setAdditionalMoreKeysPositionOf("c", 2); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/GermanCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/GermanCustomizer.java new file mode 100644 index 000000000..6d38937aa --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/GermanCustomizer.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class GermanCustomizer extends LayoutCustomizer { + public GermanCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + .setMoreKeysOf("e", "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0117") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B") + .setAdditionalMoreKeysPositionOf("u", 2) + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F6", "\u00F4", "\u00F2", "\u00F3", "\u00F5", "\u0153", "\u00F8", + "\u014D") + .setAdditionalMoreKeysPositionOf("o", 2) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E4", "\u00E2", "\u00E0", "\u00E1", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + .setAdditionalMoreKeysPositionOf("a", 2) + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u00DF", "\u015B", "\u0161") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/ItalianCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/ItalianCustomizer.java new file mode 100644 index 000000000..735070946 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/ItalianCustomizer.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class ItalianCustomizer extends LayoutCustomizer { + public ItalianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0119", "\u0117", "\u0113") + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00F9", "\u00FA", "\u00FB", "\u00FC", "\u016B") + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00EC", "\u00ED", "\u00EE", "\u00EF", "\u012F", "\u012B") + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F2", "\u00F3", "\u00F4", "\u00F6", "\u00F5", "\u0153", "\u00F8", + "\u014D", "\u00BA") + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101", "\u00AA"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java new file mode 100644 index 000000000..4002c49c2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.util.Log; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; +import com.android.inputmethod.keyboard.KeyboardLayoutSetTestsBase; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ActualKeyboardBuilder; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.Arrays; + +/** + * Base class for keyboard layout unit test. + */ +abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase { + private LayoutBase mLayout; + private InputMethodSubtype mSubtype; + private String mLogTag; + private KeyboardLayoutSet mKeyboardLayoutSet; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mLayout = getLayout(); + mSubtype = getSubtype(mLayout.getLocale(), mLayout.getName()); + mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/" + + (isPhone() ? "phone" : "tablet"); + mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */); + } + + // Those helper methods have a lower case name to be readable when defining expected keyboard + // layouts. + + // Helper method to create an {@link ExpectedKey} object that has the label. + static ExpectedKey key(final String label, final ExpectedKey ... moreKeys) { + return AbstractLayoutBase.key(label, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has the label and the output text. + static ExpectedKey key(final String label, final String outputText, + final ExpectedKey ... moreKeys) { + return AbstractLayoutBase.key(label, outputText, moreKeys); + } + + // Helper method to create an {@link ExpectedKey} object that has new "more keys". + static ExpectedKey key(final ExpectedKey key, final ExpectedKey ... moreKeys) { + return AbstractLayoutBase.key(key, moreKeys); + } + + // Helper method to create an {@link ExpectedAdditionalMoreKey} object for an + // "additional more key" that has the label. + public static ExpectedAdditionalMoreKey additionalMoreKey(final String label) { + return AbstractLayoutBase.additionalMoreKey(label); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label. + static ExpectedKey moreKey(final String label) { + return AbstractLayoutBase.moreKey(label); + } + + // Helper method to create an {@link ExpectedKey} object for a "more key" that has the label + // and the output text. + static ExpectedKey moreKey(final String label, final String outputText) { + return AbstractLayoutBase.moreKey(label, outputText); + } + + // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, + // {@link ExpectedKey} array, and {@link String}. + static ExpectedKey[] joinMoreKeys(final Object ... moreKeys) { + return AbstractLayoutBase.joinKeys(moreKeys); + } + + // Helper method to create {@link ExpectedKey} array by joining {@link ExpectedKey}, + // {@link ExpectedKey} array, and {@link String}. + static ExpectedKey[] joinKeys(final Object ... keys) { + return AbstractLayoutBase.joinKeys(keys); + } + + // Keyboard layout for testing subtype. + abstract LayoutBase getLayout(); + + ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder; + } + + // TODO: Add phone, phone symbols, number, number password layout tests. + + public final void testAlphabet() { + doKeyboardTests(KeyboardId.ELEMENT_ALPHABET); + } + + public final void testAlphabetAutomaticShifted() { + doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED); + } + + public final void testAlphabetManualShifted() { + doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED); + } + + public final void testAlphabetShiftLocked() { + doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED); + } + + public final void testAlphabetShiftLockShifted() { + doKeyboardTests(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED); + } + + public final void testSymbols() { + doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS); + } + + public final void testSymbolsShifted() { + doKeyboardTests(KeyboardId.ELEMENT_SYMBOLS_SHIFTED); + } + + // Comparing expected keyboard and actual keyboard. + private void doKeyboardTests(final int elementId) { + final ExpectedKey[][] expectedKeyboard = mLayout.getLayout(isPhone(), elementId); + // Skip test if no keyboard is defined. + if (expectedKeyboard == null) { + return; + } + final String tag = mLogTag + "/" + KeyboardId.elementIdToName(elementId); + // Create actual keyboard object. + final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(elementId); + // Create actual keyboard to be compared with the expected keyboard. + final Key[][] actualKeyboard = ActualKeyboardBuilder.buildKeyboard( + keyboard.getSortedKeys()); + + // Dump human readable definition of expected/actual keyboards. + Log.d(tag, "expected=\n" + ExpectedKeyboardBuilder.toString(expectedKeyboard)); + Log.d(tag, "actual =\n" + ActualKeyboardBuilder.toString(actualKeyboard)); + // Test both keyboards have the same number of rows. + assertEquals(tag + " labels" + + "\nexpected=" + ExpectedKeyboardBuilder.toString(expectedKeyboard) + + "\nactual =" + ActualKeyboardBuilder.toString(actualKeyboard), + expectedKeyboard.length, actualKeyboard.length); + for (int r = 0; r < actualKeyboard.length; r++) { + final int row = r + 1; + // Test both keyboards' rows have the same number of columns. + assertEquals(tag + " labels row=" + row + + "\nexpected=" + Arrays.toString(expectedKeyboard[r]) + + "\nactual =" + ActualKeyboardBuilder.toString(actualKeyboard[r]), + expectedKeyboard[r].length, actualKeyboard[r].length); + for (int c = 0; c < actualKeyboard[r].length; c++) { + final int column = c + 1; + final Key actualKey = actualKeyboard[r][c]; + final ExpectedKey expectedKey = expectedKeyboard[r][c]; + // Test both keyboards' keys have the same visual outlook and key output. + assertTrue(tag + " labels row,column=" + row + "," + column + + "\nexpected=" + expectedKey + + "\nactual =" + ActualKeyboardBuilder.toString(actualKey), + expectedKey.equalsTo(actualKey)); + } + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/NoLanguageCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/NoLanguageCustomizer.java new file mode 100644 index 000000000..9edbcab69 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/NoLanguageCustomizer.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class NoLanguageCustomizer extends LayoutCustomizer { + NoLanguageCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + .setMoreKeysOf("w", "\u0175") + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0115: "ĕ" LATIN SMALL LETTER E WITH BREVE + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + .setMoreKeysOf("e", + "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113", "\u0115", "\u0117", + "\u0119", "\u011B") + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + .setMoreKeysOf("r", "\u0155", "\u0157", "\u0159") + // U+00FE: "þ" LATIN SMALL LETTER THORN + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE + .setMoreKeysOf("t", "\u00FE", "\u0163", "\u0165", "\u0167") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("y", "\u00FD", "\u0177", "\u00FF", "\u0133") + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + .setMoreKeysOf("u", + "\u00F9", "\u00FA", "\u00FB", "\u00FC", "\u0169", "\u016B", "\u016D", + "\u016F", "\u0171", "\u0173") + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012D: "ĭ" LATIN SMALL LETTER I WITH BREVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("i", + "\u00EC", "\u00ED", "\u00EE", "\u00EF", "\u0129", "\u012B", "\u012D", + "\u012F", "\u0131", "\u0133") + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+014F: "ŏ" LATIN SMALL LETTER O WITH BREVE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F2", "\u00F3", "\u00F4", "\u00F5", "\u00F6", "\u00F8", "\u014D", + "\u014F", "\u0151", "\u0153", "\u00BA") + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u00E4", "\u00E5", "\u00E6", + "\u0101", "\u0103", "\u0105", "\u00AA") + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+017F: "ſ" LATIN SMALL LETTER LONG S + .setMoreKeysOf("s", "\u00DF", "\u015B", "\u015D", "\u015F", "\u0161", "\u017F") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + // U+00F0: "ð" LATIN SMALL LETTER ETH + .setMoreKeysOf("d", "\u010F", "\u0111", "\u00F0") + // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + .setMoreKeysOf("g", "\u011D", "\u011F", "\u0121", "\u0123") + // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX + .setMoreKeysOf("h", "\u0125") + // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX + .setMoreKeysOf("j", "\u0135") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + // U+0138: "ĸ" LATIN SMALL LETTER KRA + .setMoreKeysOf("k", "\u0137", "\u0138") + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u013A", "\u013C", "\u013E", "\u0140", "\u0142") + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + .setMoreKeysOf("z", "\u017A", "\u017C", "\u017E") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX + // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u0109", "\u010B", "\u010D") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + // U+014B: "ŋ" LATIN SMALL LETTER ENG + .setMoreKeysOf("n", "\u00F1", "\u0144", "\u0146", "\u0148", "\u0149", "\u014B"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/PortugueseCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/PortugueseCustomizer.java new file mode 100644 index 000000000..629e8cb8b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/PortugueseCustomizer.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class PortugueseCustomizer extends LayoutCustomizer { + PortugueseCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + .setMoreKeysOf("e", + "\u00E9", "\u00EA", "\u00E8", "\u0119", "\u0117", "\u0113", "\u00EB") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00F9", "\u00FB", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EE", "\u00EC", "\u00EF", "\u012F", "\u012B") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F3", "\u00F5", "\u00F4", "\u00F2", "\u00F6", "\u0153", "\u00F8", + "\u014D", "\u00BA") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E1", "\u00E3", "\u00E0", "\u00E2", "\u00E4", "\u00E5", "\u00E6", + "\u00AA") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u00E7", "\u010D", "\u0107"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/SpanishCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/SpanishCustomizer.java new file mode 100644 index 000000000..8974ad6ec --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/SpanishCustomizer.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.AbstractLayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +class SpanishCustomizer extends LayoutCustomizer { + SpanishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? PHONE_PUNCTUATION_MORE_KEYS + : LayoutBase.TABLET_PUNCTUATION_MORE_KEYS; + } + + // Punctuation more keys for phone form factor. + private static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = AbstractLayoutBase.joinKeys( + // U+00A1: "¡" INVERTED EXCLAMATION MARK + // U+00BF: "¿" INVERTED QUESTION MARK + ",", "?", "!", "#", ")", "(", "/", ";", "\u00A1", + "'", "@", ":", "-", "\"", "+", "%", "&", "\u00BF"); + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00E8", "\u00EB", "\u00EA", "\u0119", "\u0117", "\u0113") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00F9", "\u00FB", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EF", "\u00EC", "\u00EE", "\u012F", "\u012B") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F3", "\u00F2", "\u00F6", "\u00F4", "\u00F5", "\u00F8", "\u0153", + "\u014D", "\u00BA") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E1", "\u00E0", "\u00E4", "\u00E2", "\u00E3", "\u00E5", "\u0105", + "\u00E6", "\u0101", "\u00AA") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + .replaceKeyOfLabel(Spanish.ROW2_10, "\u00F1") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAfrikaans.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAfrikaans.java new file mode 100644 index 000000000..cd2259888 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAfrikaans.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * af: TestsAfrikaans/qwerty + */ +@SmallTest +public final class TestsAfrikaans extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("af"); + private static final LayoutBase LAYOUT = new Qwerty(new AfrikaansCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class AfrikaansCustomizer extends LayoutCustomizer { + AfrikaansCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", "\u0113") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FB", "\u00FC", "\u00F9", "\u016B") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("y", "\u00FD", "\u0133") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("i", + "\u00ED", "\u00EC", "\u00EF", "\u00EE", "\u012F", "\u012B", "\u0133") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F4", "\u00F6", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E1", "\u00E2", "\u00E4", "\u00E0", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArabic.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArabic.java new file mode 100644 index 000000000..fd7670827 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArabic.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Arabic; +import com.android.inputmethod.keyboard.layout.Arabic.ArabicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * ar: Arabic/arabic + */ +@SmallTest +public class TestsArabic extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ar"); + private static final LayoutBase LAYOUT = new Arabic(new ArabicCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArmenianAMPhonetic.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArmenianAMPhonetic.java new file mode 100644 index 000000000..327e9438f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsArmenianAMPhonetic.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.ArmenianPhonetic; +import com.android.inputmethod.keyboard.layout.ArmenianPhonetic.ArmenianPhoneticCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic + */ +@SmallTest +public final class TestsArmenianAMPhonetic extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("hy", "AM"); + private static final LayoutBase LAYOUT = new ArmenianPhonetic( + new ArmenianPhoneticCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAzerbaijaniAZ.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAzerbaijaniAZ.java new file mode 100644 index 000000000..f5317e269 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsAzerbaijaniAZ.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * az_AZ: Azerbaijani (Azerbaijan)/qwerty + */ +@SmallTest +public final class TestsAzerbaijaniAZ extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("az", "AZ"); + private static final LayoutBase LAYOUT = new Qwerty(new AzerbaijaniAZCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static final class AzerbaijaniAZCustomizer extends LayoutCustomizer { + public AzerbaijaniAZCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0259: "ə" LATIN SMALL LETTER SCHWA + .setMoreKeysOf("e", "\u0259") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B") + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", + "\u0131", "\u00EE", "\u00EF", "\u00EC", "\u00ED", "\u012F", "\u012B") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F6", "\u00F4", "\u0153", "\u00F2", "\u00F3", "\u00F5", "\u00F8", + "\u014D") + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + .setMoreKeysOf("a", "\u00E2") + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u015F", "\u00DF", "\u015B", "\u0161") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D") + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u011F"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBasqueES.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBasqueES.java new file mode 100644 index 000000000..bef18c5d5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBasqueES.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * eu_ES: Basque (Spain)/spanish + */ +@SmallTest +public class TestsBasqueES extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("eu", "ES"); + private static final LayoutBase LAYOUT = new Spanish(new BasqueESCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class BasqueESCustomizer extends EuroCustomizer { + private final SpanishCustomizer mSpanishCustomizer; + + public BasqueESCustomizer(final Locale locale) { + super(locale); + mSpanishCustomizer = new SpanishCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mSpanishCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBelarusianBY.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBelarusianBY.java new file mode 100644 index 000000000..c5238d54f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBelarusianBY.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.EastSlavic; +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * be_BY: Belarusian (Belarus)/east_slavic + */ +@SmallTest +public final class TestsBelarusianBY extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("be", "BY"); + private static final LayoutBase LAYOUT = new EastSlavic(new BelarusianBYCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class BelarusianBYCustomizer extends EastSlavicCustomizer { + public BelarusianBYCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { + return Symbols.DOUBLE_QUOTES_R9L; + } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { + return Symbols.SINGLE_QUOTES_R9L; + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0451: "ё" CYRILLIC SMALL LETTER IO + .setMoreKeysOf("\u0435", "\u0451") + // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U + .replaceKeyOfLabel(EastSlavic.ROW1_9, key("\u045E", additionalMoreKey("9"))) + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + .replaceKeyOfLabel(EastSlavic.ROW2_2, "\u044B") + // U+044D: "э" CYRILLIC SMALL LETTER E + .replaceKeyOfLabel(EastSlavic.ROW2_11, "\u044D") + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + .replaceKeyOfLabel(EastSlavic.ROW3_5, "\u0456") + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + .setMoreKeysOf("\u044C", "\u044A"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarian.java new file mode 100644 index 000000000..ded8d7243 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarian.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Bulgarian; +import com.android.inputmethod.keyboard.layout.Bulgarian.BulgarianCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * bg: TestsBulgarian/bulgarian + */ +@SmallTest +public final class TestsBulgarian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("bg"); + private static final LayoutBase LAYOUT = new Bulgarian(new BulgarianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarianBds.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarianBds.java new file mode 100644 index 000000000..22b2011ee --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBulgarianBds.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.BulgarianBds; +import com.android.inputmethod.keyboard.layout.BulgarianBds.BulgarianBdsCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * bg: Bulgarian/bulgarian_bds + */ +@SmallTest +public final class TestsBulgarianBds extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("bg"); + private static final LayoutBase LAYOUT = new BulgarianBds(new BulgarianBdsCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCatalan.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCatalan.java new file mode 100644 index 000000000..151a0a627 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCatalan.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * ca: Catalan/spanish + */ +@SmallTest +public class TestsCatalan extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ca"); + private static final LayoutBase LAYOUT = new Spanish(new CatalanCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class CatalanCustomizer extends EuroCustomizer { + public CatalanCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? PHONE_PUNCTUATION_MORE_KEYS + : TABLET_PUNCTUATION_MORE_KEYS; + } + + // U+00B7: "·" MIDDLE DOT + private static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "?", "!", "\u00B7", "#", ")", "(", "/", ";", + "'", "@", ":", "-", "\"", "+", "%", "&"); + + private static final ExpectedKey[] TABLET_PUNCTUATION_MORE_KEYS = joinKeys( + ",", "'", "\u00B7", "#", ")", "(", "/", ";", + "@", ":", "-", "\"", "+", "%", "&"); + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E8", "\u00E9", "\u00EB", "\u00EA", "\u0119", "\u0117", "\u0113") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00F9", "\u00FB", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EF", "\u00EC", "\u00EE", "\u012F", "\u012B") + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F2", "\u00F3", "\u00F6", "\u00F4", "\u00F5", "\u00F8", "\u0153", + "\u014D", "\u00BA") + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u00E4", "\u00E2", "\u00E3", "\u00E5", "\u0105", + "\u00E6", "\u0101", "\u00AA") + // U+00B7: "·" MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "l\u00B7l", "\u0142") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + .replaceKeyOfLabel(Spanish.ROW2_10, "\u00E7") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCroatian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCroatian.java new file mode 100644 index 000000000..8575ef219 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCroatian.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwertz; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * hr: Croatian/qwertz + */ +@SmallTest +public final class TestsCroatian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("hr"); + private static final LayoutBase LAYOUT = new Qwertz(new CroatianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class CroatianCustomizer extends LayoutCustomizer { + public CroatianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + .setMoreKeysOf("z", "\u017E", "\u017A", "\u017C") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + .setMoreKeysOf("s", "\u0161", "\u015B", "\u00DF") + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + .setMoreKeysOf("d", "\u0111") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + .setMoreKeysOf("c", "\u010D", "\u0107", "\u00E7") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCzech.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCzech.java new file mode 100644 index 000000000..f4794707f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsCzech.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwertz; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * cs: Czech/qwertz + */ +@SmallTest +public final class TestsCzech extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("cs"); + private static final LayoutBase LAYOUT = new Qwertz(new CzechCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class CzechCustomizer extends LayoutCustomizer { + public CzechCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u011B", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", + "\u0113") + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + .setMoreKeysOf("r", "\u0159") + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + .setMoreKeysOf("t", "\u0165") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + .setMoreKeysOf("z", "\u017E", "\u017A", "\u017C") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u016F", "\u00FB", "\u00FC", "\u00F9", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EE", "\u00EF", "\u00EC", "\u012F", "\u012B") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E1", "\u00E0", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u010F") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107") + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u0148", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanish.java new file mode 100644 index 000000000..85c63a128 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanish.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Nordic; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * da: Danish/nordic + */ +@SmallTest +public final class TestsDanish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("da"); + private static final LayoutBase LAYOUT = new Nordic(new DanishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class DanishCustomizer extends EuroCustomizer { + public DanishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + .setMoreKeysOf("e", "\u00E9", "\u00EB") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00FB", "\u00F9", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + .setMoreKeysOf("i", "\u00ED", "\u00EF") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", "\u00F3", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u014D") + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + .replaceKeyOfLabel(Nordic.ROW1_11, "\u00E5") + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW2_10, key("\u00E6", moreKey("\u00E4"))) + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW2_11, key("\u00F8", moreKey("\u00F6"))) + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", "\u00E1", "\u00E4", "\u00E0", "\u00E2", "\u00E3", "\u0101") + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u00DF", "\u015B", "\u0161") + // U+00F0: "ð" LATIN SMALL LETTER ETH + .setMoreKeysOf("d", "\u00F0") + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u0142") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutch.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutch.java new file mode 100644 index 000000000..1730f66be --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutch.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * nl: Dutch/qwerty + */ +@SmallTest +public final class TestsDutch extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("nl"); + private static final LayoutBase LAYOUT = new Qwerty(new DutchCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + static class DutchCustomizer extends EuroCustomizer { + public DutchCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E1", "\u00E4", "\u00E2", "\u00E0", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00EB", "\u00EA", "\u00E8", "\u0119", "\u0117", "\u0113") + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("y", "\u0133") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00FB", "\u00F9", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("i", + "\u00ED", "\u00EF", "\u00EC", "\u00EE", "\u012F", "\u012B", "\u0133") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutchBE.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutchBE.java new file mode 100644 index 000000000..31adf7a8d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDutchBE.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Azerty; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.tests.TestsDutch.DutchCustomizer; + +import java.util.Locale; + +/** + * nl_BE: Dutch (Belgium)/azerty + */ +@SmallTest +public final class TestsDutchBE extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("nl", "BE"); + private static final LayoutBase LAYOUT = new Azerty(new DutchCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java new file mode 100644 index 000000000..a05269312 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Dvorak; +import com.android.inputmethod.keyboard.layout.Dvorak.DvorakCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * en_US: English (United States)/dvorak + */ +@SmallTest +public class TestsEnglishDvorak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("en", "US"); + private static final LayoutBase LAYOUT = new Dvorak(new EnglishDvorakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class EnglishDvorakCustomizer extends DvorakCustomizer { + private final EnglishCustomizer mEnglishCustomizer; + + EnglishDvorakCustomizer(final Locale locale) { + super(locale); + mEnglishCustomizer = new EnglishCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mEnglishCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishIN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishIN.java new file mode 100644 index 000000000..c80b25024 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishIN.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/* + * en_IN: English (India)/qwerty + */ +@SmallTest +public final class TestsEnglishIN extends TestsEnglishUS { + private static final Locale LOCALE = new Locale("en", "IN"); + private static final LayoutBase LAYOUT = new Qwerty(new EnglishINCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class EnglishINCustomizer extends EnglishCustomizer { + public EnglishINCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + // U+20B9: "₹" INDIAN RUPEE SIGN + private static final ExpectedKey CURRENCY_RUPEE = key("\u20B9", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUK.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUK.java new file mode 100644 index 000000000..c0dcbdc06 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUK.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/* + * en_GB: English (Great Britain)/qwerty + */ +@SmallTest +public final class TestsEnglishUK extends TestsEnglishUS { + private static final Locale LOCALE = new Locale("en", "GB"); + private static final LayoutBase LAYOUT = new Qwerty(new EnglishUKCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class EnglishUKCustomizer extends EnglishCustomizer { + public EnglishUKCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_POUND; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { return CURRENCIES_OTHER_THAN_POUND; } + + private static final ExpectedKey CURRENCY_POUND = key(Symbols.POUND_SIGN, + Symbols.CENT_SIGN, Symbols.DOLLAR_SIGN, Symbols.EURO_SIGN, Symbols.YEN_SIGN, + Symbols.PESO_SIGN); + + private static final ExpectedKey[] CURRENCIES_OTHER_THAN_POUND = { + Symbols.EURO_SIGN, Symbols.YEN_SIGN, key(Symbols.DOLLAR_SIGN, Symbols.CENT_SIGN), + Symbols.CENT_SIGN + }; + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java new file mode 100644 index 000000000..6ea8f6000 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishUS.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * en_US: English (United States)/qwerty + */ +@SmallTest +public class TestsEnglishUS extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("en", "US"); + private static final LayoutBase LAYOUT = new Qwerty(new EnglishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEsperanto.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEsperanto.java new file mode 100644 index 000000000..6a44187c9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEsperanto.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * eo: Esperanto/spanish + */ +@SmallTest +public class TestsEsperanto extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("eo"); + private static final LayoutBase LAYOUT = new Spanish(new EsperantoCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class EsperantoCustomizer extends LayoutCustomizer { + public EsperantoCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX + .replaceKeyOfLabel("q", key("\u015D", joinMoreKeys( + additionalMoreKey("1"), "q"))) + // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + .replaceKeyOfLabel("w", key("\u011D", joinMoreKeys( + additionalMoreKey("2"), "w", "\u0175"))) + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u011B", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", + "\u0113") + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + .setMoreKeysOf("r", "\u0159", "\u0155", "\u0157") + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE + .setMoreKeysOf("t", "\u0165", "\u021B", "\u0163", "\u0167") + // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + // U+00FE: "þ" LATIN SMALL LETTER THORN + .replaceKeyOfLabel("y", key("\u016D", joinMoreKeys( + additionalMoreKey("6"), "y", "\u00FD", "\u0177", "\u00FF", "\u00FE"))) + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00B5: "µ" MICRO SIGN + .setMoreKeysOf("u", + "\u00FA", "\u016F", "\u00FB", "\u00FC", "\u00F9", "\u016B", "\u0169", + "\u0171", "\u0173", "\u00B5") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+0133: "ij" LATIN SMALL LIGATURE IJ + .setMoreKeysOf("i", + "\u00ED", "\u00EE", "\u00EF", "\u0129", "\u00EC", "\u012F", "\u012B", + "\u0131", "\u0133") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00BA: "º" MASCULINE ORDINAL INDICATOR + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D", "\u0151", "\u00BA") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00AA: "ª" FEMININE ORDINAL INDICATOR + .setMoreKeysOf("a", + "\u00E1", "\u00E0", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101", "\u0103", "\u0105", "\u00AA") + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + .setMoreKeysOf("s", "\u00DF", "\u0161", "\u015B", "\u0219", "\u015F") + // U+00F0: "ð" LATIN SMALL LETTER ETH + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + .setMoreKeysOf("d", "\u00F0", "\u010F", "\u0111") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + // U+014B: "ŋ" LATIN SMALL LETTER ENG + .setMoreKeysOf("n", "\u00F1", "\u0144", "\u0146", "\u0148", "\u0149", "\u014B") + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + .setMoreKeysOf("g", "\u011F", "\u0121", "\u0123") + // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX + // U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE + .setMoreKeysOf("h", "\u0125", "\u0127") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + // U+0138: "ĸ" LATIN SMALL LETTER KRA + .setMoreKeysOf("k", "\u0137", "\u0138") + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u013A", "\u013C", "\u013E", "\u0140", "\u0142") + // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX + .replaceKeyOfLabel(Spanish.ROW2_10, "\u0135") + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + .setMoreKeysOf("z", "\u017A", "\u017C", "\u017E") + // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX + .replaceKeyOfLabel("x", key("\u0109", moreKey("x"))) + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE + .setMoreKeysOf("c", "\u0107", "\u010D", "\u00E7", "\u010B") + // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX + .setMoreKeysOf("v", "w", "\u0175"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java new file mode 100644 index 000000000..865e9ea17 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Nordic; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * et_EE: Estonian (Estonia)/nordic + */ +@SmallTest +public final class TestsEstonianEE extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("et", "EE"); + private static final LayoutBase LAYOUT = new Nordic(new EstonianEECustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class EstonianEECustomizer extends EuroCustomizer { + public EstonianEECustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + .setMoreKeysOf("e", + "\u0113", "\u00E8", "\u0117", "\u00E9", "\u00EA", "\u00EB", "\u0119", + "\u011B") + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + .setMoreKeysOf("r", "\u0157", "\u0159", "\u0155") + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + .setMoreKeysOf("t", "\u0163", "\u0165") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + .setMoreKeysOf("u", + "\u00FC", "\u016B", "\u0173", "\u00F9", "\u00FA", "\u00FB", "\u016F", + "\u0171") + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + .setMoreKeysOf("i", + "\u012B", "\u00EC", "\u012F", "\u00ED", "\u00EE", "\u00EF", "\u0131") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + .setMoreKeysOf("o", + "\u00F6", "\u00F5", "\u00F2", "\u00F3", "\u00F4", "\u0153", "\u0151", + "\u00F8") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW1_11, "\u00FC") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + .replaceKeyOfLabel(Nordic.ROW2_10, key("\u00F6", moreKey("\u00F5"))) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW2_11, "\u00E4") + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + .setMoreKeysOf("a", + "\u00E4", "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u00E5", + "\u00E6", "\u0105") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u010F") + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u0123", "\u011F") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + .setMoreKeysOf("k", "\u0137") + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + .setMoreKeysOf("l", "\u013C", "\u0142", "\u013A", "\u013E") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107") + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u0146", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnish.java new file mode 100644 index 000000000..ff32da117 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnish.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Nordic; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * fi: Finnish/nordic + */ +@SmallTest +public final class TestsFinnish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fi"); + private static final LayoutBase LAYOUT = new Nordic(new FinnishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class FinnishCustomizer extends EuroCustomizer { + public FinnishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + .setMoreKeysOf("u", "\u00FC") + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F8", "\u00F4", "\u00F2", "\u00F3", "\u00F5", "\u0153", "\u014D") + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + .replaceKeyOfLabel(Nordic.ROW1_11, "\u00E5") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + .replaceKeyOfLabel(Nordic.ROW2_10, key("\u00F6", moreKey("\u00F8"))) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + .replaceKeyOfLabel(Nordic.ROW2_11, key("\u00E4", moreKey("\u00E6"))) + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", "\u00E6", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u0101") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + .setMoreKeysOf("z", "\u017E", "\u017A", "\u017C"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrench.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrench.java new file mode 100644 index 000000000..7ced1fb7b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrench.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Azerty; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/** + * fr: French/azerty + */ +@SmallTest +public final class TestsFrench extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fr"); + private static final LayoutBase LAYOUT = new Azerty(new FrenchEuroCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + static final class FrenchEuroCustomizer extends FrenchCustomizer { + private final EuroCustomizer mEuroCustomizer; + + public FrenchEuroCustomizer(final Locale locale) { + super(locale); + mEuroCustomizer = new EuroCustomizer(locale); + } + + @Override + public final ExpectedKey getCurrencyKey() { return mEuroCustomizer.getCurrencyKey(); } + + @Override + public final ExpectedKey[] getOtherCurrencyKeys() { + return mEuroCustomizer.getOtherCurrencyKeys(); + } + } +}
\ No newline at end of file diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCA.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCA.java new file mode 100644 index 000000000..9b3cd1ee2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCA.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * fr_CA: French (Canada)/qwerty + */ +@SmallTest +public final class TestsFrenchCA extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fr", "CA"); + private static final LayoutBase LAYOUT = new Qwerty(new FrenchCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCH.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCH.java new file mode 100644 index 000000000..2598aa3bf --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchCH.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Swiss; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * fr_CH: French (Switzerland)/swiss + */ +@SmallTest +public final class TestsFrenchCH extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fr", "CH"); + private static final LayoutBase LAYOUT = new Swiss(new FrenchCHCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class FrenchCHCustomizer extends FrenchCustomizer { + public FrenchCHCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + super.setAccentedLetters(builder); + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + .replaceKeyOfLabel(Swiss.ROW1_11, key("\u00E8", moreKey("\u00FC"))) + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + .replaceKeyOfLabel(Swiss.ROW2_10, key("\u00E9", moreKey("\u00F6"))) + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + .replaceKeyOfLabel(Swiss.ROW2_11, key("\u00E0", moreKey("\u00E4"))); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchDvorak.java new file mode 100644 index 000000000..33d1445a4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchDvorak.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Dvorak; +import com.android.inputmethod.keyboard.layout.Dvorak.DvorakCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; +import com.android.inputmethod.keyboard.layout.tests.TestsFrench.FrenchEuroCustomizer; + +import java.util.Locale; + +/** + * fr: French/dvorak + */ +@SmallTest +public final class TestsFrenchDvorak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fr"); + private static final LayoutBase LAYOUT = new Dvorak(new FrenchDvorakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class FrenchDvorakCustomizer extends DvorakCustomizer { + private final FrenchEuroCustomizer mFrenchEuroCustomizer; + + public FrenchDvorakCustomizer(final Locale locale) { + super(locale); + mFrenchEuroCustomizer = new FrenchEuroCustomizer(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return mFrenchEuroCustomizer.getCurrencyKey(); } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return mFrenchEuroCustomizer.getOtherCurrencyKeys(); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mFrenchEuroCustomizer.setAccentedLetters(builder); + } + } +}
\ No newline at end of file diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchQwertz.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchQwertz.java new file mode 100644 index 000000000..6ab28704a --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFrenchQwertz.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwertz; +import com.android.inputmethod.keyboard.layout.tests.TestsFrench.FrenchEuroCustomizer; + +import java.util.Locale; + +/** + * fr: French/qwertz + */ +@SmallTest +public final class TestsFrenchQwertz extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fr"); + private static final LayoutBase LAYOUT = new Qwertz(new FrenchEuroCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGalicianES.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGalicianES.java new file mode 100644 index 000000000..1472828a4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGalicianES.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * gl_ES: Galician (Spain)/spanish + */ +@SmallTest +public class TestsGalicianES extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("gl", "ES"); + private static final LayoutBase LAYOUT = new Spanish(new GalicianESCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class GalicianESCustomizer extends EuroCustomizer { + private final SpanishCustomizer mSpanishCustomizer; + + public GalicianESCustomizer(final Locale locale) { + super(locale); + mSpanishCustomizer = new SpanishCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mSpanishCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGeorgianGE.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGeorgianGE.java new file mode 100644 index 000000000..f25942fb5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGeorgianGE.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Georgian; +import com.android.inputmethod.keyboard.layout.Georgian.GeorgianCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * ka_GE: Georgian (Georgia)/georgian + */ +@SmallTest +public final class TestsGeorgianGE extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ka", "GE"); + private static final LayoutBase LAYOUT = new Georgian(new GeorgianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGerman.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGerman.java new file mode 100644 index 000000000..6f7571197 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGerman.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwertz; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/** + * de: German/qwertz + */ +@SmallTest +public final class TestsGerman extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("de"); + private static final LayoutBase LAYOUT = new Qwertz(new GermanEuroCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + static class GermanEuroCustomizer extends GermanCustomizer { + final EuroCustomizer mEuroCustomizer; + + public GermanEuroCustomizer(final Locale locale) { + super(locale); + mEuroCustomizer = new EuroCustomizer(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return mEuroCustomizer.getCurrencyKey(); } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return mEuroCustomizer.getOtherCurrencyKeys(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanCH.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanCH.java new file mode 100644 index 000000000..7deb00bb4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanCH.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Swiss; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * de_CH: German (Switzerland)/swiss + */ +@SmallTest +public final class TestsGermanCH extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("de", "CH"); + private static final LayoutBase LAYOUT = new Swiss(new GermanCHCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class GermanCHCustomizer extends GermanCustomizer { + public GermanCHCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + super.setAccentedLetters(builder); + return builder + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + .replaceKeyOfLabel(Swiss.ROW1_11, key("\u00FC", moreKey("\u00E8"))) + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + .replaceKeyOfLabel(Swiss.ROW2_10, key("\u00F6", moreKey("\u00E9"))) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + .replaceKeyOfLabel(Swiss.ROW2_11, key("\u00E4", moreKey("\u00E0"))); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanDvorak.java new file mode 100644 index 000000000..b28d5cfcf --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanDvorak.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Dvorak; +import com.android.inputmethod.keyboard.layout.Dvorak.DvorakCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * de: German/dvorak + */ +@SmallTest +public final class TestsGermanDvorak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("de"); + private static final LayoutBase LAYOUT = new Dvorak(new GermanDvorakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + static class GermanDvorakCustomizer extends DvorakCustomizer { + final GermanCustomizer mGermanCustomizer; + + public GermanDvorakCustomizer(final Locale locale) { + super(locale); + mGermanCustomizer = new GermanCustomizer(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return Symbols.CURRENCY_EURO; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_THAN_EURO; + } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mGermanCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanQwerty.java new file mode 100644 index 000000000..19ae5a3f5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGermanQwerty.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.tests.TestsGerman.GermanEuroCustomizer; + +import java.util.Locale; + +/** + * de: German/qwerty + */ +@SmallTest +public final class TestsGermanQwerty extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("de"); + private static final LayoutBase LAYOUT = new Qwerty(new GermanEuroCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGreek.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGreek.java new file mode 100644 index 000000000..4acb119ac --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsGreek.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Greek; +import com.android.inputmethod.keyboard.layout.Greek.GreekCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * el: Greek/greek + */ +@SmallTest +public class TestsGreek extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("el"); + private static final LayoutBase LAYOUT = new Greek(new GreekCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHebrew.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHebrew.java new file mode 100644 index 000000000..c0243a870 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHebrew.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Hebrew; +import com.android.inputmethod.keyboard.layout.Hebrew.HebrewCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * iw: Hebrew/hebrew + */ +@SmallTest +public class TestsHebrew extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("iw"); + private static final LayoutBase LAYOUT = new Hebrew(new HebrewCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindi.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindi.java new file mode 100644 index 000000000..84053b5be --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindi.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Hindi; +import com.android.inputmethod.keyboard.layout.Hindi.HindiCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * hi: Hindi/hindi + */ +@SmallTest +public final class TestsHindi extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("hi"); + private static final LayoutBase LAYOUT = new Hindi(new HindiCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java new file mode 100644 index 000000000..2e676df26 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.HindiCompact; +import com.android.inputmethod.keyboard.layout.HindiCompact.HindiCompactCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * hi: Hindi/hindi_compact + */ +@SmallTest +public final class TestsHindiCompact extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("hi"); + private static final LayoutBase LAYOUT = new HindiCompact(new HindiCompactCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHungarian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHungarian.java new file mode 100644 index 000000000..efc95dcf9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHungarian.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwertz; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * hu: Hungarian/qwertz + */ +@SmallTest +public final class TestsHungarian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("hu"); + private static final LayoutBase LAYOUT = new Qwertz(new HungarianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class HungarianCustomizer extends LayoutCustomizer { + public HungarianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", "\u0113") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u0171", "\u00FB", "\u00F9", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EE", "\u00EF", "\u00EC", "\u012F", "\u012B") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u0151", "\u00F4", "\u00F2", "\u00F5", "\u0153", + "\u00F8", "\u014D") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E1", "\u00E0", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIcelandic.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIcelandic.java new file mode 100644 index 000000000..62b111e6a --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIcelandic.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * is: Icelandic/qwerty + */ +@SmallTest +public final class TestsIcelandic extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("is"); + private static final LayoutBase LAYOUT = new Qwerty(new IcelandicCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class IcelandicCustomizer extends LayoutCustomizer { + public IcelandicCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00EB", "\u00E8", "\u00EA", "\u0119", "\u0117", "\u0113") + // U+00FE: "þ" LATIN SMALL LETTER THORN + .setMoreKeysOf("t", "\u00FE") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FA", "\u00FC", "\u00FB", "\u00F9", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00ED", "\u00EF", "\u00EE", "\u00EC", "\u012F", "\u012B") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E1", "\u00E4", "\u00E6", "\u00E5", "\u00E0", "\u00E2", "\u00E3", + "\u0101") + // U+00F0: "ð" LATIN SMALL LETTER ETH + .setMoreKeysOf("d", "\u00F0"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIndonesian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIndonesian.java new file mode 100644 index 000000000..9b23bfe2b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsIndonesian.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * in: Indonesian/qwerty # "id" is the official language code of Indonesian. + */ +@SmallTest +public final class TestsIndonesian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("in"); + private static final LayoutBase LAYOUT = new Qwerty(new LayoutCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalian.java new file mode 100644 index 000000000..f3c610c8b --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalian.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * it: Italian/qwerty + */ +@SmallTest +public final class TestsItalian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("it"); + private static final LayoutBase LAYOUT = new Qwerty(new ItalianITCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class ItalianITCustomizer extends EuroCustomizer { + private final ItalianCustomizer mItalianCustomizer; + + public ItalianITCustomizer(final Locale locale) { + super(locale); + mItalianCustomizer = new ItalianCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mItalianCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalianCH.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalianCH.java new file mode 100644 index 000000000..d32f9e957 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsItalianCH.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Swiss; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * it_CH: Italian (Switzerland)/swiss + */ +@SmallTest +public final class TestsItalianCH extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("it", "CH"); + private static final LayoutBase LAYOUT = new Swiss(new ItalianCHCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class ItalianCHCustomizer extends ItalianCustomizer { + public ItalianCHCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + super.setAccentedLetters(builder); + return builder + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + .replaceKeyOfLabel(Swiss.ROW1_11, key("\u00FC", moreKey("\u00E8"))) + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + .replaceKeyOfLabel(Swiss.ROW2_10, key("\u00F6", moreKey("\u00E9"))) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + .replaceKeyOfLabel(Swiss.ROW2_11, key("\u00E4", moreKey("\u00E0"))); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKazakh.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKazakh.java new file mode 100644 index 000000000..d255a0fa9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKazakh.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.EastSlavic; +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * kk: Kazakh/east_slavic + */ +@SmallTest +public final class TestsKazakh extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("kk"); + private static final LayoutBase LAYOUT = new EastSlavic(new KazakhCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class KazakhCustomizer extends EastSlavicCustomizer { + public KazakhCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0443: "у" CYRILLIC SMALL LETTER U + // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U + // U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE + .setMoreKeysOf("\u0443", "\u04AF", "\u04B1") + // U+043A: "к" CYRILLIC SMALL LETTER KA + // U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER + .setMoreKeysOf("\u043A", "\u049B") + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0451: "ё" CYRILLIC SMALL LETTER IO + .setMoreKeysOf("\u0435", "\u0451") + // U+043D: "н" CYRILLIC SMALL LETTER EN + // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER + .setMoreKeysOf("\u043D", "\u04A3") + // U+0433: "г" CYRILLIC SMALL LETTER GHE + // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE + .setMoreKeysOf("\u0433", "\u0493") + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + .replaceKeyOfLabel(EastSlavic.ROW1_9, key("\u0449", additionalMoreKey("9"))) + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + .replaceKeyOfLabel(EastSlavic.ROW2_2, key("\u044B", moreKey("\u0456"))) + // U+0430: "а" CYRILLIC SMALL LETTER A + // U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA + .setMoreKeysOf("\u0430", "\u04D9") + // U+043E: "о" CYRILLIC SMALL LETTER O + // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O + .setMoreKeysOf("\u043E", "\u04E9") + // U+044D: "э" CYRILLIC SMALL LETTER E + // U+04BB: "һ" CYRILLIC SMALL LETTER SHHA + .replaceKeyOfLabel(EastSlavic.ROW2_11, key("\u044D", moreKey("\u04BB"))) + // U+0438: "и" CYRILLIC SMALL LETTER I + .replaceKeyOfLabel(EastSlavic.ROW3_5, "\u0438") + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + .setMoreKeysOf("\u044C", "\u044A"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKhmerKH.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKhmerKH.java new file mode 100644 index 000000000..df2f40d86 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKhmerKH.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Khmer; +import com.android.inputmethod.keyboard.layout.Khmer.KhmerCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * km_KH: Khmer (Cambodia)/khmer + */ +@SmallTest +public final class TestsKhmerKH extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("km", "KH"); + private static final LayoutBase LAYOUT = new Khmer(new KhmerCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKyrgyz.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKyrgyz.java new file mode 100644 index 000000000..9797b4ba9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsKyrgyz.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.EastSlavic; +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * ky: Kyrgyz/east_slavic + */ +@SmallTest +public final class TestsKyrgyz extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ky"); + private static final LayoutBase LAYOUT = new EastSlavic(new KyrgyzCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class KyrgyzCustomizer extends EastSlavicCustomizer { + public KyrgyzCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0443: "у" CYRILLIC SMALL LETTER U + // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U + .setMoreKeysOf("\u0443", "\u04AF") + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0451: "ё" CYRILLIC SMALL LETTER IO + .setMoreKeysOf("\u0435", "\u0451") + // U+043D: "н" CYRILLIC SMALL LETTER EN + // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER + .setMoreKeysOf("\u043D", "\u04A3") + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + .replaceKeyOfLabel(EastSlavic.ROW1_9, key("\u0449", additionalMoreKey("9"))) + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + .replaceKeyOfLabel(EastSlavic.ROW2_2, "\u044B") + // U+043E: "о" CYRILLIC SMALL LETTER O + // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O + .setMoreKeysOf("\u043E", "\u04E9") + // U+044D: "э" CYRILLIC SMALL LETTER E + .replaceKeyOfLabel(EastSlavic.ROW2_11, "\u044D") + // U+0438: "и" CYRILLIC SMALL LETTER I + .replaceKeyOfLabel(EastSlavic.ROW3_5, "\u0438") + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + .setMoreKeysOf("\u044C", "\u044A"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLaoLA.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLaoLA.java new file mode 100644 index 000000000..34ad1fb7f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLaoLA.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Lao; +import com.android.inputmethod.keyboard.layout.Lao.LaoCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * lo_LA: Lao (Laos)/lao + */ +@SmallTest +public final class TestsLaoLA extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("lo", "LA"); + private static final LayoutBase LAYOUT = new Lao(new LaoCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLatvian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLatvian.java new file mode 100644 index 000000000..dc1736c6d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLatvian.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * lv: Latvian/qwerty + */ +@SmallTest +public final class TestsLatvian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("lv"); + private static final LayoutBase LAYOUT = new Qwerty(new LatvianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class LatvianCustomizer extends LayoutCustomizer { + public LatvianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + .setMoreKeysOf("e", + "\u0113", "\u0117", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0119", + "\u011B") + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + .setMoreKeysOf("r", "\u0157", "\u0159", "\u0155") + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + .setMoreKeysOf("t", "\u0163", "\u0165") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + .setMoreKeysOf("u", + "\u016B", "\u0173", "\u00F9", "\u00FA", "\u00FB", "\u00FC", "\u016F", + "\u0171") + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + .setMoreKeysOf("i", + "\u012B", "\u012F", "\u00EC", "\u00ED", "\u00EE", "\u00EF", "\u0131") + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + .setMoreKeysOf("o", + "\u00F2", "\u00F3", "\u00F4", "\u00F5", "\u00F6", "\u0153", "\u0151", + "\u00F8") + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + .setMoreKeysOf("a", + "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u00E4", "\u00E5", + "\u00E6", "\u0105") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u010F") + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u0123", "\u011F") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + .setMoreKeysOf("k", "\u0137") + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + .setMoreKeysOf("l", "\u013C", "\u0142", "\u013A", "\u013E") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107") + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u0146", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLithuanian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLithuanian.java new file mode 100644 index 000000000..55ac37a37 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsLithuanian.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * lt: Lithuanian/qwerty + */ +@SmallTest +public final class TestsLithuanian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("lt"); + private static final LayoutBase LAYOUT = new Qwerty(new LithuanianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class LithuanianCustomizer extends LayoutCustomizer { + public LithuanianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + .setMoreKeysOf("e", + "\u0117", "\u0119", "\u0113", "\u00E8", "\u00E9", "\u00EA", "\u00EB", + "\u011B") + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + .setMoreKeysOf("r", "\u0157", "\u0159", "\u0155") + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + .setMoreKeysOf("t", "\u0163", "\u0165") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + .setMoreKeysOf("u", + "\u016B", "\u0173", "\u00FC", "\u016B", "\u00F9", "\u00FA", "\u00FB", + "\u016F", "\u0171") + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + .setMoreKeysOf("i", + "\u012F", "\u012B", "\u00EC", "\u00ED", "\u00EE", "\u00EF", "\u0131") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + .setMoreKeysOf("o", + "\u00F6", "\u00F5", "\u00F2", "\u00F3", "\u00F4", "\u0153", "\u0151", + "\u00F8") + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + .setMoreKeysOf("a", + "\u0105", "\u00E4", "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3", + "\u00E5", "\u00E6") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u010F") + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u0123", "\u011F") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + .setMoreKeysOf("k", "\u0137") + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + .setMoreKeysOf("l", "\u013C", "\u0142", "\u013A", "\u013E") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107") + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u0146", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMacedonian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMacedonian.java new file mode 100644 index 000000000..1d7d85650 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMacedonian.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.SouthSlavic; +import com.android.inputmethod.keyboard.layout.SouthSlavic.SouthSlavicLayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * mk: Macedonian/south_slavic + */ +@SmallTest +public final class TestsMacedonian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("mk"); + private static final LayoutBase LAYOUT = new SouthSlavic(new MacedonianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class MacedonianCustomizer extends SouthSlavicLayoutCustomizer { + public MacedonianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE + .setMoreKeysOf("\u0435", "\u0450") + // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE + .replaceKeyOfLabel(SouthSlavic.ROW1_6, key("\u0455", additionalMoreKey("6"))) + // U+0438: "и" CYRILLIC SMALL LETTER I + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + .setMoreKeysOf("\u0438", "\u045D") + // U+045C: "ќ" CYRILLIC SMALL LETTER KJE + .replaceKeyOfLabel(SouthSlavic.ROW2_11, "\u045C") + // U+0437: "з" CYRILLIC SMALL LETTER ZE + .replaceKeyOfLabel(SouthSlavic.ROW3_1, "\u0437") + // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE + .replaceKeyOfLabel(SouthSlavic.ROW3_8, "\u0453"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayMY.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayMY.java new file mode 100644 index 000000000..9792af9d0 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayMY.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * ms_MY: Malay (Malaysia)/qwerty + */ +@SmallTest +public final class TestsMalayMY extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ms", "MY"); + private static final LayoutBase LAYOUT = new Qwerty(new LayoutCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMongolianMN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMongolianMN.java new file mode 100644 index 000000000..e28e962f9 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMongolianMN.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Mongolian; +import com.android.inputmethod.keyboard.layout.Mongolian.MongolianMNCustomizer; + +import java.util.Locale; + +/** + * mn_MN: Mongolian (Mongolia)/mongolian + */ +@SmallTest +public final class TestsMongolianMN extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("mn", "MN"); + private static final LayoutBase LAYOUT = new Mongolian(new MongolianMNCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java new file mode 100644 index 000000000..e6d3b3b92 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Myanmar; +import com.android.inputmethod.keyboard.layout.Myanmar.MyanmarCustomizer; + +import java.util.Locale; + +/** + * my_MM: Myanmar (Myanmar)/myanmar + */ +@SmallTest +public final class TestsMyanmarMM extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("my", "MM"); + private static final LayoutBase LAYOUT = new Myanmar(new MyanmarCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliRomanized.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliRomanized.java new file mode 100644 index 000000000..971976aec --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliRomanized.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.NepaliRomanized; +import com.android.inputmethod.keyboard.layout.NepaliRomanized.NepaliRomanizedCustomizer; + +import java.util.Locale; + +/** + * ne_NP: Nepali (Nepal) Romanized/nepali_romanized + */ +@SmallTest +public final class TestsNepaliRomanized extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ne", "NP"); + private static final LayoutBase LAYOUT = new NepaliRomanized( + new NepaliRomanizedCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliTraditional.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliTraditional.java new file mode 100644 index 000000000..724c4304f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNepaliTraditional.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.NepaliTraditional; +import com.android.inputmethod.keyboard.layout.NepaliTraditional.NepaliTraditionalCustomizer; + +import java.util.Locale; + +/** + * ne_NP: Nepali (Nepal) Traditional/nepali_traditional + */ +@SmallTest +public final class TestsNepaliTraditional extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ne", "NP"); + private static final LayoutBase LAYOUT = new NepaliTraditional( + new NepaliTraditionalCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguage.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguage.java new file mode 100644 index 000000000..3ed63153a --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguage.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * zz: Alphabet/qwerty + */ +@SmallTest +public final class TestsNoLanguage extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("zz"); + private static final LayoutBase LAYOUT = new Qwerty(new NoLanguageCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageColemak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageColemak.java new file mode 100644 index 000000000..8d627e3b4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageColemak.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Colemak; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * zz: Alphabet/colemak + */ +@SmallTest +public final class TestsNoLanguageColemak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("zz"); + private static final LayoutBase LAYOUT = new Colemak(new NoLanguageColemakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class NoLanguageColemakCustomizer extends LayoutCustomizer { + private final NoLanguageCustomizer mNoLanguageCustomizer; + + public NoLanguageColemakCustomizer(final Locale locale) { + super(locale); + mNoLanguageCustomizer = new NoLanguageCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mNoLanguageCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageDvorak.java new file mode 100644 index 000000000..9bf47ed42 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguageDvorak.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Dvorak; +import com.android.inputmethod.keyboard.layout.Dvorak.DvorakCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * zz: Alphabet/dvorak + */ +@SmallTest +public final class TestsNoLanguageDvorak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("zz"); + private static final LayoutBase LAYOUT = new Dvorak(new NoLanguageDvorakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class NoLanguageDvorakCustomizer extends DvorakCustomizer { + private final NoLanguageCustomizer mNoLanguageCustomizer; + + public NoLanguageDvorakCustomizer(final Locale locale) { + super(locale); + mNoLanguageCustomizer = new NoLanguageCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mNoLanguageCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java new file mode 100644 index 000000000..cd8d43ca8 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNoLanguagePcQwerty.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.PcQwerty; +import com.android.inputmethod.keyboard.layout.PcQwerty.PcQwertyCustomizer; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * zz: Alphabet/pcqwerty + */ +@SmallTest +public final class TestsNoLanguagePcQwerty extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("zz"); + private static final LayoutBase LAYOUT = new PcQwerty(new NoLanguagePcQwertyCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class NoLanguagePcQwertyCustomizer extends PcQwertyCustomizer { + private final NoLanguageCustomizer mNoLanguageCustomizer; + + public NoLanguagePcQwertyCustomizer(final Locale locale) { + super(locale); + mNoLanguageCustomizer = new NoLanguageCustomizer(locale); + } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return mNoLanguageCustomizer.setAccentedLetters(builder); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegian.java new file mode 100644 index 000000000..5d220dfa1 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegian.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Nordic; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * nb: Norwegian Bokmål/nordic + */ +@SmallTest +public final class TestsNorwegian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("nb"); + private static final LayoutBase LAYOUT = new Nordic(new NorwegianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class NorwegianCustomizer extends LayoutCustomizer { + public NorwegianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0119", "\u0117", "\u0113") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B") + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F4", "\u00F2", "\u00F3", "\u00F6", "\u00F5", "\u0153", "\u014D") + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + .replaceKeyOfLabel(Nordic.ROW1_11, "\u00E5") + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW2_10, key("\u00F8", moreKey("\u00F6"))) + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + .replaceKeyOfLabel(Nordic.ROW2_11, key("\u00E6", moreKey("\u00E4"))) + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", "\u00E0", "\u00E4", "\u00E1", "\u00E2", "\u00E3", "\u0101"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPersian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPersian.java new file mode 100644 index 000000000..b7d75c9f0 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPersian.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.Farsi; +import com.android.inputmethod.keyboard.layout.Farsi.FarsiCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; + +import java.util.Locale; + +/** + * fa: Persian/farsi + */ +@SmallTest +public class TestsPersian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("fa"); + private static final LayoutBase LAYOUT = new Farsi(new FarsiCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPolish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPolish.java new file mode 100644 index 000000000..04f88c3fc --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPolish.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * pl: Polish/qwerty + */ +@SmallTest +public final class TestsPolish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("pl"); + private static final LayoutBase LAYOUT = new Qwerty(new PolishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class PolishCustomizer extends LayoutCustomizer { + public PolishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", + "\u0119", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0117", "\u0113") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F3", "\u00F6", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u00F8", + "\u014D") + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u0105", "\u00E1", "\u00E0", "\u00E2", "\u00E4", "\u00E6", "\u00E3", + "\u00E5", "\u0101") + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u015B", "\u00DF", "\u0161") + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u0142") + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + .setMoreKeysOf("z", "\u017C", "\u017A", "\u017E") + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u0107", "\u00E7", "\u010D") + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + .setMoreKeysOf("n", "\u0144", "\u00F1"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortugueseBR.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortugueseBR.java new file mode 100644 index 000000000..8a984a765 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortugueseBR.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * pt_BR: Portuguese (Brazil)/qwerty + */ +@SmallTest +public class TestsPortugueseBR extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("pt", "BR"); + private static final LayoutBase LAYOUT = new Qwerty(new PortugueseCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortuguesePT.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortuguesePT.java new file mode 100644 index 000000000..e15e811db --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsPortuguesePT.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/** + * pt_PT: Portuguese (Portugal)/qwerty + */ +@SmallTest +public final class TestsPortuguesePT extends TestsPortugueseBR { + private static final Locale LOCALE = new Locale("pt", "PT"); + private static final LayoutBase LAYOUT = new Qwerty(new PortuguesePTCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class PortuguesePTCustomizer extends PortugueseCustomizer { + private final EuroCustomizer mEuroCustomizer; + + public PortuguesePTCustomizer(final Locale locale) { + super(locale); + mEuroCustomizer = new EuroCustomizer(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return mEuroCustomizer.getCurrencyKey(); } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return mEuroCustomizer.getOtherCurrencyKeys(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java new file mode 100644 index 000000000..0207f1c22 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRomanian.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * ro: Romanian/qwerty + */ +@SmallTest +public final class TestsRomanian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ro"); + private static final LayoutBase LAYOUT = new Qwerty(new RomanianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class RomanianCustomizer extends LayoutCustomizer { + public RomanianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_L9R; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_L9R; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW + .setMoreKeysOf("t", "\u021B") + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", "\u00EE", "\u00EF", "\u00EC", "\u00ED", "\u012F", "\u012B") + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E2", "\u00E3", "\u0103", "\u00E0", "\u00E1", "\u00E4", "\u00E6", + "\u00E5", "\u0101") + // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u0219", "\u00DF", "\u015B", "\u0161"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRussian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRussian.java new file mode 100644 index 000000000..9919207ed --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsRussian.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.EastSlavic; +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * ru: Russian/east_slavic + */ +@SmallTest +public final class TestsRussian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("ru"); + private static final LayoutBase LAYOUT = new EastSlavic(new RussianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class RussianCustomizer extends EastSlavicCustomizer { + public RussianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0451: "ё" CYRILLIC SMALL LETTER IO + .setMoreKeysOf("\u0435", "\u0451") + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + .replaceKeyOfLabel(EastSlavic.ROW1_9, key("\u0449", additionalMoreKey("9"))) + // U+044B: "ы" CYRILLIC SMALL LETTER YERU + .replaceKeyOfLabel(EastSlavic.ROW2_2, "\u044B") + // U+044D: "э" CYRILLIC SMALL LETTER E + .replaceKeyOfLabel(EastSlavic.ROW2_11, "\u044D") + // U+0438: "и" CYRILLIC SMALL LETTER I + .replaceKeyOfLabel(EastSlavic.ROW3_5, "\u0438") + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + .setMoreKeysOf("\u044C", "\u044A"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbian.java new file mode 100644 index 000000000..41f1690f3 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbian.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.SouthSlavic; +import com.android.inputmethod.keyboard.layout.SouthSlavic.SouthSlavicLayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * sr: Serbian/south_slavic + */ +@SmallTest +public final class TestsSerbian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("sr"); + private static final LayoutBase LAYOUT = new SouthSlavic(new SerbianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SerbianCustomizer extends SouthSlavicLayoutCustomizer { + public SerbianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0435: "е" CYRILLIC SMALL LETTER IE + // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE + .setMoreKeysOf("\u0435", "\u0450") + // U+0437: "з" CYRILLIC SMALL LETTER ZE + .replaceKeyOfLabel(SouthSlavic.ROW1_6, key("\u0437", additionalMoreKey("6"))) + // U+0438: "и" CYRILLIC SMALL LETTER I + // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE + .setMoreKeysOf("\u0438", "\u045D") + // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE + .replaceKeyOfLabel(SouthSlavic.ROW2_11, "\u045B") + // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE + .replaceKeyOfLabel(SouthSlavic.ROW3_1, "\u0455") + // U+0452: "ђ" CYRILLIC SMALL LETTER DJE + .replaceKeyOfLabel(SouthSlavic.ROW3_8, "\u0452"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovak.java new file mode 100644 index 000000000..bdaf0cad1 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovak.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * sk: Slovak/qwerty + */ +@SmallTest +public final class TestsSlovak extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("sk"); + private static final LayoutBase LAYOUT = new Qwerty(new SlovakCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SlovakCustomizer extends EuroCustomizer { + public SlovakCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+011B: "ě" LATIN SMALL LETTER E WITH CARON + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + .setMoreKeysOf("e", + "\u00E9", "\u011B", "\u0113", "\u0117", "\u00E8", "\u00EA", "\u00EB", + "\u0119") + // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA + .setMoreKeysOf("r", "\u0155", "\u0159", "\u0157") + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA + .setMoreKeysOf("t", "\u0165", "\u0163") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE + .setMoreKeysOf("u", + "\u00FA", "\u016F", "\u00FC", "\u016B", "\u0173", "\u00F9", "\u00FB", + "\u0171") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + .setMoreKeysOf("i", + "\u00ED", "\u012B", "\u012F", "\u00EC", "\u00EE", "\u00EF", "\u0131") + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + .setMoreKeysOf("o", + "\u00F4", "\u00F3", "\u00F6", "\u00F2", "\u00F5", "\u0153", "\u0151", + "\u00F8") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + .setMoreKeysOf("a", + "\u00E1", "\u00E4", "\u0101", "\u00E0", "\u00E2", "\u00E3", "\u00E5", + "\u00E6", "\u0105") + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F") + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u010F") + // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u0123", "\u011F") + // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA + .setMoreKeysOf("k", "\u0137") + // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON + // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE + // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u013E", "\u013A", "\u013C", "\u0142") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107") + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + .setMoreKeysOf("n", "\u0148", "\u0146", "\u00F1", "\u0144"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovenian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovenian.java new file mode 100644 index 000000000..cdb1beeba --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSlovenian.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * sl: Slovenian/qwerty + */ +@SmallTest +public final class TestsSlovenian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("sl"); + private static final LayoutBase LAYOUT = new Qwerty(new SlovenianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SlovenianCustomizer extends EuroCustomizer { + public SlovenianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u0161") + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + .setMoreKeysOf("d", "\u0111") + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + .setMoreKeysOf("z", "\u017E") + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + .setMoreKeysOf("c", "\u010D", "\u0107"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish.java new file mode 100644 index 000000000..12e8676ae --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/** + * es: Spanish/spanish + */ +@SmallTest +public class TestsSpanish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("es"); + private static final LayoutBase LAYOUT = new Spanish(new SpanishESCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SpanishESCustomizer extends SpanishCustomizer { + private final EuroCustomizer mEuroCustomizer; + + public SpanishESCustomizer(final Locale locale) { + super(locale); + mEuroCustomizer = new EuroCustomizer(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return mEuroCustomizer.getCurrencyKey(); } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return mEuroCustomizer.getOtherCurrencyKeys(); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish419.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish419.java new file mode 100644 index 000000000..75aad136f --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanish419.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Spanish; + +import java.util.Locale; + +/** + * es_419: Spanish (Latin America)/spanish + */ +@SmallTest +public class TestsSpanish419 extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("es", "419"); + private static final LayoutBase LAYOUT = new Spanish(new SpanishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanishUS.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanishUS.java new file mode 100644 index 000000000..c3ac0a0c0 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSpanishUS.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Spanish; + +import java.util.Locale; + +/** + * es_US: Spanish (United States)/spanish + */ +@SmallTest +public class TestsSpanishUS extends TestsSpanish { + private static final Locale LOCALE = new Locale("es", "US"); + private static final LayoutBase LAYOUT = new Spanish(new SpanishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwahili.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwahili.java new file mode 100644 index 000000000..13b974194 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwahili.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * sw: Swahili/qwerty + */ +@SmallTest +public final class TestsSwahili extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("sw"); + private static final LayoutBase LAYOUT = new Qwerty(new SwahiliCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SwahiliCustomizer extends LayoutCustomizer { + public SwahiliCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON + .setMoreKeysOf("e", "\u00E8", "\u00E9", "\u00EA", "\u00EB", "\u0113") + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FB", "\u00FC", "\u00F9", "\u00FA", "\u016B") + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + .setMoreKeysOf("i", "\u00EE", "\u00EF", "\u00ED", "\u012B", "\u00EC") + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + .setMoreKeysOf("o", + "\u00F4", "\u00F6", "\u00F2", "\u00F3", "\u0153", "\u00F8", "\u014D", + "\u00F5") + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u00E2", "\u00E4", "\u00E6", "\u00E3", "\u00E5", + "\u0101") + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + .setMoreKeysOf("s", "\u00DF") + .setMoreKeysOf("g", "g'") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + .setMoreKeysOf("c", "\u00E7") + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + .setMoreKeysOf("n", "\u00F1"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedish.java new file mode 100644 index 000000000..9b58914a2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedish.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Nordic; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * sv: Swedish/nordic + */ +@SmallTest +public final class TestsSwedish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("sv"); + private static final LayoutBase LAYOUT = new Nordic(new SwedishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class SwedishCustomizer extends EuroCustomizer { + public SwedishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey[] getDoubleAngleQuoteKeys() { return Symbols.DOUBLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKey[] getSingleAngleQuoteKeys() { return Symbols.SINGLE_ANGLE_QUOTES_RL; } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + .setMoreKeysOf("e", "\u00E9", "\u00E8", "\u00EA", "\u00EB", "\u0119") + // U+0159: "ř" LATIN SMALL LETTER R WITH CARON + .setMoreKeysOf("r", "\u0159") + // U+0165: "ť" LATIN SMALL LETTER T WITH CARON + // U+00FE: "þ" LATIN SMALL LETTER THORN + .setMoreKeysOf("t", "\u0165", "\u00FE") + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS + .setMoreKeysOf("y", "\u00FD", "\u00FF") + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FC", "\u00FA", "\u00F9", "\u00FB", "\u016B") + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + .setMoreKeysOf("i", "\u00ED", "\u00EC", "\u00EE", "\u00EF") + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", "\u00F3", "\u00F2", "\u00F4", "\u00F5", "\u014D") + // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + .replaceKeyOfLabel(Nordic.ROW1_11, "\u00E5") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+0153: "œ" LATIN SMALL LIGATURE OE + .replaceKeyOfLabel(Nordic.ROW2_10, + key("\u00F6", joinMoreKeys("\u00F8", "\u0153"))) + // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + // U+00E6: "æ" LATIN SMALL LETTER AE + .replaceKeyOfLabel(Nordic.ROW2_11, key("\u00E4", moreKey("\u00E6"))) + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + .setMoreKeysOf("a", "\u00E1", "\u00E0", "\u00E2", "\u0105", "\u00E3") + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + .setMoreKeysOf("s", "\u015B", "\u0161", "\u015F", "\u00DF") + // U+00F0: "ð" LATIN SMALL LETTER ETH + // U+010F: "ď" LATIN SMALL LETTER D WITH CARON + .setMoreKeysOf("d", "\u00F0", "\u010F") + // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE + .setMoreKeysOf("l", "\u0142") + // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE + // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON + // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE + .setMoreKeysOf("z", "\u017A", "\u017E", "\u017C") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D") + // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE + // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + // U+0148: "ň" LATIN SMALL LETTER N WITH CARON + .setMoreKeysOf("n", "\u0144", "\u00F1", "\u0148"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTagalog.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTagalog.java new file mode 100644 index 000000000..38d5364e5 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTagalog.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Spanish; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; + +import java.util.Locale; + +/** + * tl: Tagalog/spanish + */ +@SmallTest +public class TestsTagalog extends TestsSpanish { + private static final Locale LOCALE = new Locale("tl"); + private static final LayoutBase LAYOUT = new Spanish(new TagalogCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class TagalogCustomizer extends SpanishCustomizer { + + public TagalogCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey[] getPunctuationMoreKeys(final boolean isPhone) { + return isPhone ? LayoutBase.PHONE_PUNCTUATION_MORE_KEYS + : LayoutBase.TABLET_PUNCTUATION_MORE_KEYS; + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsThai.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsThai.java new file mode 100644 index 000000000..3c8727290 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsThai.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Thai; +import com.android.inputmethod.keyboard.layout.Thai.ThaiCustomizer; + +import java.util.Locale; + +/** + * th: Thai/thai + */ +@SmallTest +public final class TestsThai extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("th"); + private static final LayoutBase LAYOUT = new Thai(new ThaiCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTurkish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTurkish.java new file mode 100644 index 000000000..b35f8850a --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTurkish.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * tr: Turkish/qwerty + */ +@SmallTest +public final class TestsTurkish extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("tr"); + private static final LayoutBase LAYOUT = new Qwerty(new TurkishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class TurkishCustomizer extends EuroCustomizer { + public TurkishCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON + .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B") + // U+0131: "ı" LATIN SMALL LETTER DOTLESS I + // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON + .setMoreKeysOf("i", + "\u0131", "\u00EE", "\u00EF", "\u00EC", "\u00ED", "\u012F", "\u012B") + // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+0153: "œ" LATIN SMALL LIGATURE OE + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + .setMoreKeysOf("o", + "\u00F6", "\u00F4", "\u0153", "\u00F2", "\u00F3", "\u00F5", "\u00F8", + "\u014D") + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + .setMoreKeysOf("a", "\u00E2") + // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA + // U+00DF: "ß" LATIN SMALL LETTER SHARP S + // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE + // U+0161: "š" LATIN SMALL LETTER S WITH CARON + .setMoreKeysOf("s", "\u015F", "\u00DF", "\u015B", "\u0161") + // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE + .setMoreKeysOf("g", "\u011F") + // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + // U+010D: "č" LATIN SMALL LETTER C WITH CARON + .setMoreKeysOf("c", "\u00E7", "\u0107", "\u010D"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUkrainian.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUkrainian.java new file mode 100644 index 000000000..a6bcacc9e --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUkrainian.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.EastSlavic; +import com.android.inputmethod.keyboard.layout.EastSlavic.EastSlavicCustomizer; +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * uk: Ukrainian/east_slavic + */ +@SmallTest +public final class TestsUkrainian extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("uk"); + private static final LayoutBase LAYOUT = new EastSlavic(new UkrainianCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class UkrainianCustomizer extends EastSlavicCustomizer { + public UkrainianCustomizer(final Locale locale) { super(locale); } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_HRYVNIA; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + @Override + public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; } + + @Override + public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; } + + // U+20B4: "₴" HRYVNIA SIGN + private static final ExpectedKey CURRENCY_HRYVNIA = key("\u20B4", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+0433: "г" CYRILLIC SMALL LETTER GHE + // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN + .setMoreKeysOf("\u0433", "\u0491") + // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA + .replaceKeyOfLabel(EastSlavic.ROW1_9, key("\u0449", additionalMoreKey("9"))) + // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + // U+0457: "ї" CYRILLIC SMALL LETTER YI + .replaceKeyOfLabel(EastSlavic.ROW2_2, key("\u0456", moreKey("\u0457"))) + // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE + .replaceKeyOfLabel(EastSlavic.ROW2_11, "\u0454") + // U+0438: "и" CYRILLIC SMALL LETTER I + .replaceKeyOfLabel(EastSlavic.ROW3_5, "\u0438") + // U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN + // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN + .setMoreKeysOf("\u044C", "\u044A"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsVietnamese.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsVietnamese.java new file mode 100644 index 000000000..83d86ac4d --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsVietnamese.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.LayoutBase.LayoutCustomizer; +import com.android.inputmethod.keyboard.layout.Qwerty; +import com.android.inputmethod.keyboard.layout.Symbols; +import com.android.inputmethod.keyboard.layout.SymbolsShifted; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKey; +import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder; + +import java.util.Locale; + +/** + * vi: Vietnamese/qwerty + */ +@SmallTest +public final class TestsVietnamese extends LayoutTestsBase { + private static final Locale LOCALE = new Locale("vi"); + private static final LayoutBase LAYOUT = new Qwerty(new VietnameseCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } + + private static class VietnameseCustomizer extends LayoutCustomizer { + public VietnameseCustomizer(final Locale locale) { + super(locale); + } + + @Override + public ExpectedKey getCurrencyKey() { return CURRENCY_DONG; } + + @Override + public ExpectedKey[] getOtherCurrencyKeys() { + return SymbolsShifted.CURRENCIES_OTHER_GENERIC; + } + + // U+20AB: "₫" DONG SIGN + private static final ExpectedKey CURRENCY_DONG = key("\u20AB", + Symbols.CURRENCY_GENERIC_MORE_KEYS); + + @Override + public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) { + return builder + // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + // U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE + // U+1EBD: "ẽ" LATIN SMALL LETTER E WITH TILDE + // U+1EB9: "ẹ" LATIN SMALL LETTER E WITH DOT BELOW + // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + // U+1EC1: "ề" LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE + // U+1EBF: "ế" LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE + // U+1EC3: "ể" LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE + // U+1EC5: "ễ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE + // U+1EC7: "ệ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW + .setMoreKeysOf("e", + "\u00E8", "\u00E9", "\u1EBB", "\u1EBD", "\u1EB9", "\u00EA", "\u1EC1", + "\u1EBF", "\u1EC3", "\u1EC5", "\u1EC7") + // U+1EF3: "ỳ" LATIN SMALL LETTER Y WITH GRAVE + // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE + // U+1EF7: "ỷ" LATIN SMALL LETTER Y WITH HOOK ABOVE + // U+1EF9: "ỹ" LATIN SMALL LETTER Y WITH TILDE + // U+1EF5: "ỵ" LATIN SMALL LETTER Y WITH DOT BELOW + .setMoreKeysOf("y", "\u1EF3", "\u00FD", "\u1EF7", "\u1EF9", "\u1EF5") + // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + // U+1EE7: "ủ" LATIN SMALL LETTER U WITH HOOK ABOVE + // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE + // U+1EE5: "ụ" LATIN SMALL LETTER U WITH DOT BELOW + // U+01B0: "ư" LATIN SMALL LETTER U WITH HORN + // U+1EEB: "ừ" LATIN SMALL LETTER U WITH HORN AND GRAVE + // U+1EE9: "ứ" LATIN SMALL LETTER U WITH HORN AND ACUTE + // U+1EED: "ử" LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE + // U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE + // U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW + .setMoreKeysOf("u", + "\u00F9", "\u00FA", "\u1EE7", "\u0169", "\u1EE5", "\u01B0", "\u1EEB", + "\u1EE9", "\u1EED", "\u1EEF", "\u1EF1") + // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + // U+1EC9: "ỉ" LATIN SMALL LETTER I WITH HOOK ABOVE + // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE + // U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW + .setMoreKeysOf("i", "\u00EC", "\u00ED", "\u1EC9", "\u0129", "\u1ECB") + // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + // U+1ECF: "ỏ" LATIN SMALL LETTER O WITH HOOK ABOVE + // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + // U+1ECD: "ọ" LATIN SMALL LETTER O WITH DOT BELOW + // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + // U+1ED3: "ồ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE + // U+1ED1: "ố" LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE + // U+1ED5: "ổ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE + // U+1ED7: "ỗ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE + // U+1ED9: "ộ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW + // U+01A1: "ơ" LATIN SMALL LETTER O WITH HORN + // U+1EDD: "ờ" LATIN SMALL LETTER O WITH HORN AND GRAVE + // U+1EDB: "ớ" LATIN SMALL LETTER O WITH HORN AND ACUTE + // U+1EDF: "ở" LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE + // U+1EE1: "ỡ" LATIN SMALL LETTER O WITH HORN AND TILDE + // U+1EE3: "ợ" LATIN SMALL LETTER O WITH HORN AND DOT BELOW + .setMoreKeysOf("o", + "\u00F2", "\u00F3", "\u1ECF", "\u00F5", "\u1ECD", "\u00F4", "\u1ED3", + "\u1ED1", "\u1ED5", "\u1ED7", "\u1ED9", "\u01A1", "\u1EDD", "\u1EDB", + "\u1EDF", "\u1EE1", "\u1EE3") + // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + // U+1EA3: "ả" LATIN SMALL LETTER A WITH HOOK ABOVE + // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + // U+1EA1: "ạ" LATIN SMALL LETTER A WITH DOT BELOW + // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE + // U+1EB1: "ằ" LATIN SMALL LETTER A WITH BREVE AND GRAVE + // U+1EAF: "ắ" LATIN SMALL LETTER A WITH BREVE AND ACUTE + // U+1EB3: "ẳ" LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE + // U+1EB5: "ẵ" LATIN SMALL LETTER A WITH BREVE AND TILDE + // U+1EB7: "ặ" LATIN SMALL LETTER A WITH BREVE AND DOT BELOW + // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + // U+1EA7: "ầ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE + // U+1EA5: "ấ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE + // U+1EA9: "ẩ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE + // U+1EAB: "ẫ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE + // U+1EAD: "ậ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW + .setMoreKeysOf("a", + "\u00E0", "\u00E1", "\u1EA3", "\u00E3", "\u1EA1", "\u0103", "\u1EB1", + "\u1EAF", "\u1EB3", "\u1EB5", "\u1EB7", "\u00E2", "\u1EA7", "\u1EA5", + "\u1EA9", "\u1EAB", "\u1EAD") + // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE + .setMoreKeysOf("d", "\u0111"); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsZulu.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsZulu.java new file mode 100644 index 000000000..e048e92c2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsZulu.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 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.layout.tests; + +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.keyboard.layout.LayoutBase; +import com.android.inputmethod.keyboard.layout.Qwerty; + +import java.util.Locale; + +/** + * zu: Zulu/qwerty + */ +@SmallTest +public final class TestsZulu extends TestsEnglishUS { + private static final Locale LOCALE = new Locale("zu"); + private static final LayoutBase LAYOUT = new Qwerty(new EnglishCustomizer(LOCALE)); + + @Override + LayoutBase getLayout() { return LAYOUT; } +} diff --git a/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java b/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java new file mode 100644 index 000000000..c29257d34 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/AppWorkaroundsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 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.latin.settings.Settings; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build.VERSION_CODES; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.inputmethod.EditorInfo; + +@LargeTest +public class AppWorkaroundsTests extends InputTestsBase { + String packageNameOfAppBeforeJellyBean; + String packageNameOfAppAfterJellyBean; + + @Override + protected void setUp() throws Exception { + // NOTE: this will fail if there is no app installed that targets an SDK + // before Jelly Bean. For the moment, it's fine. + final PackageManager pm = getContext().getPackageManager(); + for (ApplicationInfo ai : pm.getInstalledApplications(0 /* flags */)) { + if (ai.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { + packageNameOfAppBeforeJellyBean = ai.packageName; + } else { + packageNameOfAppAfterJellyBean = ai.packageName; + } + } + super.setUp(); + } + + // We want to test if the app package info is correctly retrieved by LatinIME. Since it + // asks this information to the package manager from the package name, and that it takes + // the package name from the EditorInfo, all we have to do it put the correct package + // name in the editor info. + // To this end, our base class InputTestsBase offers a hook for us to touch the EditorInfo. + // We override this hook to write the package name that we need. + @Override + protected EditorInfo enrichEditorInfo(final EditorInfo ei) { + if ("testBeforeJellyBeanTrue".equals(getName())) { + ei.packageName = packageNameOfAppBeforeJellyBean; + } else if ("testBeforeJellyBeanFalse".equals(getName())) { + ei.packageName = packageNameOfAppAfterJellyBean; + } + return ei; + } + + public void testBeforeJellyBeanTrue() { + assertTrue("Couldn't successfully detect this app targets < Jelly Bean (package is " + + packageNameOfAppBeforeJellyBean + ")", + Settings.getInstance().getCurrent().isBeforeJellyBean()); + } + + public void testBeforeJellyBeanFalse() { + assertFalse("Couldn't successfully detect this app targets >= Jelly Bean (package is " + + packageNameOfAppAfterJellyBean + ")", + Settings.getInstance().getCurrent().isBeforeJellyBean()); + } +}
\ No newline at end of file diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index cd5384ea4..ae2205b36 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -20,8 +20,17 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Pair; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.CodePointUtils; +import com.android.inputmethod.latin.makedict.DictDecoder; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; +import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.File; import java.io.IOException; @@ -30,68 +39,169 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Random; +import java.util.concurrent.TimeUnit; @LargeTest public class BinaryDictionaryDecayingTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; - - // Note that these are corresponding definitions in native code in - // latinime::DynamicPatriciaTriePolicy. - private static final String SET_NEEDS_TO_DECAY_FOR_TESTING_KEY = - "SET_NEEDS_TO_DECAY_FOR_TESTING"; - private static final int DUMMY_PROBABILITY = 0; + private int mCurrentTime = 0; + @Override protected void setUp() throws Exception { super.setUp(); + mCurrentTime = 0; } @Override protected void tearDown() throws Exception { + stopTestModeInNativeCode(); super.tearDown(); } + private void addUnigramWord(final BinaryDictionary binaryDictionary, final String word, + final int probability) { + binaryDictionary.addUnigramWord(word, probability, "" /* shortcutTarget */, + BinaryDictionary.NOT_A_PROBABILITY /* shortcutProbability */, + false /* isNotAWord */, false /* isBlacklisted */, + mCurrentTime /* timestamp */); + } + + private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, + final String word1, final int probability) { + binaryDictionary.addBigramWords(word0, word1, probability, + mCurrentTime /* timestamp */); + } + private void forcePassingShortTime(final BinaryDictionary binaryDictionary) { - // Entries having low probability would be suppressed once in 3 GCs. - final int count = 3; - for (int i = 0; i < count; i++) { - binaryDictionary.getPropertyForTests(SET_NEEDS_TO_DECAY_FOR_TESTING_KEY); - binaryDictionary.flushWithGC(); - } + // 30 days. + final int timeToElapse = (int)TimeUnit.SECONDS.convert(30, TimeUnit.DAYS); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + binaryDictionary.flushWithGC(); } private void forcePassingLongTime(final BinaryDictionary binaryDictionary) { - // Currently, probabilities are decayed when GC is run. All entries that have never been - // typed in 128 GCs would be removed. - final int count = 128; - for (int i = 0; i < count; i++) { - binaryDictionary.getPropertyForTests(SET_NEEDS_TO_DECAY_FOR_TESTING_KEY); - binaryDictionary.flushWithGC(); + // 365 days. + final int timeToElapse = (int)TimeUnit.SECONDS.convert(365, TimeUnit.DAYS); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + binaryDictionary.flushWithGC(); + } + + private File createEmptyDictionaryAndGetFile(final String dictId, + final int formatVersion) throws IOException { + if (formatVersion == FormatSpec.VERSION4) { + return createEmptyVer4DictionaryAndGetFile(dictId); + } else { + throw new IOException("Dictionary format version " + formatVersion + + " is not supported."); } } - private File createEmptyDictionaryAndGetFile(final String filename) throws IOException { - final File file = File.createTempFile(filename, TEST_DICT_FILE_EXTENSION, + private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { + final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION, getContext().getCacheDir()); + FileUtils.deleteRecursively(file); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - attributeMap.put(FormatSpec.FileHeader.USES_FORGETTING_CURVE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - 3 /* dictVersion */, attributeMap)) { + attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId); + attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, + String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); + attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { return file; } else { - throw new IOException("Empty dictionary cannot be created."); + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); + } + } + + private static int setCurrentTimeForTestMode(final int currentTime) { + return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime); + } + + private static int stopTestModeInNativeCode() { + return BinaryDictionaryUtils.setCurrentTimeForTest(-1); + } + + public void testReadDictInJavaSide() { + testReadDictInJavaSide(FormatSpec.VERSION4); + } + + private void testReadDictInJavaSide(final int formatVersion) { + setCurrentTimeForTestMode(mCurrentTime); + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "ab", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "aaa", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "aaa", DUMMY_PROBABILITY); + binaryDictionary.flushWithGC(); + binaryDictionary.close(); + + final DictDecoder dictDecoder = + BinaryDictIOUtils.getDictDecoder(dictFile, 0, dictFile.length()); + try { + final FusionDictionary dict = + dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "a"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + assertNotNull(ptNode.getBigram("aaa")); + ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "ab"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"); + assertNotNull(ptNode); + assertTrue(ptNode.isTerminal()); + } catch (IOException e) { + fail("IOException while reading dictionary: " + e); + } catch (UnsupportedFormatException e) { + fail("Unsupported format: " + e); } + dictFile.delete(); + } + + public void testControlCurrentTime() { + testControlCurrentTime(FormatSpec.VERSION4); + } + + private void testControlCurrentTime(final int formatVersion) { + final int TEST_COUNT = 1000; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int startTime = stopTestModeInNativeCode(); + for (int i = 0; i < TEST_COUNT; i++) { + final int currentTime = random.nextInt(Integer.MAX_VALUE); + final int currentTimeInNativeCode = setCurrentTimeForTestMode(currentTime); + assertEquals(currentTime, currentTimeInNativeCode); + } + final int endTime = stopTestModeInNativeCode(); + final int MAX_ALLOWED_ELAPSED_TIME = 10; + assertTrue(startTime <= endTime && endTime <= startTime + MAX_ALLOWED_ELAPSED_TIME); } public void testAddValidAndInvalidWords() { + testAddValidAndInvalidWords(FormatSpec.VERSION4); + } + + private void testAddValidAndInvalidWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -99,36 +209,28 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); - assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); - assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); + addUnigramWord(binaryDictionary, "a", Dictionary.NOT_A_PROBABILITY); assertTrue(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidWord("b")); - final int unigramProbability = binaryDictionary.getFrequency("a"); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); - assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); - assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addBigramWords("a", "b", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", Dictionary.NOT_A_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addUnigramWord("c", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "c", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "c", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "c", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "c")); // Add bigrams of not valid unigrams. - binaryDictionary.addBigramWords("x", "y", Dictionary.NOT_A_PROBABILITY); + addBigramWords(binaryDictionary, "x", "y", Dictionary.NOT_A_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("x", "y")); - binaryDictionary.addBigramWords("x", "y", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "x", "y", DUMMY_PROBABILITY); assertFalse(binaryDictionary.isValidBigram("x", "y")); binaryDictionary.close(); @@ -136,9 +238,13 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } public void testDecayingProbability() { + testDecayingProbability(FormatSpec.VERSION4); + } + + private void testDecayingProbability(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -146,39 +252,36 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidWord("a")); forcePassingShortTime(binaryDictionary); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + assertTrue(binaryDictionary.isValidWord("a")); forcePassingShortTime(binaryDictionary); assertTrue(binaryDictionary.isValidWord("a")); forcePassingLongTime(binaryDictionary); assertFalse(binaryDictionary.isValidWord("a")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); forcePassingShortTime(binaryDictionary); assertFalse(binaryDictionary.isValidBigram("a", "b")); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("a", DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord("b", DUMMY_PROBABILITY); - binaryDictionary.addBigramWords("a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "a", DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, "b", DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, "a", "b", DUMMY_PROBABILITY); assertTrue(binaryDictionary.isValidBigram("a", "b")); forcePassingShortTime(binaryDictionary); assertTrue(binaryDictionary.isValidBigram("a", "b")); @@ -190,6 +293,10 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } public void testAddManyUnigramsToDecayingDict() { + testAddManyUnigramsToDecayingDict(FormatSpec.VERSION4); + } + + private void testAddManyUnigramsToDecayingDict(final int formatVersion) { final int unigramCount = 30000; final int unigramTypedCount = 100000; final int codePointSetSize = 50; @@ -198,13 +305,14 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); final ArrayList<String> words = new ArrayList<String>(); @@ -215,32 +323,98 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } final int maxUnigramCount = Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY)); + binaryDictionary.getPropertyForTest(BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY)); for (int i = 0; i < unigramTypedCount; i++) { final String word = words.get(random.nextInt(words.size())); - binaryDictionary.addUnigramWord(word, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { final int unigramCountBeforeGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)); while (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { - binaryDictionary.flushWithGC(); + forcePassingShortTime(binaryDictionary); } final int unigramCountAfterGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)); assertTrue(unigramCountBeforeGC > unigramCountAfterGC); } } - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)) > 0); - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.UNIGRAM_COUNT_QUERY)) <= maxUnigramCount); + forcePassingLongTime(binaryDictionary); + assertEquals(0, Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY))); + } + + public void testOverflowUnigrams() { + testOverflowUnigrams(FormatSpec.VERSION4); + } + + private void testOverflowUnigrams(final int formatVersion) { + final int unigramCount = 20000; + final int eachUnigramTypedCount = 2; + final int strongUnigramTypedCount = 20; + final int weakUnigramTypedCount = 1; + final int codePointSetSize = 50; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final String strong = "strong"; + final String weak = "weak"; + for (int j = 0; j < strongUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, strong, DUMMY_PROBABILITY); + } + for (int j = 0; j < weakUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, weak, DUMMY_PROBABILITY); + } + assertTrue(binaryDictionary.isValidWord(strong)); + assertTrue(binaryDictionary.isValidWord(weak)); + + for (int i = 0; i < unigramCount; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + for (int j = 0; j < eachUnigramTypedCount; j++) { + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + final int unigramCountBeforeGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY)); + assertTrue(binaryDictionary.isValidWord(strong)); + assertTrue(binaryDictionary.isValidWord(weak)); + binaryDictionary.flushWithGC(); + final int unigramCountAfterGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.UNIGRAM_COUNT_QUERY)); + assertTrue(unigramCountBeforeGC > unigramCountAfterGC); + assertFalse(binaryDictionary.isValidWord(weak)); + assertTrue(binaryDictionary.isValidWord(strong)); + break; + } + } } public void testAddManyBigramsToDecayingDict() { + testAddManyBigramsToDecayingDict(FormatSpec.VERSION4); + } + + private void testAddManyBigramsToDecayingDict(final int formatVersion) { final int unigramCount = 5000; final int bigramCount = 30000; final int bigramTypedCount = 100000; @@ -250,13 +424,14 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); final ArrayList<String> words = new ArrayList<String>(); @@ -279,30 +454,112 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } final int maxBigramCount = Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.MAX_BIGRAM_COUNT_QUERY)); + binaryDictionary.getPropertyForTest(BinaryDictionary.MAX_BIGRAM_COUNT_QUERY)); for (int i = 0; i < bigramTypedCount; ++i) { final Pair<String, String> bigram = bigrams.get(random.nextInt(bigrams.size())); - binaryDictionary.addUnigramWord(bigram.first, DUMMY_PROBABILITY); - binaryDictionary.addUnigramWord(bigram.second, DUMMY_PROBABILITY); - binaryDictionary.addBigramWords(bigram.first, bigram.second, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, bigram.first, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, bigram.second, DUMMY_PROBABILITY); + addBigramWords(binaryDictionary, bigram.first, bigram.second, DUMMY_PROBABILITY); if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { final int bigramCountBeforeGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)); while (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { - binaryDictionary.flushWithGC(); + forcePassingShortTime(binaryDictionary); } final int bigramCountAfterGC = - Integer.parseInt(binaryDictionary.getPropertyForTests( + Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)); assertTrue(bigramCountBeforeGC > bigramCountAfterGC); } } - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)) > 0); - assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTests( + assertTrue(Integer.parseInt(binaryDictionary.getPropertyForTest( BinaryDictionary.BIGRAM_COUNT_QUERY)) <= maxBigramCount); + forcePassingLongTime(binaryDictionary); + assertEquals(0, Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY))); + } + + public void testOverflowBigrams() { + testOverflowBigrams(FormatSpec.VERSION4); + } + + private void testOverflowBigrams(final int formatVersion) { + final int bigramCount = 20000; + final int unigramCount = 1000; + final int unigramTypedCount = 20; + final int eachBigramTypedCount = 2; + final int strongBigramTypedCount = 20; + final int weakBigramTypedCount = 1; + final int codePointSetSize = 50; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + setCurrentTimeForTestMode(mCurrentTime); + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final ArrayList<String> words = new ArrayList<String>(); + for (int i = 0; i < unigramCount; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + words.add(word); + for (int j = 0; j < unigramTypedCount; j++) { + addUnigramWord(binaryDictionary, word, DUMMY_PROBABILITY); + } + } + final String strong = "strong"; + final String weak = "weak"; + final String target = "target"; + for (int j = 0; j < unigramTypedCount; j++) { + addUnigramWord(binaryDictionary, strong, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, weak, DUMMY_PROBABILITY); + addUnigramWord(binaryDictionary, target, DUMMY_PROBABILITY); + } + binaryDictionary.flushWithGC(); + for (int j = 0; j < strongBigramTypedCount; j++) { + addBigramWords(binaryDictionary, strong, target, DUMMY_PROBABILITY); + } + for (int j = 0; j < weakBigramTypedCount; j++) { + addBigramWords(binaryDictionary, weak, target, DUMMY_PROBABILITY); + } + assertTrue(binaryDictionary.isValidBigram(strong, target)); + assertTrue(binaryDictionary.isValidBigram(weak, target)); + + for (int i = 0; i < bigramCount; i++) { + final int word0Index = random.nextInt(words.size()); + final String word0 = words.get(word0Index); + final int index = random.nextInt(words.size() - 1); + final int word1Index = (index >= word0Index) ? index + 1 : index; + final String word1 = words.get(word1Index); + + for (int j = 0; j < eachBigramTypedCount; j++) { + addBigramWords(binaryDictionary, word0, word1, DUMMY_PROBABILITY); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + final int bigramCountBeforeGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY)); + binaryDictionary.flushWithGC(); + final int bigramCountAfterGC = + Integer.parseInt(binaryDictionary.getPropertyForTest( + BinaryDictionary.BIGRAM_COUNT_QUERY)); + assertTrue(bigramCountBeforeGC > bigramCountAfterGC); + assertTrue(binaryDictionary.isValidBigram(strong, target)); + assertFalse(binaryDictionary.isValidBigram(weak, target)); + break; + } + } } } diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index 5b8f0e977..0fb0fa587 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -23,6 +23,11 @@ import android.util.Pair; import com.android.inputmethod.latin.makedict.CodePointUtils; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; +import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LanguageModelParam; import java.io.File; import java.io.IOException; @@ -33,39 +38,45 @@ import java.util.Locale; import java.util.Map; import java.util.Random; +// TODO Use the seed passed as an argument for makedict test. @LargeTest public class BinaryDictionaryTests extends AndroidTestCase { private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; private static final String TEST_LOCALE = "test"; - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); + private File createEmptyDictionaryAndGetFile(final String dictId, + final int formatVersion) throws IOException { + if (formatVersion == FormatSpec.VERSION4) { + return createEmptyVer4DictionaryAndGetFile(dictId); + } else { + throw new IOException("Dictionary format version " + formatVersion + + " is not supported."); + } } - private File createEmptyDictionaryAndGetFile(final String filename) throws IOException { - final File file = File.createTempFile(filename, TEST_DICT_FILE_EXTENSION, + private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { + final File file = File.createTempFile(dictId, TEST_DICT_FILE_EXTENSION, getContext().getCacheDir()); + file.delete(); + file.mkdir(); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), - 3 /* dictVersion */, attributeMap)) { + if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + Locale.ENGLISH, attributeMap)) { return file; } else { - throw new IOException("Empty dictionary cannot be created."); + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); } } public void testIsValidDictionary() { + testIsValidDictionary(FormatSpec.VERSION4); + } + + private void testIsValidDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -77,7 +88,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.close(); assertFalse("binaryDictionary must be invalid after closing.", binaryDictionary.isValidDictionary()); - dictFile.delete(); + FileUtils.deleteRecursively(dictFile); binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); @@ -86,10 +97,104 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.close(); } + public void testConstructingDictionaryOnMemory() { + testConstructingDictionaryOnMemory(FormatSpec.VERSION4); + } + + private void testConstructingDictionaryOnMemory(final int formatVersion) { + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + FileUtils.deleteRecursively(dictFile); + assertFalse(dictFile.exists()); + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + true /* useFullEditDistance */, Locale.getDefault(), TEST_LOCALE, formatVersion, + new HashMap<String, String>()); + assertTrue(binaryDictionary.isValidDictionary()); + assertEquals(formatVersion, binaryDictionary.getFormatVersion()); + final int probability = 100; + addUnigramWord(binaryDictionary, "word", probability); + assertEquals(probability, binaryDictionary.getFrequency("word")); + assertFalse(dictFile.exists()); + binaryDictionary.flush(); + assertTrue(dictFile.exists()); + assertTrue(binaryDictionary.isValidDictionary()); + assertEquals(formatVersion, binaryDictionary.getFormatVersion()); + assertEquals(probability, binaryDictionary.getFrequency("word")); + binaryDictionary.close(); + dictFile.delete(); + } + + public void testAddTooLongWord() { + testAddTooLongWord(FormatSpec.VERSION4); + } + + private void testAddTooLongWord(final int formatVersion) { + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final StringBuffer stringBuilder = new StringBuffer(); + for (int i = 0; i < Constants.DICTIONARY_MAX_WORD_LENGTH; i++) { + stringBuilder.append('a'); + } + final String validLongWord = stringBuilder.toString(); + stringBuilder.append('a'); + final String invalidLongWord = stringBuilder.toString(); + final int probability = 100; + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, validLongWord, probability); + addUnigramWord(binaryDictionary, invalidLongWord, probability); + // Too long short cut. + binaryDictionary.addUnigramWord("a", probability, invalidLongWord, + 10 /* shortcutProbability */, false /* isNotAWord */, false /* isBlacklisted */, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + addUnigramWord(binaryDictionary, "abc", probability); + final int updatedProbability = 200; + // Update. + addUnigramWord(binaryDictionary, validLongWord, updatedProbability); + addUnigramWord(binaryDictionary, invalidLongWord, updatedProbability); + addUnigramWord(binaryDictionary, "abc", updatedProbability); + + assertEquals(probability, binaryDictionary.getFrequency("aaa")); + assertEquals(updatedProbability, binaryDictionary.getFrequency(validLongWord)); + assertEquals(BinaryDictionary.NOT_A_PROBABILITY, + binaryDictionary.getFrequency(invalidLongWord)); + assertEquals(updatedProbability, binaryDictionary.getFrequency("abc")); + dictFile.delete(); + } + + private void addUnigramWord(final BinaryDictionary binaryDictionary, final String word, + final int probability) { + binaryDictionary.addUnigramWord(word, probability, "" /* shortcutTarget */, + BinaryDictionary.NOT_A_PROBABILITY /* shortcutProbability */, + false /* isNotAWord */, false /* isBlacklisted */, + BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */); + } + + private void addBigramWords(final BinaryDictionary binaryDictionary, final String word0, + final String word1, final int probability) { + binaryDictionary.addBigramWords(word0, word1, probability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */); + } + public void testAddUnigramWord() { + testAddUnigramWord(FormatSpec.VERSION4); + } + + private void testAddUnigramWord(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -98,21 +203,21 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int probability = 100; - binaryDictionary.addUnigramWord("aaa", probability); + addUnigramWord(binaryDictionary, "aaa", probability); // Reallocate and create. - binaryDictionary.addUnigramWord("aab", probability); + addUnigramWord(binaryDictionary, "aab", probability); // Insert into children. - binaryDictionary.addUnigramWord("aac", probability); + addUnigramWord(binaryDictionary, "aac", probability); // Make terminal. - binaryDictionary.addUnigramWord("aa", probability); + addUnigramWord(binaryDictionary, "aa", probability); // Create children. - binaryDictionary.addUnigramWord("aaaa", probability); + addUnigramWord(binaryDictionary, "aaaa", probability); // Reallocate and make termianl. - binaryDictionary.addUnigramWord("a", probability); + addUnigramWord(binaryDictionary, "a", probability); final int updatedProbability = 200; // Update. - binaryDictionary.addUnigramWord("aaa", updatedProbability); + addUnigramWord(binaryDictionary, "aaa", updatedProbability); assertEquals(probability, binaryDictionary.getFrequency("aab")); assertEquals(probability, binaryDictionary.getFrequency("aac")); @@ -125,13 +230,17 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testRandomlyAddUnigramWord() { + testRandomlyAddUnigramWord(FormatSpec.VERSION4); + } + + private void testRandomlyAddUnigramWord(final int formatVersion) { final int wordCount = 1000; final int codePointSetSize = 50; final long seed = System.currentTimeMillis(); File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -148,7 +257,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { probabilityMap.put(word, random.nextInt(0xFF)); } for (String word : probabilityMap.keySet()) { - binaryDictionary.addUnigramWord(word, probabilityMap.get(word)); + addUnigramWord(binaryDictionary, word, probabilityMap.get(word)); } for (String word : probabilityMap.keySet()) { assertEquals(word, (int)probabilityMap.get(word), binaryDictionary.getFrequency(word)); @@ -157,9 +266,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testAddBigramWords() { + testAddBigramWords(FormatSpec.VERSION4); + } + + private void testAddBigramWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -170,13 +283,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { final int unigramProbability = 100; final int bigramProbability = 10; final int updatedBigramProbability = 15; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); final int probability = binaryDictionary.calculateProbability(unigramProbability, bigramProbability); @@ -189,7 +302,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(probability, binaryDictionary.getBigramProbability("abb", "aaa")); assertEquals(probability, binaryDictionary.getBigramProbability("abb", "bcc")); - binaryDictionary.addBigramWords("aaa", "abb", updatedBigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", updatedBigramProbability); final int updatedProbability = binaryDictionary.calculateProbability(unigramProbability, updatedBigramProbability); assertEquals(updatedProbability, binaryDictionary.getBigramProbability("aaa", "abb")); @@ -205,22 +318,26 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.getBigramProbability("aaa", "aaa")); // Testing bigram link. - binaryDictionary.addUnigramWord("abcde", unigramProbability); - binaryDictionary.addUnigramWord("fghij", unigramProbability); - binaryDictionary.addBigramWords("abcde", "fghij", bigramProbability); - binaryDictionary.addUnigramWord("fgh", unigramProbability); - binaryDictionary.addUnigramWord("abc", unigramProbability); - binaryDictionary.addUnigramWord("f", unigramProbability); + addUnigramWord(binaryDictionary, "abcde", unigramProbability); + addUnigramWord(binaryDictionary, "fghij", unigramProbability); + addBigramWords(binaryDictionary, "abcde", "fghij", bigramProbability); + addUnigramWord(binaryDictionary, "fgh", unigramProbability); + addUnigramWord(binaryDictionary, "abc", unigramProbability); + addUnigramWord(binaryDictionary, "f", unigramProbability); assertEquals(probability, binaryDictionary.getBigramProbability("abcde", "fghij")); assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getBigramProbability("abcde", "fgh")); - binaryDictionary.addBigramWords("abcde", "fghij", updatedBigramProbability); + addBigramWords(binaryDictionary, "abcde", "fghij", updatedBigramProbability); assertEquals(updatedProbability, binaryDictionary.getBigramProbability("abcde", "fghij")); dictFile.delete(); } public void testRandomlyAddBigramWords() { + testRandomlyAddBigramWords(FormatSpec.VERSION4); + } + + private void testRandomlyAddBigramWords(final int formatVersion) { final int wordCount = 100; final int bigramCount = 1000; final int codePointSetSize = 50; @@ -229,7 +346,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -249,7 +366,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int i = 0; i < bigramCount; i++) { @@ -262,7 +379,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { bigramWords.add(bigram); final int bigramProbability = random.nextInt(0xF); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } for (final Pair<String, String> bigram : bigramWords) { @@ -278,9 +395,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testRemoveBigramWords() { + testRemoveBigramWords(FormatSpec.VERSION4); + } + + private void testRemoveBigramWords(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -289,13 +410,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int unigramProbability = 100; final int bigramProbability = 10; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb")); assertEquals(true, binaryDictionary.isValidBigram("aaa", "bcc")); @@ -304,7 +425,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { binaryDictionary.removeBigramWords("aaa", "abb"); assertEquals(false, binaryDictionary.isValidBigram("aaa", "abb")); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb")); @@ -324,9 +445,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testFlushDictionary() { + testFlushDictionary(FormatSpec.VERSION4); + } + + private void testFlushDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -335,8 +460,8 @@ public class BinaryDictionaryTests extends AndroidTestCase { Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); final int probability = 100; - binaryDictionary.addUnigramWord("aaa", probability); - binaryDictionary.addUnigramWord("abcd", probability); + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, "abcd", probability); // Close without flushing. binaryDictionary.close(); @@ -347,8 +472,8 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("aaa")); assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("abcd")); - binaryDictionary.addUnigramWord("aaa", probability); - binaryDictionary.addUnigramWord("abcd", probability); + addUnigramWord(binaryDictionary, "aaa", probability); + addUnigramWord(binaryDictionary, "abcd", probability); binaryDictionary.flush(); binaryDictionary.close(); @@ -358,7 +483,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { assertEquals(probability, binaryDictionary.getFrequency("aaa")); assertEquals(probability, binaryDictionary.getFrequency("abcd")); - binaryDictionary.addUnigramWord("bcde", probability); + addUnigramWord(binaryDictionary, "bcde", probability); binaryDictionary.flush(); binaryDictionary.close(); @@ -372,9 +497,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testFlushWithGCDictionary() { + testFlushWithGCDictionary(FormatSpec.VERSION4); + } + + private void testFlushWithGCDictionary(final int formatVersion) { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -384,13 +513,13 @@ public class BinaryDictionaryTests extends AndroidTestCase { final int unigramProbability = 100; final int bigramProbability = 10; - binaryDictionary.addUnigramWord("aaa", unigramProbability); - binaryDictionary.addUnigramWord("abb", unigramProbability); - binaryDictionary.addUnigramWord("bcc", unigramProbability); - binaryDictionary.addBigramWords("aaa", "abb", bigramProbability); - binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability); - binaryDictionary.addBigramWords("abb", "aaa", bigramProbability); - binaryDictionary.addBigramWords("abb", "bcc", bigramProbability); + addUnigramWord(binaryDictionary, "aaa", unigramProbability); + addUnigramWord(binaryDictionary, "abb", unigramProbability); + addUnigramWord(binaryDictionary, "bcc", unigramProbability); + addBigramWords(binaryDictionary, "aaa", "abb", bigramProbability); + addBigramWords(binaryDictionary, "aaa", "bcc", bigramProbability); + addBigramWords(binaryDictionary, "abb", "aaa", bigramProbability); + addBigramWords(binaryDictionary, "abb", "bcc", bigramProbability); binaryDictionary.flushWithGC(); binaryDictionary.close(); @@ -415,8 +544,12 @@ public class BinaryDictionaryTests extends AndroidTestCase { dictFile.delete(); } - // TODO: Evaluate performance of GC public void testAddBigramWordsAndFlashWithGC() { + testAddBigramWordsAndFlashWithGC(FormatSpec.VERSION4); + } + + // TODO: Evaluate performance of GC + private void testAddBigramWordsAndFlashWithGC(final int formatVersion) { final int wordCount = 100; final int bigramCount = 1000; final int codePointSetSize = 30; @@ -425,7 +558,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -446,7 +579,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int i = 0; i < bigramCount; i++) { @@ -459,7 +592,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { bigramWords.add(bigram); final int bigramProbability = random.nextInt(0xF); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } binaryDictionary.flushWithGC(); @@ -480,7 +613,11 @@ public class BinaryDictionaryTests extends AndroidTestCase { dictFile.delete(); } - public void testRandomOperetionsAndFlashWithGC() { + public void testRandomOperationsAndFlashWithGC() { + testRandomOperationsAndFlashWithGC(FormatSpec.VERSION4); + } + + private void testRandomOperationsAndFlashWithGC(final int formatVersion) { final int flashWithGCIterationCount = 50; final int operationCountInEachIteration = 200; final int initialUnigramCount = 100; @@ -494,7 +631,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -513,7 +650,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } binaryDictionary.flushWithGC(); binaryDictionary.close(); @@ -529,7 +666,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } // Add bigram. if (random.nextFloat() < addBigramProb && words.size() > 2) { @@ -547,7 +684,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { final Pair<String, String> bigram = new Pair<String, String>(word0, word1); bigramWords.add(bigram); bigramProbabilities.put(bigram, bigramProbability); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } // Remove bigram. if (random.nextFloat() < removeBigramProb && !bigramWords.isEmpty()) { @@ -588,6 +725,10 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testAddManyUnigramsAndFlushWithGC() { + testAddManyUnigramsAndFlushWithGC(FormatSpec.VERSION4); + } + + private void testAddManyUnigramsAndFlushWithGC(final int formatVersion) { final int flashWithGCIterationCount = 3; final int codePointSetSize = 50; @@ -596,7 +737,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -615,7 +756,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { words.add(word); final int unigramProbability = random.nextInt(0xFF); unigramProbabilities.put(word, unigramProbability); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int j = 0; j < words.size(); j++) { @@ -632,6 +773,10 @@ public class BinaryDictionaryTests extends AndroidTestCase { } public void testUnigramAndBigramCount() { + testUnigramAndBigramCount(FormatSpec.VERSION4); + } + + private void testUnigramAndBigramCount(final int formatVersion) { final int flashWithGCIterationCount = 10; final int codePointSetSize = 50; final int unigramCountPerIteration = 1000; @@ -641,7 +786,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { File dictFile = null; try { - dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary"); + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); } @@ -659,7 +804,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { final String word = CodePointUtils.generateWord(random, codePointSet); words.add(word); final int unigramProbability = random.nextInt(0xFF); - binaryDictionary.addUnigramWord(word, unigramProbability); + addUnigramWord(binaryDictionary, word, unigramProbability); } for (int j = 0; j < bigramCountPerIteration; j++) { final String word0 = words.get(random.nextInt(words.size())); @@ -669,20 +814,413 @@ public class BinaryDictionaryTests extends AndroidTestCase { } bigrams.add(new Pair<String, String>(word0, word1)); final int bigramProbability = random.nextInt(0xF); - binaryDictionary.addBigramWords(word0, word1, bigramProbability); + addBigramWords(binaryDictionary, word0, word1, bigramProbability); } assertEquals(new HashSet<String>(words).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.UNIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.UNIGRAM_COUNT_QUERY))); assertEquals(new HashSet<Pair<String, String>>(bigrams).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.BIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.BIGRAM_COUNT_QUERY))); binaryDictionary.flushWithGC(); assertEquals(new HashSet<String>(words).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.UNIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.UNIGRAM_COUNT_QUERY))); assertEquals(new HashSet<Pair<String, String>>(bigrams).size(), Integer.parseInt( - binaryDictionary.getPropertyForTests(BinaryDictionary.BIGRAM_COUNT_QUERY))); + binaryDictionary.getPropertyForTest(BinaryDictionary.BIGRAM_COUNT_QUERY))); binaryDictionary.close(); } dictFile.delete(); } + + public void testAddMultipleDictionaryEntries() { + testAddMultipleDictionaryEntries(FormatSpec.VERSION4); + } + + private void testAddMultipleDictionaryEntries(final int formatVersion) { + final int codePointSetSize = 20; + final int lmParamCount = 1000; + final double bigramContinueRate = 0.9; + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilities = + new HashMap<Pair<String, String>, Integer>(); + + final LanguageModelParam[] languageModelParams = new LanguageModelParam[lmParamCount]; + String prevWord = null; + for (int i = 0; i < languageModelParams.length; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int probability = random.nextInt(0xFF); + final int bigramProbability = random.nextInt(0xF); + unigramProbabilities.put(word, probability); + if (prevWord == null) { + languageModelParams[i] = new LanguageModelParam(word, probability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + } else { + languageModelParams[i] = new LanguageModelParam(prevWord, word, probability, + bigramProbability, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + bigramProbabilities.put(new Pair<String, String>(prevWord, word), + bigramProbability); + } + prevWord = (random.nextDouble() < bigramContinueRate) ? word : null; + } + + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + binaryDictionary.addMultipleDictionaryEntries(languageModelParams); + + for (Map.Entry<String, Integer> entry : unigramProbabilities.entrySet()) { + assertEquals((int)entry.getValue(), binaryDictionary.getFrequency(entry.getKey())); + } + + for (Map.Entry<Pair<String, String>, Integer> entry : bigramProbabilities.entrySet()) { + final String word0 = entry.getKey().first; + final String word1 = entry.getKey().second; + final int unigramProbability = unigramProbabilities.get(word1); + final int bigramProbability = entry.getValue(); + final int probability = binaryDictionary.calculateProbability( + unigramProbability, bigramProbability); + assertEquals(probability, binaryDictionary.getBigramProbability(word0, word1)); + } + } + + public void testGetWordProperties() { + testGetWordProperties(FormatSpec.VERSION4); + } + + private void testGetWordProperties(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int BIGRAM_COUNT = 1000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord"); + assertFalse(invalidWordProperty.isValid()); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> wordProbabilities = new HashMap<String, Integer>(); + final HashMap<String, HashSet<String>> bigrams = new HashMap<String, HashSet<String>>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilities = + new HashMap<Pair<String, String>, Integer>(); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + final boolean isNotAWord = random.nextBoolean(); + final boolean isBlacklisted = random.nextBoolean(); + // TODO: Add tests for historical info. + binaryDictionary.addUnigramWord(word, unigramProbability, + null /* shortcutTarget */, BinaryDictionary.NOT_A_PROBABILITY, + isNotAWord, isBlacklisted, BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + words.add(word); + wordProbabilities.put(word, unigramProbability); + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals(word, wordProperty.mWord); + assertTrue(wordProperty.isValid()); + assertEquals(isNotAWord, wordProperty.mIsNotAWord); + assertEquals(isBlacklisted, wordProperty.mIsBlacklistEntry); + assertEquals(false, wordProperty.mHasBigrams); + assertEquals(false, wordProperty.mHasShortcuts); + assertEquals(unigramProbability, wordProperty.mProbabilityInfo.mProbability); + assertTrue(wordProperty.mShortcutTargets.isEmpty()); + } + + for (int i = 0; i < BIGRAM_COUNT; i++) { + final int word0Index = random.nextInt(wordProbabilities.size()); + final int word1Index = random.nextInt(wordProbabilities.size()); + if (word0Index == word1Index) { + continue; + } + final String word0 = words.get(word0Index); + final String word1 = words.get(word1Index); + final int bigramProbability = random.nextInt(0xF); + binaryDictionary.addBigramWords(word0, word1, bigramProbability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + if (!bigrams.containsKey(word0)) { + final HashSet<String> bigramWord1s = new HashSet<String>(); + bigrams.put(word0, bigramWord1s); + } + bigrams.get(word0).add(word1); + bigramProbabilities.put(new Pair<String, String>(word0, word1), bigramProbability); + } + + for (int i = 0; i < words.size(); i++) { + final String word0 = words.get(i); + if (!bigrams.containsKey(word0)) { + continue; + } + final HashSet<String> bigramWord1s = bigrams.get(word0); + final WordProperty wordProperty = binaryDictionary.getWordProperty(word0); + assertEquals(bigramWord1s.size(), wordProperty.mBigrams.size()); + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + assertTrue(bigramWord1s.contains(word1)); + final int bigramProbabilityDelta = bigramProbabilities.get( + new Pair<String, String>(word0, word1)); + final int unigramProbability = wordProbabilities.get(word1); + final int bigramProbablity = binaryDictionary.calculateProbability( + unigramProbability, bigramProbabilityDelta); + assertEquals(wordProperty.mBigrams.get(j).getProbability(), bigramProbablity); + } + } + } + + public void testIterateAllWords() { + testIterateAllWords(FormatSpec.VERSION4); + } + + private void testIterateAllWords(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int BIGRAM_COUNT = 1000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final WordProperty invalidWordProperty = binaryDictionary.getWordProperty("dummyWord"); + assertFalse(invalidWordProperty.isValid()); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> wordProbabilitiesToCheckLater = + new HashMap<String, Integer>(); + final HashMap<String, HashSet<String>> bigrams = new HashMap<String, HashSet<String>>(); + final HashMap<Pair<String, String>, Integer> bigramProbabilitiesToCheckLater = + new HashMap<Pair<String, String>, Integer>(); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + addUnigramWord(binaryDictionary, word, unigramProbability); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + words.add(word); + wordProbabilitiesToCheckLater.put(word, unigramProbability); + } + + for (int i = 0; i < BIGRAM_COUNT; i++) { + final int word0Index = random.nextInt(wordProbabilitiesToCheckLater.size()); + final int word1Index = random.nextInt(wordProbabilitiesToCheckLater.size()); + if (word0Index == word1Index) { + continue; + } + final String word0 = words.get(word0Index); + final String word1 = words.get(word1Index); + final int bigramProbability = random.nextInt(0xF); + binaryDictionary.addBigramWords(word0, word1, bigramProbability, + BinaryDictionary.NOT_A_VALID_TIMESTAMP); + if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + if (!bigrams.containsKey(word0)) { + final HashSet<String> bigramWord1s = new HashSet<String>(); + bigrams.put(word0, bigramWord1s); + } + bigrams.get(word0).add(word1); + bigramProbabilitiesToCheckLater.put( + new Pair<String, String>(word0, word1), bigramProbability); + } + + final HashSet<String> wordSet = new HashSet<String>(words); + final HashSet<Pair<String, String>> bigramSet = + new HashSet<Pair<String,String>>(bigramProbabilitiesToCheckLater.keySet()); + int token = 0; + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + final String word0 = wordProperty.mWord; + assertEquals((int)wordProbabilitiesToCheckLater.get(word0), + wordProperty.mProbabilityInfo.mProbability); + wordSet.remove(word0); + final HashSet<String> bigramWord1s = bigrams.get(word0); + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + assertTrue(bigramWord1s.contains(word1)); + final int unigramProbability = wordProbabilitiesToCheckLater.get(word1); + final Pair<String, String> bigram = new Pair<String, String>(word0, word1); + final int bigramProbabilityDelta = bigramProbabilitiesToCheckLater.get(bigram); + final int bigramProbablity = binaryDictionary.calculateProbability( + unigramProbability, bigramProbabilityDelta); + assertEquals(wordProperty.mBigrams.get(j).getProbability(), bigramProbablity); + bigramSet.remove(bigram); + } + token = result.mNextToken; + } while (token != 0); + assertTrue(wordSet.isEmpty()); + assertTrue(bigramSet.isEmpty()); + } + + public void testAddShortcuts() { + testAddShortcuts(FormatSpec.VERSION4); + } + + private void testAddShortcuts(final int formatVersion) { + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + final int unigramProbability = 100; + final int shortcutProbability = 10; + binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz", + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + WordProperty wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(1, wordProperty.mShortcutTargets.size()); + assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord); + assertEquals(shortcutProbability, wordProperty.mShortcutTargets.get(0).getProbability()); + final int updatedShortcutProbability = 2; + binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz", + updatedShortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(1, wordProperty.mShortcutTargets.size()); + assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord); + assertEquals(updatedShortcutProbability, + wordProperty.mShortcutTargets.get(0).getProbability()); + binaryDictionary.addUnigramWord("aaa", unigramProbability, "yyy", + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + final HashMap<String, Integer> shortcutTargets = new HashMap<String, Integer>(); + shortcutTargets.put("zzz", updatedShortcutProbability); + shortcutTargets.put("yyy", shortcutProbability); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(2, wordProperty.mShortcutTargets.size()); + for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord)); + assertEquals((int)shortcutTargets.get(shortcutTarget.mWord), + shortcutTarget.getProbability()); + shortcutTargets.remove(shortcutTarget.mWord); + } + shortcutTargets.put("zzz", updatedShortcutProbability); + shortcutTargets.put("yyy", shortcutProbability); + binaryDictionary.flushWithGC(); + wordProperty = binaryDictionary.getWordProperty("aaa"); + assertEquals(2, wordProperty.mShortcutTargets.size()); + for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord)); + assertEquals((int)shortcutTargets.get(shortcutTarget.mWord), + shortcutTarget.getProbability()); + shortcutTargets.remove(shortcutTarget.mWord); + } + } + + public void testAddManyShortcuts() { + testAddManyShortcuts(FormatSpec.VERSION4); + } + + private void testAddManyShortcuts(final int formatVersion) { + final long seed = System.currentTimeMillis(); + final Random random = new Random(seed); + final int UNIGRAM_COUNT = 1000; + final int SHORTCUT_COUNT = 10000; + final int codePointSetSize = 20; + final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); + + final ArrayList<String> words = new ArrayList<String>(); + final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>(); + final HashMap<String, HashMap<String, Integer>> shortcutTargets = + new HashMap<String, HashMap<String, Integer>>(); + + File dictFile = null; + try { + dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), + 0 /* offset */, dictFile.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + + for (int i = 0; i < UNIGRAM_COUNT; i++) { + final String word = CodePointUtils.generateWord(random, codePointSet); + final int unigramProbability = random.nextInt(0xFF); + addUnigramWord(binaryDictionary, word, unigramProbability); + words.add(word); + unigramProbabilities.put(word, unigramProbability); + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + } + for (int i = 0; i < SHORTCUT_COUNT; i++) { + final String shortcutTarget = CodePointUtils.generateWord(random, codePointSet); + final int shortcutProbability = random.nextInt(0xF); + final String word = words.get(random.nextInt(words.size())); + final int unigramProbability = unigramProbabilities.get(word); + binaryDictionary.addUnigramWord(word, unigramProbability, shortcutTarget, + shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */, + 0 /* timestamp */); + if (shortcutTargets.containsKey(word)) { + final HashMap<String, Integer> shortcutTargetsOfWord = shortcutTargets.get(word); + shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability); + } else { + final HashMap<String, Integer> shortcutTargetsOfWord = + new HashMap<String, Integer>(); + shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability); + shortcutTargets.put(word, shortcutTargetsOfWord); + } + if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDictionary.flushWithGC(); + } + } + + for (final String word : words) { + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals((int)unigramProbabilities.get(word), + wordProperty.mProbabilityInfo.mProbability); + if (!shortcutTargets.containsKey(word)) { + // The word does not have shortcut targets. + continue; + } + assertEquals(shortcutTargets.get(word).size(), wordProperty.mShortcutTargets.size()); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + final String targetCodePonts = shortcutTarget.mWord; + assertEquals((int)shortcutTargets.get(word).get(targetCodePonts), + shortcutTarget.getProbability()); + } + } + } } diff --git a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java index c4fd5a0c4..6e894decf 100644 --- a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java +++ b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java @@ -50,8 +50,7 @@ public class BlueUnderlineTests extends InputTestsBase { final SpanGetter spanBefore = new SpanGetter(mEditText.getText(), SuggestionSpan.class); assertEquals("extend blue underline, span start", EXPECTED_SPAN_START, spanBefore.mStart); assertEquals("extend blue underline, span end", EXPECTED_SPAN_END, spanBefore.mEnd); - assertEquals("extend blue underline, span color", true, - spanBefore.isAutoCorrectionIndicator()); + assertTrue("extend blue underline, span color", spanBefore.isAutoCorrectionIndicator()); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); // Now we have been able to re-evaluate the word, there shouldn't be an auto-correction span @@ -61,6 +60,7 @@ public class BlueUnderlineTests extends InputTestsBase { public void testBlueUnderlineOnBackspace() { final String STRING_TO_TYPE = "tgis"; + final int typedLength = STRING_TO_TYPE.length(); final int EXPECTED_SUGGESTION_SPAN_START = -1; final int EXPECTED_UNDERLINE_SPAN_START = 0; final int EXPECTED_UNDERLINE_SPAN_END = 4; @@ -68,6 +68,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); type(Constants.CODE_SPACE); + // typedLength + 1 because we also typed a space + mLatinIME.onUpdateSelection(0, 0, typedLength + 1, typedLength + 1, -1, -1); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); type(Constants.CODE_DELETE); @@ -77,8 +79,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); final SpanGetter suggestionSpan = new SpanGetter(mEditText.getText(), SuggestionSpan.class); - assertEquals("show no blue underline after backspace, span start should be -1", - EXPECTED_SUGGESTION_SPAN_START, suggestionSpan.mStart); + assertFalse("show no blue underline after backspace, span should not be the auto-" + + "correction indicator", suggestionSpan.isAutoCorrectionIndicator()); final SpanGetter underlineSpan = new SpanGetter(mEditText.getText(), UnderlineSpan.class); assertEquals("should be composing, so should have an underline span", EXPECTED_UNDERLINE_SPAN_START, underlineSpan.mStart); @@ -104,7 +106,8 @@ public class BlueUnderlineTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); final SpanGetter span = new SpanGetter(mEditText.getText(), SuggestionSpan.class); - assertNull("blue underline removed when cursor is moved", span.mSpan); + assertFalse("blue underline removed when cursor is moved", + span.isAutoCorrectionIndicator()); } public void testComposingStopsOnSpace() { diff --git a/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java b/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java deleted file mode 100644 index 6aae1044e..000000000 --- a/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2013 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.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -/** - * Unit test for ExpandableDictionary - */ -@SmallTest -public class ExpandableDictionaryTests extends AndroidTestCase { - - private final static int UNIGRAM_FREQ = 50; - // See UserBinaryDictionary for more information about this variable. - // For tests, its actual value does not matter. - private final static int SHORTCUT_FREQ = 14; - - public void testAddWordAndGetWordFrequency() { - final ExpandableDictionary dict = new ExpandableDictionary(Dictionary.TYPE_USER); - - // Add words - dict.addWord("abcde", "abcde", UNIGRAM_FREQ, SHORTCUT_FREQ); - dict.addWord("abcef", null, UNIGRAM_FREQ + 1, 0); - - // Check words - assertFalse(dict.isValidWord("abcde")); - assertEquals(UNIGRAM_FREQ, dict.getWordFrequency("abcde")); - assertTrue(dict.isValidWord("abcef")); - assertEquals(UNIGRAM_FREQ+1, dict.getWordFrequency("abcef")); - - dict.addWord("abc", null, UNIGRAM_FREQ + 2, 0); - assertTrue(dict.isValidWord("abc")); - assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc")); - - // Add existing word with lower frequency - dict.addWord("abc", null, UNIGRAM_FREQ, 0); - assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc")); - - // Add existing word with higher frequency - dict.addWord("abc", null, UNIGRAM_FREQ + 3, 0); - assertEquals(UNIGRAM_FREQ + 3, dict.getWordFrequency("abc")); - } -} diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java index cadd0f8f3..09309bcc0 100644 --- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java @@ -19,7 +19,9 @@ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import java.util.HashMap; @@ -31,18 +33,18 @@ import java.util.HashMap; public class FusionDictionaryTests extends AndroidTestCase { public void testFindWordInTree() { FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); + new DictionaryOptions(new HashMap<String,String>())); - dict.add("abc", 10, null, false /* isNotAWord */); + dict.add("abc", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc")); - dict.add("aa", 10, null, false /* isNotAWord */); + dict.add("aa", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa")); - dict.add("babcd", 10, null, false /* isNotAWord */); - dict.add("bacde", 10, null, false /* isNotAWord */); + dict.add("babcd", new ProbabilityInfo(10), null, false /* isNotAWord */); + dict.add("bacde", new ProbabilityInfo(10), null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd")); assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "bacde")); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 8ad8689d8..d2dd29262 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -16,7 +16,10 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.settings.Settings; + import android.test.suitebuilder.annotation.LargeTest; +import android.text.TextUtils; import android.view.inputmethod.BaseInputConnection; @LargeTest @@ -179,6 +182,8 @@ public class InputLogicTests extends InputTestsBase { } public void testDoubleSpace() { + // Set default pref just in case + setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true); // U+1F607 is an emoji final String[] STRINGS_TO_TYPE = new String[] { "this ", "a+ ", "\u1F607 ", ".. ", ") ", "( ", "% " }; @@ -200,6 +205,76 @@ public class InputLogicTests extends InputTestsBase { assertEquals("double space make a period", EXPECTED_RESULT, mEditText.getText().toString()); } + private void testDoubleSpacePeriodWithSettings(final boolean expectsPeriod, + final Object... settingsKeysValues) { + final Object[] oldSettings = new Object[settingsKeysValues.length / 2]; + final String STRING_WITHOUT_PERIOD = "this "; + final String STRING_WITH_PERIOD = "this. "; + final String EXPECTED_RESULT = expectsPeriod ? STRING_WITH_PERIOD : STRING_WITHOUT_PERIOD; + try { + for (int i = 0; i < settingsKeysValues.length; i += 2) { + if (settingsKeysValues[i + 1] instanceof String) { + oldSettings[i / 2] = setStringPreference((String)settingsKeysValues[i], + (String)settingsKeysValues[i + 1], "0"); + } else { + oldSettings[i / 2] = setBooleanPreference((String)settingsKeysValues[i], + (Boolean)settingsKeysValues[i + 1], false); + } + } + mLatinIME.loadSettings(); + mEditText.setText(""); + type(STRING_WITHOUT_PERIOD); + assertEquals("double-space-to-period with specific settings " + + TextUtils.join(" ", settingsKeysValues), + EXPECTED_RESULT, mEditText.getText().toString()); + } finally { + // Restore old settings + for (int i = 0; i < settingsKeysValues.length; i += 2) { + if (null == oldSettings[i / 2]) { + break; + } if (oldSettings[i / 2] instanceof String) { + setStringPreference((String)settingsKeysValues[i], (String)oldSettings[i / 2], + ""); + } else { + setBooleanPreference((String)settingsKeysValues[i], (Boolean)oldSettings[i / 2], + false); + } + } + } + } + + public void testDoubleSpacePeriod() { + // Reset settings to default, else these tests will go flaky. + setStringPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING, "0", "0"); + setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, "1", "1"); + setBooleanPreference(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true, true); + testDoubleSpacePeriodWithSettings(true /* expectsPeriod */); + // "Suggestion visibility" to "always hide" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS_SETTING, "2"); + // "Suggestion visibility" to "portrait only" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS_SETTING, "1"); + // "Suggestion visibility" to "always show" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS_SETTING, "0"); + + // "Double-space period" to "off" + testDoubleSpacePeriodWithSettings(false, Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false); + + // "Auto-correction" to "off" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0"); + // "Auto-correction" to "modest" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "1"); + // "Auto-correction" to "very aggressive" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_AUTO_CORRECTION_THRESHOLD, "3"); + + // "Suggestion visibility" to "always hide" and "Auto-correction" to "off" + testDoubleSpacePeriodWithSettings(true, Settings.PREF_SHOW_SUGGESTIONS_SETTING, "0", + Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0"); + // "Suggestion visibility" to "always hide" and "Auto-correction" to "off" + testDoubleSpacePeriodWithSettings(false, Settings.PREF_SHOW_SUGGESTIONS_SETTING, "0", + Settings.PREF_AUTO_CORRECTION_THRESHOLD, "0", + Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, false); + } + public void testBackspaceAtStartAfterAutocorrect() { final String STRING_TO_TYPE = "tgis "; final int typedLength = STRING_TO_TYPE.length(); @@ -307,12 +382,14 @@ public class InputLogicTests extends InputTestsBase { } public void testResumeSuggestionOnBackspace() { - final String WORD_TO_TYPE = "and this "; - type(WORD_TO_TYPE); + final String STRING_TO_TYPE = "and this "; + final int typedLength = STRING_TO_TYPE.length(); + type(STRING_TO_TYPE); assertEquals("resume suggestion on backspace", -1, BaseInputConnection.getComposingSpanStart(mEditText.getText())); assertEquals("resume suggestion on backspace", -1, BaseInputConnection.getComposingSpanEnd(mEditText.getText())); + mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1); type(Constants.CODE_DELETE); assertEquals("resume suggestion on backspace", 4, BaseInputConnection.getComposingSpanStart(mEditText.getText())); @@ -348,4 +425,167 @@ public class InputLogicTests extends InputTestsBase { helperTestComposing("a'", true); } // TODO: Add some tests for non-BMP characters + + public void testAutoCorrectByUserHistory() { + final String WORD_TO_BE_CORRECTED = "qpmx"; + final String NOT_CORRECTED_RESULT = "qpmx "; + final String DESIRED_WORD = "qpmz"; + final String CORRECTED_RESULT = "qpmz "; + final int typeCountNotToAutocorrect = 1; + final int typeCountToAutoCorrect = 16; + int startIndex = 0; + int endIndex = 0; + + for (int i = 0; i < typeCountNotToAutocorrect; i++) { + type(DESIRED_WORD); + type(Constants.CODE_SPACE); + } + startIndex = mEditText.getText().length(); + type(WORD_TO_BE_CORRECTED); + type(Constants.CODE_SPACE); + endIndex = mEditText.getText().length(); + assertEquals("not auto-corrected by user history", NOT_CORRECTED_RESULT, + mEditText.getText().subSequence(startIndex, endIndex).toString()); + for (int i = typeCountNotToAutocorrect; i < typeCountToAutoCorrect; i++) { + type(DESIRED_WORD); + type(Constants.CODE_SPACE); + } + startIndex = mEditText.getText().length(); + type(WORD_TO_BE_CORRECTED); + type(Constants.CODE_SPACE); + endIndex = mEditText.getText().length(); + assertEquals("auto-corrected by user history", + CORRECTED_RESULT, mEditText.getText().subSequence(startIndex, endIndex).toString()); + } + + public void testPredictionsAfterSpace() { + final String WORD_TO_TYPE = "Barack "; + type(WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after space", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } + + public void testPredictionsAfterManualPick() { + final String WORD_TO_TYPE = "Barack"; + type(WORD_TO_TYPE); + // Choose the auto-correction, which is always in position 0. For "Barack", the + // auto-correction should be "Barack". + pickSuggestionManually(0, WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after manual pick", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } + + public void testNoPredictionsAfterPeriod() { + final String WORD_TO_TYPE = "Barack. "; + type(WORD_TO_TYPE); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is not displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("no prediction after period", 0, suggestedWords.size()); + } + + public void testPredictionsAfterRecorrection() { + final String PREFIX = "A "; + final String WORD_TO_TYPE = "Barack"; + final String FIRST_NON_TYPED_SUGGESTION = "Barrack"; + final int endOfPrefix = PREFIX.length(); + final int endOfWord = endOfPrefix + WORD_TO_TYPE.length(); + final int endOfSuggestion = endOfPrefix + FIRST_NON_TYPED_SUGGESTION.length(); + final int indexForManualCursor = endOfPrefix + 3; // +3 because it's after "Bar" in "Barack" + type(PREFIX); + mLatinIME.onUpdateSelection(0, 0, endOfPrefix, endOfPrefix, -1, -1); + type(WORD_TO_TYPE); + pickSuggestionManually(1, FIRST_NON_TYPED_SUGGESTION); + mLatinIME.onUpdateSelection(endOfPrefix, endOfPrefix, endOfSuggestion, endOfSuggestion, + -1, -1); + runMessages(); + type(" "); + mLatinIME.onUpdateSelection(endOfSuggestion, endOfSuggestion, + endOfSuggestion + 1, endOfSuggestion + 1, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Simulate a manual cursor move + mInputConnection.setSelection(indexForManualCursor, indexForManualCursor); + mLatinIME.onUpdateSelection(endOfSuggestion + 1, endOfSuggestion + 1, + indexForManualCursor, indexForManualCursor, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(indexForManualCursor, indexForManualCursor, + endOfWord, endOfWord, -1, -1); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); + assertEquals("predictions after recorrection", "Obama", + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); + } + + public void testComposingMultipleBackspace() { + final String WORD_TO_TYPE = "radklro"; + final int TIMES_TO_TYPE = 3; + final int TIMES_TO_BACKSPACE = 8; + type(WORD_TO_TYPE); + type(Constants.CODE_DELETE); + type(Constants.CODE_DELETE); + type(Constants.CODE_DELETE); + type(WORD_TO_TYPE); + type(Constants.CODE_DELETE); + type(Constants.CODE_DELETE); + type(WORD_TO_TYPE); + type(Constants.CODE_DELETE); + type(Constants.CODE_DELETE); + type(Constants.CODE_DELETE); + assertEquals("composing with multiple backspace", + WORD_TO_TYPE.length() * TIMES_TO_TYPE - TIMES_TO_BACKSPACE, + mEditText.getText().length()); + } + + public void testManySingleQuotes() { + final String WORD_TO_AUTOCORRECT = "i"; + final String WORD_AUTOCORRECTED = "I"; + final String QUOTES = "''''''''''''''''''''"; + final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " "; + final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " "; + type(WORD_TO_TYPE); + assertEquals("auto-correct with many trailing single quotes", EXPECTED_RESULT, + mEditText.getText().toString()); + } + + public void testManySingleQuotesOneByOne() { + final String WORD_TO_AUTOCORRECT = "i"; + final String WORD_AUTOCORRECTED = "I"; + final String QUOTES = "''''''''''''''''''''"; + final String WORD_TO_TYPE = WORD_TO_AUTOCORRECT + QUOTES + " "; + final String EXPECTED_RESULT = WORD_AUTOCORRECTED + QUOTES + " "; + + for (int i = 0; i < WORD_TO_TYPE.length(); ++i) { + type(WORD_TO_TYPE.substring(i, i+1)); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + } + assertEquals("type many trailing single quotes one by one", EXPECTED_RESULT, + mEditText.getText().toString()); + } + + public void testTypingSingleQuotesOneByOne() { + final String WORD_TO_TYPE = "it's "; + final String EXPECTED_RESULT = WORD_TO_TYPE; + for (int i = 0; i < WORD_TO_TYPE.length(); ++i) { + type(WORD_TO_TYPE.substring(i, i+1)); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + } + assertEquals("type words letter by letter", EXPECTED_RESULT, + mEditText.getText().toString()); + } } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java index 0f0ebafb9..e38ba721e 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java @@ -99,7 +99,8 @@ public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase { assertEquals("predictions in lang without spaces", "Barack", mEditText.getText().toString()); // Test the first prediction is displayed + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); assertEquals("predictions in lang without spaces", "Obama", - mLatinIME.getFirstSuggestedWord()); + suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); } } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java index 2d736e338..1257ae297 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java @@ -60,7 +60,7 @@ public class InputLogicTestsNonEnglish extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); assertTrue("type word then type space should display punctuation strip", - mLatinIME.isShowingPunctuationList()); + mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions()); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); assertEquals("type word then type space then punctuation from strip twice for French", @@ -84,8 +84,9 @@ public class InputLogicTestsNonEnglish extends InputTestsBase { type(WORD_TO_TYPE); sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); + final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest(); assertEquals("type word then type space yields predictions for French", - EXPECTED_RESULT, mLatinIME.getFirstSuggestedWord()); + EXPECTED_RESULT, suggestedWords.size() > 0 ? suggestedWords.getWord(0) : null); } finally { setBooleanPreference(NEXT_WORD_PREDICTION_OPTION, previousNextWordPredictionOption, defaultNextWordPredictionOption); diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java index 5095f9606..1a47cddf4 100644 --- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java +++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java @@ -55,14 +55,22 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = src.getXCoordinates().length * 2 + 10; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); assertEquals("size after add " + i, i + 1, src.getPointerSize()); } for (int i = 0; i < limit; i++) { - assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, i * 4, src.getTimes()[i]); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } @@ -70,14 +78,22 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = 1000, step = 100; for (int i = 0; i < limit; i += step) { - src.addPointer(i, i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointerAt(i, x, y, pointerId, time); assertEquals("size after add at " + i, i + 1, src.getPointerSize()); } for (int i = 0; i < limit; i += step) { - assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, i * 4, src.getTimes()[i]); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } @@ -85,7 +101,11 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = src.getXCoordinates().length * 2 + 10; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); dst.set(src); @@ -100,7 +120,11 @@ public class InputPointersTests extends AndroidTestCase { final InputPointers src = new InputPointers(DEFAULT_CAPACITY); final int limit = 100; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); dst.copy(src); @@ -121,106 +145,135 @@ public class InputPointersTests extends AndroidTestCase { } public void testAppend() { - final InputPointers src = new InputPointers(DEFAULT_CAPACITY); - final int srcLen = 100; - for (int i = 0; i < srcLen; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); - } - final int dstLen = 50; + final int dstLength = 50; final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); - for (int i = 0; i < dstLen; i++) { - final int value = -i - 1; - dst.addPointer(value * 4, value * 3, value * 2, value); + for (int i = 0; i < dstLength; i++) { + final int x = i * 4; + final int y = i * 3; + final int pointerId = i * 2; + final int time = i; + dst.addPointer(x, y, pointerId, time); } final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); dstCopy.copy(dst); - dst.append(src, 0, 0); - assertEquals("size after append zero", dstLen, dst.getPointerSize()); + final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcYCoords = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcPointerIds = new ResizableIntArray(DEFAULT_CAPACITY); + final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY); + final int srcLength = 100; + final int srcPointerId = 10; + for (int i = 0; i < srcLength; i++) { + final int x = i; + final int y = i * 2; + // The time value must be larger than <code>dst</code>. + final int time = i * 4 + dstLength; + srcXCoords.add(x); + srcYCoords.add(y); + srcPointerIds.add(srcPointerId); + srcTimes.add(time); + } + + final int startPos = 0; + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, + startPos, 0 /* length */); + assertEquals("size after append zero", dstLength, dst.getPointerSize()); assertIntArrayEquals("xCoordinates after append zero", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength); assertIntArrayEquals("yCoordinates after append zero", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength); assertIntArrayEquals("pointerIds after append zero", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength); assertIntArrayEquals("times after append zero", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength); - dst.append(src, 0, srcLen); - assertEquals("size after append", dstLen + srcLen, dst.getPointerSize()); + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, + startPos, srcLength); + assertEquals("size after append", dstLength + srcLength, dst.getPointerSize()); assertTrue("primitive length after append", - dst.getPointerIds().length >= dstLen + srcLen); + dst.getPointerIds().length >= dstLength + srcLength); assertIntArrayEquals("original xCoordinates values after append", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength); assertIntArrayEquals("original yCoordinates values after append", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength); assertIntArrayEquals("original pointerIds values after append", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength); assertIntArrayEquals("original times values after append", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength); assertIntArrayEquals("appended xCoordinates values after append", - src.getXCoordinates(), 0, dst.getXCoordinates(), dstLen, srcLen); + srcXCoords.getPrimitiveArray(), startPos, dst.getXCoordinates(), + dstLength, srcLength); assertIntArrayEquals("appended yCoordinates values after append", - src.getYCoordinates(), 0, dst.getYCoordinates(), dstLen, srcLen); + srcYCoords.getPrimitiveArray(), startPos, dst.getYCoordinates(), + dstLength, srcLength); assertIntArrayEquals("appended pointerIds values after append", - src.getPointerIds(), 0, dst.getPointerIds(), dstLen, srcLen); + srcPointerIds.getPrimitiveArray(), startPos, dst.getPointerIds(), + dstLength, srcLength); assertIntArrayEquals("appended times values after append", - src.getTimes(), 0, dst.getTimes(), dstLen, srcLen); + srcTimes.getPrimitiveArray(), startPos, dst.getTimes(), dstLength, srcLength); } public void testAppendResizableIntArray() { - final int srcLen = 100; + final int dstLength = 50; + final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); + for (int i = 0; i < dstLength; i++) { + final int x = i * 4; + final int y = i * 3; + final int pointerId = i * 2; + final int time = i; + dst.addPointer(x, y, pointerId, time); + } + final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); + dstCopy.copy(dst); + + final int srcLength = 100; final int srcPointerId = 1; - final int[] srcPointerIds = new int[srcLen]; + final int[] srcPointerIds = new int[srcLength]; Arrays.fill(srcPointerIds, srcPointerId); final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY); final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY); final ResizableIntArray srcYCoords= new ResizableIntArray(DEFAULT_CAPACITY); - for (int i = 0; i < srcLen; i++) { - srcTimes.add(i * 2); - srcXCoords.add(i * 3); - srcYCoords.add(i * 4); + for (int i = 0; i < srcLength; i++) { + // The time value must be larger than <code>dst</code>. + final int time = i * 2 + dstLength; + final int x = i * 3; + final int y = i * 4; + srcTimes.add(time); + srcXCoords.add(x); + srcYCoords.add(y); } - final int dstLen = 50; - final InputPointers dst = new InputPointers(DEFAULT_CAPACITY); - for (int i = 0; i < dstLen; i++) { - final int value = -i - 1; - dst.addPointer(value * 4, value * 3, value * 2, value); - } - final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY); - dstCopy.copy(dst); dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, 0); - assertEquals("size after append zero", dstLen, dst.getPointerSize()); + assertEquals("size after append zero", dstLength, dst.getPointerSize()); assertIntArrayEquals("xCoordinates after append zero", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength); assertIntArrayEquals("yCoordinates after append zero", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength); assertIntArrayEquals("pointerIds after append zero", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength); assertIntArrayEquals("times after append zero", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength); - dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLen); - assertEquals("size after append", dstLen + srcLen, dst.getPointerSize()); + dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLength); + assertEquals("size after append", dstLength + srcLength, dst.getPointerSize()); assertTrue("primitive length after append", - dst.getPointerIds().length >= dstLen + srcLen); + dst.getPointerIds().length >= dstLength + srcLength); assertIntArrayEquals("original xCoordinates values after append", - dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen); + dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength); assertIntArrayEquals("original yCoordinates values after append", - dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen); + dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength); assertIntArrayEquals("original pointerIds values after append", - dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen); + dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength); assertIntArrayEquals("original times values after append", - dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen); + dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength); assertIntArrayEquals("appended xCoordinates values after append", - srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLen, srcLen); + srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLength, srcLength); assertIntArrayEquals("appended yCoordinates values after append", - srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLen, srcLen); + srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLength, srcLength); assertIntArrayEquals("appended pointerIds values after append", - srcPointerIds, 0, dst.getPointerIds(), dstLen, srcLen); + srcPointerIds, 0, dst.getPointerIds(), dstLength, srcLength); assertIntArrayEquals("appended times values after append", - srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLen, srcLen); + srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLength, srcLength); } // TODO: Consolidate this method with @@ -250,14 +303,24 @@ public class InputPointersTests extends AndroidTestCase { final int limit = 100; final int shiftAmount = 20; for (int i = 0; i < limit; i++) { - src.addPointer(i, i * 2, i * 3, i * 4); + final int x = i; + final int y = i * 2; + final int pointerId = i * 3; + final int time = i * 4; + src.addPointer(x, y, pointerId, time); } src.shift(shiftAmount); + assertEquals("length after shift", src.getPointerSize(), limit - shiftAmount); for (int i = 0; i < limit - shiftAmount; ++i) { - assertEquals("xCoordinates at " + i, i + shiftAmount, src.getXCoordinates()[i]); - assertEquals("yCoordinates at " + i, (i + shiftAmount) * 2, src.getYCoordinates()[i]); - assertEquals("pointerIds at " + i, (i + shiftAmount) * 3, src.getPointerIds()[i]); - assertEquals("times at " + i, (i + shiftAmount) * 4, src.getTimes()[i]); + final int oldIndex = i + shiftAmount; + final int x = oldIndex; + final int y = oldIndex * 2; + final int pointerId = oldIndex * 3; + final int time = oldIndex * 4; + assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]); + assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]); + assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]); + assertEquals("times at " + i, time, src.getTimes()[i]); } } } diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index b9b52a6f3..260e534ee 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -25,35 +25,48 @@ import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.style.CharacterStyle; import android.text.style.SuggestionSpan; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodSubtype; import android.widget.EditText; import android.widget.FrameLayout; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.settings.DebugSettings; +import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Locale; +import java.util.concurrent.TimeUnit; public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { + private static final String TAG = InputTestsBase.class.getSimpleName(); - private static final String PREF_DEBUG_MODE = "debug_mode"; + // Default value for auto-correction threshold. This is the string representation of the + // index in the resources array of auto-correction threshold settings. + private static final String DEFAULT_AUTO_CORRECTION_THRESHOLD = "1"; - // The message that sets the underline is posted with a 200 ms delay - protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 200; + // The message that sets the underline is posted with a 500 ms delay + protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 500; // The message that sets predictions is posted with a 200 ms delay protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200; + private final int TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS = 60; protected LatinIME mLatinIME; protected Keyboard mKeyboard; protected MyEditText mEditText; protected View mInputView; protected InputConnection mInputConnection; + private boolean mPreviousBigramPredictionSettings; + private String mPreviousAutoCorrectSetting; // A helper class to ease span tests public static class SpanGetter { @@ -135,13 +148,30 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { final boolean previousSetting = prefs.getBoolean(key, defaultValue); final SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(key, value); - editor.commit(); + editor.apply(); + return previousSetting; + } + + protected String setStringPreference(final String key, final String value, + final String defaultValue) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); + final String previousSetting = prefs.getString(key, defaultValue); + final SharedPreferences.Editor editor = prefs.edit(); + editor.putString(key, value); + editor.apply(); return previousSetting; } // returns the previous setting value protected boolean setDebugMode(final boolean value) { - return setBooleanPreference(PREF_DEBUG_MODE, value, false); + return setBooleanPreference(DebugSettings.PREF_DEBUG_MODE, value, false); + } + + protected EditorInfo enrichEditorInfo(final EditorInfo ei) { + // Some tests that inherit from us need to add some data in the EditorInfo (see + // AppWorkaroundsTests#enrichEditorInfo() for a concrete example of this). Since we + // control the EditorInfo, we supply a hook here for children to override. + return ei; } @Override @@ -154,15 +184,19 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { mEditText.setEnabled(true); setupService(); mLatinIME = getService(); - final boolean previousDebugSetting = setDebugMode(true); + setDebugMode(true); + mPreviousBigramPredictionSettings = setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, + true, true /* defaultValue */); + mPreviousAutoCorrectSetting = setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, + DEFAULT_AUTO_CORRECTION_THRESHOLD, DEFAULT_AUTO_CORRECTION_THRESHOLD); mLatinIME.onCreate(); - setDebugMode(previousDebugSetting); - final EditorInfo ei = new EditorInfo(); + EditorInfo ei = new EditorInfo(); final InputConnection ic = mEditText.onCreateInputConnection(ei); final LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); final ViewGroup vg = new FrameLayout(getContext()); mInputView = inflater.inflate(R.layout.input_view, vg); + ei = enrichEditorInfo(ei); mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); mLatinIME.setInputView(mInputView); mLatinIME.onBindInput(); @@ -170,6 +204,27 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { mLatinIME.onStartInputView(ei, false); mInputConnection = ic; changeLanguage("en_US"); + // Run messages to avoid the messages enqueued by startInputView() and its friends + // to run on a later call and ruin things. We need to wait first because some of them + // can be posted with a delay (notably, MSG_RESUME_SUGGESTIONS) + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + } + + @Override + protected void tearDown() throws Exception { + mLatinIME.onFinishInputView(true); + mLatinIME.onFinishInput(); + runMessages(); + mLatinIME.mHandler.removeAllMessages(); + setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, mPreviousBigramPredictionSettings, + true /* defaultValue */); + setStringPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD, mPreviousAutoCorrectSetting, + DEFAULT_AUTO_CORRECTION_THRESHOLD); + setDebugMode(false); + mLatinIME.recycle(); + super.tearDown(); + mLatinIME = null; } // We need to run the messages added to the handler from LatinIME. The only way to do @@ -199,7 +254,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { } // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. - protected void type(final int codePoint) { + protected void typeInternal(final int codePoint, final boolean isKeyRepeat) { // 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 @@ -208,56 +263,81 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { // but keep them in mind if something breaks. Commenting them out as is should work. //mLatinIME.onPressKey(codePoint, 0 /* repeatCount */, true /* isSinglePointer */); final Key key = mKeyboard.getKey(codePoint); - if (key != null) { + if (key == null) { + mLatinIME.onCodeInput(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, + isKeyRepeat); + } else { final int x = key.getX() + key.getWidth() / 2; final int y = key.getY() + key.getHeight() / 2; - mLatinIME.onCodeInput(codePoint, x, y); - return; + mLatinIME.onCodeInput(codePoint, x, y, isKeyRepeat); } - mLatinIME.onCodeInput(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + // Also see the comment at the top of this function about onReleaseKey //mLatinIME.onReleaseKey(codePoint, false /* withSliding */); } + protected void type(final int codePoint) { + typeInternal(codePoint, false /* isKeyRepeat */); + } + + protected void repeatKey(final int codePoint) { + typeInternal(codePoint, true /* isKeyRepeat */); + } + protected void type(final String stringToType) { for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) { type(stringToType.codePointAt(i)); } } - protected void waitForDictionaryToBeLoaded() { - int remainingAttempts = 300; - while (remainingAttempts > 0 && mLatinIME.isCurrentlyWaitingForMainDictionary()) { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - // Don't do much - } finally { - --remainingAttempts; - } + protected void waitForDictionariesToBeLoaded() { + try { + mLatinIME.waitForLoadingDictionaries( + TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted during waiting for loading main dictionary.", e); } } protected void changeLanguage(final String locale) { changeLanguageWithoutWait(locale); - waitForDictionaryToBeLoaded(); + waitForDictionariesToBeLoaded(); } protected void changeLanguageWithoutWait(final String locale) { mEditText.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale); - SubtypeSwitcher.getInstance().forceLocale(mEditText.mCurrentLocale); + // TODO: this is forcing a QWERTY keyboard for all locales, which is wrong. + // It's still better than using whatever keyboard is the current one, but we + // should actually use the default keyboard for this locale. + // TODO: Use {@link InputMethodSubtype.InputMethodSubtypeBuilder} directly or indirectly so + // that {@link InputMethodSubtype#isAsciiCapable} can return the correct value. + final String EXTRA_VALUE_FOR_TEST = + "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY + + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + final InputMethodSubtype subtype = InputMethodSubtypeCompatUtils.newInputMethodSubtype( + R.string.subtype_no_language_qwerty, + R.drawable.ic_ime_switcher_dark, + locale, + Constants.Subtype.KEYBOARD_MODE, + EXTRA_VALUE_FOR_TEST, + false /* isAuxiliary */, + false /* overridesImplicitlyEnabledSubtype */, + 0 /* id */); + SubtypeSwitcher.getInstance().forceSubtype(subtype); mLatinIME.loadKeyboard(); runMessages(); mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard(); + mLatinIME.clearPersonalizedDictionariesForTest(); } protected void changeKeyboardLocaleAndDictLocale(final String keyboardLocale, final String dictLocale) { changeLanguage(keyboardLocale); if (!keyboardLocale.equals(dictLocale)) { - mLatinIME.replaceMainDictionaryForTest( - LocaleUtils.constructLocaleFromString(dictLocale)); + mLatinIME.replaceDictionariesForTest(LocaleUtils.constructLocaleFromString(dictLocale)); } - waitForDictionaryToBeLoaded(); + waitForDictionariesToBeLoaded(); } protected void pickSuggestionManually(final int index, final String suggestion) { diff --git a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java index 5e98cdf8d..db14b8329 100644 --- a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java +++ b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java @@ -41,7 +41,7 @@ public class LatinImeStressTests extends InputTestsBase { } } } - public void testSwitchLanguagesAndInputRandamCodePoints() { + public void testSwitchLanguagesAndInputRandomCodePoints() { final String[] locales = {"en_US", "de", "el", "es", "fi", "it", "nl", "pt", "ru"}; final int switchCount = 50; final int maxWordCountToTypeInEachIteration = 20; diff --git a/tests/src/com/android/inputmethod/latin/PunctuationTests.java b/tests/src/com/android/inputmethod/latin/PunctuationTests.java index 84ff6b307..c253e6488 100644 --- a/tests/src/com/android/inputmethod/latin/PunctuationTests.java +++ b/tests/src/com/android/inputmethod/latin/PunctuationTests.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import android.provider.Settings.Secure; import android.test.suitebuilder.annotation.LargeTest; import com.android.inputmethod.latin.R; @@ -40,7 +41,7 @@ public class PunctuationTests extends InputTestsBase { sleep(DELAY_TO_WAIT_FOR_UNDERLINE); runMessages(); assertTrue("type word then type space should display punctuation strip", - mLatinIME.isShowingPunctuationList()); + mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions()); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); assertEquals("type word then type space then punctuation from strip twice", @@ -153,7 +154,9 @@ public class PunctuationTests extends InputTestsBase { final String WORD_TO_TYPE = "you'f "; final String EXPECTED_RESULT = "you'd "; type(WORD_TO_TYPE); - assertEquals("auto-correction with single quote inside", + assertEquals("auto-correction with single quote inside. ID = " + + Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID) + + " ; Suggestions = " + mLatinIME.getSuggestedWordsForTest(), EXPECTED_RESULT, mEditText.getText().toString()); } @@ -161,7 +164,37 @@ public class PunctuationTests extends InputTestsBase { final String WORD_TO_TYPE = "'tgis' "; final String EXPECTED_RESULT = "'this' "; type(WORD_TO_TYPE); - assertEquals("auto-correction with single quotes around", + assertEquals("auto-correction with single quotes around. ID = " + + Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID) + + " ; Suggestions = " + mLatinIME.getSuggestedWordsForTest(), + EXPECTED_RESULT, mEditText.getText().toString()); + } + + public void testAutoSpaceWithDoubleQuotes() { + final String STRING_TO_TYPE = "He said\"hello\"to me. I replied,\"hi\"." + + "Then, 5\"passed. He said\"bye\"and left."; + final String EXPECTED_RESULT = "He said \"hello\" to me. I replied, \"hi\". " + + "Then, 5\" passed. He said \"bye\" and left. \""; + // Split by double quote, so that we can type the double quotes individually. + for (final String partToType : STRING_TO_TYPE.split("\"")) { + // Split at word boundaries. This regexp means "anywhere that is preceded + // by a word character but not followed by a word character, OR that is not + // preceded by a word character but followed by a word character". + // We need to input word by word because auto-spaces are only active when + // manually picking or gesturing (which we can't simulate yet), but only words + // can be picked. + final String[] wordsToType = partToType.split("(?<=\\w)(?!\\w)|(?<!\\w)(?=\\w)"); + for (final String wordToType : wordsToType) { + type(wordToType); + if (wordToType.matches("^\\w+$")) { + // Only pick selection if that was a word, because if that was not a word, + // then we don't have a composition. + pickSuggestionManually(0, wordToType); + } + } + type("\""); + } + assertEquals("auto-space with double quotes", EXPECTED_RESULT, mEditText.getText().toString()); } } diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java index c0dd9933c..842f3f3a9 100644 --- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java +++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java @@ -16,15 +16,13 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.utils.TextRange; - +import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.Parcel; import android.test.AndroidTestCase; import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; -import android.text.Spanned; import android.text.TextUtils; import android.text.style.SuggestionSpan; import android.view.inputmethod.ExtractedText; @@ -32,6 +30,11 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; +import com.android.inputmethod.latin.utils.RunInLocale; +import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.TextRange; + import java.util.Locale; @SmallTest @@ -39,11 +42,19 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { // The following is meant to be a reasonable default for // the "word_separators" resource. - private static final String sSeparators = ".,:;!?-"; + private SpacingAndPunctuations mSpacingAndPunctuations; @Override protected void setUp() throws Exception { super.setUp(); + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + mSpacingAndPunctuations = job.runInLocale(res, Locale.ENGLISH); } private class MockConnection extends InputConnectionWrapper { @@ -78,6 +89,10 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { mExtractedText = extractedText; } + public int cursorPos() { + return mTextBefore.length(); + } + /* (non-Javadoc) * @see android.view.inputmethod.InputConnectionWrapper#getTextBeforeCursor(int, int) */ @@ -120,13 +135,16 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { } private class MockInputMethodService extends InputMethodService { - InputConnection mInputConnection; - public void setInputConnection(final InputConnection inputConnection) { - mInputConnection = inputConnection; + private MockConnection mMockConnection; + public void setInputConnection(final MockConnection mockConnection) { + mMockConnection = mockConnection; + } + public int cursorPos() { + return mMockConnection.cursorPos(); } @Override public InputConnection getCurrentInputConnection() { - return mInputConnection; + return mMockConnection; } } @@ -137,9 +155,12 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { */ public void testGetPreviousWord() { // If one of the following cases breaks, the bigram suggestions won't work. - assertEquals(RichInputConnection.getNthPreviousWord("abc def", sSeparators, 2), "abc"); - assertNull(RichInputConnection.getNthPreviousWord("abc", sSeparators, 2)); - assertNull(RichInputConnection.getNthPreviousWord("abc. def", sSeparators, 2)); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def", mSpacingAndPunctuations, 2), "abc"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc", mSpacingAndPunctuations, 2)); + assertNull(RichInputConnection.getNthPreviousWord( + "abc. def", mSpacingAndPunctuations, 2)); // The following tests reflect the current behavior of the function // RichInputConnection#getNthPreviousWord. @@ -148,20 +169,34 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { // this function if needed - especially since it does not seem very // logical. These tests are just there to catch any unintentional // changes in the behavior of the RichInputConnection#getPreviousWord method. - assertEquals(RichInputConnection.getNthPreviousWord("abc def ", sSeparators, 2), "abc"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def.", sSeparators, 2), "abc"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def .", sSeparators, 2), "def"); - assertNull(RichInputConnection.getNthPreviousWord("abc ", sSeparators, 2)); - - assertEquals(RichInputConnection.getNthPreviousWord("abc def", sSeparators, 1), "def"); - assertEquals(RichInputConnection.getNthPreviousWord("abc def ", sSeparators, 1), "def"); - assertNull(RichInputConnection.getNthPreviousWord("abc def.", sSeparators, 1)); - assertNull(RichInputConnection.getNthPreviousWord("abc def .", sSeparators, 1)); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def ", mSpacingAndPunctuations, 2), "abc"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def.", mSpacingAndPunctuations, 2), "abc"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def .", mSpacingAndPunctuations, 2), "def"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc ", mSpacingAndPunctuations, 2)); + + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def", mSpacingAndPunctuations, 1), "def"); + assertEquals(RichInputConnection.getNthPreviousWord( + "abc def ", mSpacingAndPunctuations, 1), "def"); + assertNull(RichInputConnection.getNthPreviousWord( + "abc def.", mSpacingAndPunctuations, 1)); + assertNull(RichInputConnection.getNthPreviousWord( + "abc def .", mSpacingAndPunctuations, 1)); } /** * Test logic in getting the word range at the cursor. */ + private static final int[] SPACE = { Constants.CODE_SPACE }; + static final int[] TAB = { Constants.CODE_TAB }; + private static final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t"); + // A character that needs surrogate pair to represent its code point (U+2008A). + private static final String SUPPLEMENTARY_CHAR = "\uD840\uDC8A"; + public void testGetWordRangeAtCursor() { ExtractedText et = new ExtractedText(); final MockInputMethodService mockInputMethodService = new MockInputMethodService(); @@ -173,48 +208,47 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { ic.beginBatchEdit(); // basic case - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); assertTrue(TextUtils.equals("word", r.mWord)); // more than one word - r = ic.getWordRangeAtCursor(" ", 1); + r = ic.getWordRangeAtCursor(SPACE, 1); assertTrue(TextUtils.equals("word word", r.mWord)); ic.endBatchEdit(); // tab character instead of space mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor("\t", 1); + r = ic.getWordRangeAtCursor(TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // only one word doesn't go too far mockInputMethodService.setInputConnection(new MockConnection("one\tword\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor("\t", 1); + r = ic.getWordRangeAtCursor(TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // tab or space mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(" \t", 1); + r = ic.getWordRangeAtCursor(SPACE_TAB, 1); ic.endBatchEdit(); assertTrue(TextUtils.equals("word\tword", r.mWord)); // tab or space multiword mockInputMethodService.setInputConnection(new MockConnection("one word\two", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(" \t", 2); + r = ic.getWordRangeAtCursor(SPACE_TAB, 2); ic.endBatchEdit(); assertTrue(TextUtils.equals("one word\tword", r.mWord)); // splitting on supplementary character - final String supplementaryChar = "\uD840\uDC8A"; mockInputMethodService.setInputConnection( - new MockConnection("one word" + supplementaryChar + "wo", "rd", et)); + new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et)); ic.beginBatchEdit(); - r = ic.getWordRangeAtCursor(supplementaryChar, 0); + r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR), 0); ic.endBatchEdit(); assertTrue(TextUtils.equals("word", r.mWord)); } @@ -244,7 +278,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { TextRange r; SuggestionSpan[] suggestions; - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -256,7 +290,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 10 /* start */, 16 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 2); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -269,7 +303,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 16 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -281,7 +315,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 10 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -293,7 +327,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 1); MoreAsserts.assertEquals(suggestions[0].getSuggestions(), SUGGESTIONS1); @@ -305,8 +339,86 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase { text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS2, 0 /* flags */), 5 /* start */, 20 /* end */, 0 /* flags */); mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos)); - r = ic.getWordRangeAtCursor(" ", 0); + r = ic.getWordRangeAtCursor(SPACE, 0); suggestions = r.getSuggestionSpansAtWord(); assertEquals(suggestions.length, 0); } + + public void testCursorTouchingWord() { + final MockInputMethodService ims = new MockInputMethodService(); + final RichInputConnection ic = new RichInputConnection(ims); + final SpacingAndPunctuations sap = mSpacingAndPunctuations; + + ims.setInputConnection(new MockConnection("users", 5)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("users'", 5)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("users'", 6)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("'users'", 6)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("'users'", 7)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("users '", 6)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("users '", 7)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("re-", 3)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("re--", 4)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("-", 1)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection("--", 2)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" -", 2)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" --", 3)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" users '", 1)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" users '", 3)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" users '", 7)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" users are", 7)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertTrue(ic.isCursorTouchingWord(sap)); + + ims.setInputConnection(new MockConnection(" users 'are", 7)); + ic.resetCachesUponCursorMoveAndReturnSuccess(ims.cursorPos(), ims.cursorPos(), true); + assertFalse(ic.isCursorTouchingWord(sap)); + } } diff --git a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java new file mode 100644 index 000000000..6fc9df793 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014 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.test.suitebuilder.annotation.LargeTest; +import android.text.TextUtils; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.WordComposer; + +@LargeTest +public class ShiftModeTests extends InputTestsBase { + + @Override + protected EditorInfo enrichEditorInfo(final EditorInfo ei) { + ei.inputType |= TextUtils.CAP_MODE_SENTENCES; + ei.initialCapsMode = TextUtils.CAP_MODE_SENTENCES; + return ei; + } + + private boolean isCapsModeAutoShifted() { + return mLatinIME.mKeyboardSwitcher.getKeyboardShiftMode() + == WordComposer.CAPS_MODE_AUTO_SHIFTED; + } + + public void testTypicalSentence() { + assertTrue("Initial auto caps state", isCapsModeAutoShifted()); + type("Test"); + assertFalse("Caps after letter", isCapsModeAutoShifted()); + type(" "); + assertFalse("Caps after space", isCapsModeAutoShifted()); + type("some,"); + assertFalse("Caps after comma", isCapsModeAutoShifted()); + type(" "); + assertFalse("Caps after comma space", isCapsModeAutoShifted()); + type("words."); + assertFalse("Caps directly after period", isCapsModeAutoShifted()); + type(" "); + assertTrue("Caps after period space", isCapsModeAutoShifted()); + } + + public void testBackspace() { + assertTrue("Initial auto caps state", isCapsModeAutoShifted()); + type("A"); + assertFalse("Caps state after one letter", isCapsModeAutoShifted()); + type(Constants.CODE_DELETE); + assertTrue("Auto caps state at start after delete", isCapsModeAutoShifted()); + } + + public void testRepeatingBackspace() { + final String SENTENCE_TO_TYPE = "Test sentence. Another."; + final int BACKSPACE_COUNT = + SENTENCE_TO_TYPE.length() - SENTENCE_TO_TYPE.lastIndexOf(' ') - 1; + + type(SENTENCE_TO_TYPE); + assertFalse("Caps after typing \"" + SENTENCE_TO_TYPE + "\"", isCapsModeAutoShifted()); + type(Constants.CODE_DELETE); + for (int i = 1; i < BACKSPACE_COUNT; ++i) { + repeatKey(Constants.CODE_DELETE); + } + assertFalse("Caps immediately after repeating Backspace a lot", isCapsModeAutoShifted()); + sleep(DELAY_TO_WAIT_FOR_PREDICTIONS); + runMessages(); + assertTrue("Caps after a while after repeating Backspace a lot", isCapsModeAutoShifted()); + } +} diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java index 375352067..8fe473523 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java +++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java @@ -46,10 +46,9 @@ public class SuggestedWordsTests extends AndroidTestCase { } final SuggestedWords words = new SuggestedWords( - list, + list, null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */, - false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction*/); assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size()); diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java index 1434c6b63..d68bb5c54 100644 --- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java +++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java @@ -19,6 +19,9 @@ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.utils.CoordinateUtils; +import com.android.inputmethod.latin.utils.StringUtils; + /** * Unit tests for WordComposer. */ @@ -26,10 +29,20 @@ import android.test.suitebuilder.annotation.SmallTest; public class WordComposerTests extends AndroidTestCase { public void testMoveCursor() { final WordComposer wc = new WordComposer(); + // BMP is the Basic Multilingual Plane, as defined by Unicode. This includes + // most characters for most scripts, including all Roman alphabet languages, + // CJK, Arabic, Hebrew. Notable exceptions include some emoji and some + // very rare Chinese ideograms. BMP characters can be encoded on 2 bytes + // in UTF-16, whereas those outside the BMP need 4 bytes. + // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane final String STR_WITHIN_BMP = "abcdef"; - wc.setComposingWord(STR_WITHIN_BMP, null); - assertEquals(wc.size(), - STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); + final int[] CODEPOINTS_WITHIN_BMP = StringUtils.toCodePointArray(STR_WITHIN_BMP); + final int[] COORDINATES_WITHIN_BMP = + CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + final String PREVWORD = "prevword"; + wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREVWORD); + assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length())); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(2); assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -43,15 +56,26 @@ public class WordComposerTests extends AndroidTestCase { // Move the cursor to after the 'f' assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); + // Check the previous word is still there + assertEquals(PREVWORD, wc.getPreviousWordForSuggestion()); // Move the cursor past the end of the word assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15)); + // Do what LatinIME does when the cursor is moved outside of the word, + // and check the behavior is correct. + wc.reset(); + assertNull(wc.getPreviousWordForSuggestion()); // \uD861\uDED7 is 𨛗, a character outside the BMP final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh"; - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); - assertEquals(wc.size(), STR_WITH_SUPPLEMENTARY_CHAR.codePointCount(0, - STR_WITH_SUPPLEMENTARY_CHAR.length())); + final int[] CODEPOINTS_WITH_SUPPLEMENTARY_CHAR = + StringUtils.toCodePointArray(STR_WITH_SUPPLEMENTARY_CHAR); + final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR = + CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); + assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); wc.setCursorPositionWithinWord(3); assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); @@ -59,34 +83,48 @@ public class WordComposerTests extends AndroidTestCase { assertTrue(wc.isCursorFrontOrMiddleOfComposingWord()); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1)); assertFalse(wc.isCursorFrontOrMiddleOfComposingWord()); + assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); + assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7)); + assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITHIN_BMP); wc.setCursorPositionWithinWord(3); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3)); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1)); + assertEquals(STR_WITHIN_BMP, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); wc.setCursorPositionWithinWord(3); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9)); + assertNull(wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + STR_WITH_SUPPLEMENTARY_CHAR); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10)); + assertEquals(STR_WITH_SUPPLEMENTARY_CHAR, wc.getPreviousWordForSuggestion()); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); - wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null); + wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR, + null /* previousWord */); wc.setCursorPositionWithinWord(2); assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0)); } diff --git a/tests/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java new file mode 100644 index 000000000..bc856f113 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.TreeMap; + +/** + * A base class of the binary dictionary decoder. + */ +public abstract class AbstractDictDecoder implements DictDecoder { + private static final int SUCCESS = 0; + private static final int ERROR_CANNOT_READ = 1; + private static final int ERROR_WRONG_FORMAT = 2; + + @Override @UsedForTesting + public int getTerminalPosition(final String word) + throws IOException, UnsupportedFormatException { + if (!isDictBufferOpen()) { + openDictBuffer(); + } + return BinaryDictIOUtils.getTerminalPosition(this, word); + } + + @Override @UsedForTesting + public void readUnigramsAndBigramsBinary(final TreeMap<Integer, String> words, + final TreeMap<Integer, Integer> frequencies, + final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams) + throws IOException, UnsupportedFormatException { + if (!isDictBufferOpen()) { + openDictBuffer(); + } + BinaryDictIOUtils.readUnigramsAndBigramsBinary(this, words, frequencies, bigrams); + } + + /** + * Check whether the header contains the expected information. This is a no-error method, + * that will return an error code and never throw a checked exception. + * @return an error code, either ERROR_* or SUCCESS. + */ + private int checkHeader() { + try { + readHeader(); + } catch (IOException e) { + return ERROR_CANNOT_READ; + } catch (UnsupportedFormatException e) { + return ERROR_WRONG_FORMAT; + } + return SUCCESS; + } + + @Override + public boolean hasValidRawBinaryDictionary() { + return checkHeader() == SUCCESS; + } + + // Placeholder implementations below. These are actually unused. + @Override + public void openDictBuffer() throws FileNotFoundException, IOException, + UnsupportedFormatException { + } + + @Override + public boolean isDictBufferOpen() { + return false; + } + + @Override + public PtNodeInfo readPtNode(final int ptNodePos) { + return null; + } + + @Override + public void setPosition(int newPos) { + } + + @Override + public int getPosition() { + return 0; + } + + @Override + public int readPtNodeCount() { + return 0; + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index 32c07e106..f29fc21c1 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -17,30 +17,30 @@ package com.android.inputmethod.latin.makedict; import android.test.AndroidTestCase; -import android.test.MoreAsserts; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; +import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; import com.android.inputmethod.latin.utils.CollectionUtils; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Random; import java.util.Set; @@ -52,18 +52,18 @@ import java.util.TreeMap; @LargeTest public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private static final String TAG = BinaryDictDecoderEncoderTests.class.getSimpleName(); - private static final int DEFAULT_MAX_UNIGRAMS = 100; + private static final int DEFAULT_MAX_UNIGRAMS = 300; private static final int DEFAULT_CODE_POINT_SET_SIZE = 50; + private static final int LARGE_CODE_POINT_SET_SIZE = 300; private static final int UNIGRAM_FREQ = 10; private static final int BIGRAM_FREQ = 50; private static final int TOLERANCE_OF_BIGRAM_FREQ = 5; private static final int NUM_OF_NODES_HAVING_SHORTCUTS = 50; private static final int NUM_OF_SHORTCUTS = 5; - private static final int USE_BYTE_ARRAY = 1; - private static final int USE_BYTE_BUFFER = 2; - private static final ArrayList<String> sWords = CollectionUtils.newArrayList(); + private static final ArrayList<String> sWordsWithVariousCodePoints = + CollectionUtils.newArrayList(); private static final SparseArray<List<Integer>> sEmptyBigrams = CollectionUtils.newSparseArray(); private static final SparseArray<List<Integer>> sStarBigrams = CollectionUtils.newSparseArray(); @@ -71,33 +71,18 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { CollectionUtils.newSparseArray(); private static final HashMap<String, List<String>> sShortcuts = CollectionUtils.newHashMap(); - private static final FormatSpec.FormatOptions VERSION2 = new FormatSpec.FormatOptions(2); - private static final FormatSpec.FormatOptions VERSION3_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(3, false /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION3_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(3, true /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(4, false /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */); - private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP = - new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */, - true /* hasTimestamp */); - - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - public BinaryDictDecoderEncoderTests() { this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS); } public BinaryDictDecoderEncoderTests(final long seed, final int maxUnigrams) { super(); + BinaryDictionaryUtils.setCurrentTimeForTest(0); Log.e(TAG, "Testing dictionary: seed is " + seed); final Random random = new Random(seed); sWords.clear(); - final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, - random); - generateWords(maxUnigrams, random, codePointSet); + sWordsWithVariousCodePoints.clear(); + generateWords(maxUnigrams, random); for (int i = 0; i < sWords.size(); ++i) { sChainBigrams.put(i, new ArrayList<Integer>()); @@ -124,23 +109,35 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { } } - private DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) { - if (formatOptions.mVersion == FormatSpec.VERSION4) { - return new Ver4DictEncoder(getContext().getCacheDir()); - } else if (formatOptions.mVersion == 3 || formatOptions.mVersion == 2) { - return new Ver3DictEncoder(file); - } else { - throw new RuntimeException("The format option has a wrong version : " - + formatOptions.mVersion); - } + @Override + protected void setUp() throws Exception { + super.setUp(); + BinaryDictionaryUtils.setCurrentTimeForTest(0); + } + + @Override + protected void tearDown() throws Exception { + // Quit test mode. + BinaryDictionaryUtils.setCurrentTimeForTest(-1); + super.tearDown(); } - private void generateWords(final int number, final Random random, final int[] codePointSet) { + private void generateWords(final int number, final Random random) { + final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, + random); final Set<String> wordSet = CollectionUtils.newHashSet(); while (wordSet.size() < number) { wordSet.add(CodePointUtils.generateWord(random, codePointSet)); } sWords.addAll(wordSet); + + final int[] largeCodePointSet = CodePointUtils.generateCodePointSet( + LARGE_CODE_POINT_SET_SIZE, random); + wordSet.clear(); + while (wordSet.size() < number) { + wordSet.add(CodePointUtils.generateWord(random, largeCodePointSet)); + } + sWordsWithVariousCodePoints.addAll(wordSet); } /** @@ -156,8 +153,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { shortcuts.add(new WeightedString(shortcut, UNIGRAM_FREQ)); } } - dict.add(word, UNIGRAM_FREQ, (shortcutMap == null) ? null : shortcuts, - false /* isNotAWord */); + dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ), + (shortcutMap == null) ? null : shortcuts, false /* isNotAWord */); } } @@ -167,7 +164,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { for (int i = 0; i < bigrams.size(); ++i) { final int w1 = bigrams.keyAt(i); for (int w2 : bigrams.valueAt(i)) { - dict.setBigram(words.get(w1), words.get(w2), BIGRAM_FREQ); + dict.setBigram(words.get(w1), words.get(w2), new ProbabilityInfo(BIGRAM_FREQ)); } } } @@ -186,7 +183,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final DictEncoder dictEncoder = getDictEncoder(file, formatOptions); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); now = System.currentTimeMillis(); // If you need to dump the dict to a textual file, uncomment the line below and the @@ -241,56 +238,23 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private String outputOptions(final int bufferType, final FormatSpec.FormatOptions formatOptions) { String result = " : buffer type = " - + ((bufferType == USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); - result += " : version = " + formatOptions.mVersion; - return result + ", supportsDynamicUpdate = " + formatOptions.mSupportsDynamicUpdate; - } - - private DictionaryOptions getDictionaryOptions(final String id, final String version) { - final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>(), - false, false); - options.mAttributes.put("version", version); - options.mAttributes.put("dictionary", id); - return options; + + ((bufferType == BinaryDictUtils.USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); + return result + " : version = " + formatOptions.mVersion; } - private File setUpDictionaryFile(final String name, final String version) { - File file = null; - try { - file = new File(getContext().getCacheDir(), name + "." + version - + TEST_DICT_FILE_EXTENSION); - file.createNewFile(); - } catch (IOException e) { - // do nothing - } - assertTrue("Failed to create the dictionary file.", file.exists()); - return file; - } - - private DictDecoder getDictDecoder(final File file, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { - if (formatOptions.mVersion == FormatSpec.VERSION4) { - final FileHeader header = new FileHeader(0, dictOptions, formatOptions); - return FormatSpec.getDictDecoder(new File(getContext().getCacheDir(), - header.getId() + "." + header.getVersion()), bufferType); - } else { - return FormatSpec.getDictDecoder(file, bufferType); - } - } // Tests for readDictionaryBinary and writeDictionaryBinary private long timeReadingAndCheckDict(final File file, final List<String> words, final SparseArray<List<Integer>> bigrams, - final HashMap<String, List<String>> shortcutMap, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { + final HashMap<String, List<String>> shortcutMap, final int bufferType) { long now, diff = -1; FusionDictionary dict = null; try { - final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions, - dictOptions); + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(), + bufferType); now = System.currentTimeMillis(); - dict = dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */); + dict = dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); diff = System.currentTimeMillis() - now; } catch (IOException e) { Log.e(TAG, "IOException while reading dictionary", e); @@ -310,17 +274,17 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final String dictName = "runReadAndWrite"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(words.size(), dict, words, shortcuts); addBigrams(dict, words, bigrams); checkDictionary(dict, words, bigrams, shortcuts); final long write = timeWritingDictToFile(file, dict, formatOptions); - final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType, - formatOptions, dict.mOptions); + final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType); return "PROF: read=" + read + "ms, write=" + write + "ms :" + message + " : " + outputOptions(bufferType, formatOptions); @@ -340,6 +304,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { "chain with shortcuts")); results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions, "star with shortcuts")); + results.add(runReadAndWrite(sWordsWithVariousCodePoints, sEmptyBigrams, + null /* shortcuts */, bufferType, formatOptions, + "unigram with various code points")); } // Unit test for CharEncoding.readString and CharEncoding.writeString. @@ -349,8 +316,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final byte[] buffer = new byte[50 * 3]; final DictBuffer dictBuffer = new ByteArrayDictBuffer(buffer); for (final String word : sWords) { - Log.d("testReadAndWriteString", "write : " + word); - Arrays.fill(buffer, (byte)0); + Arrays.fill(buffer, (byte) 0); CharEncoding.writeString(buffer, 0, word); dictBuffer.position(0); final String str = CharEncoding.readString(dictBuffer); @@ -361,13 +327,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadAndWriteWithByteBuffer() { final List<String> results = CollectionUtils.newArrayList(); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION2); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); - + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); } @@ -376,12 +341,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadAndWriteWithByteArray() { final List<String> results = CollectionUtils.newArrayList(); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION2); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -394,53 +359,54 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final SparseArray<List<Integer>> expectedBigrams, final TreeMap<Integer, String> resultWords, final TreeMap<Integer, Integer> resultFrequencies, - final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams) { + final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams, + final boolean checkProbability) { // check unigrams final Set<String> actualWordsSet = new HashSet<String>(resultWords.values()); final Set<String> expectedWordsSet = new HashSet<String>(expectedWords); assertEquals(actualWordsSet, expectedWordsSet); - - for (int freq : resultFrequencies.values()) { - assertEquals(freq, UNIGRAM_FREQ); + if (checkProbability) { + for (int freq : resultFrequencies.values()) { + assertEquals(freq, UNIGRAM_FREQ); + } } // check bigrams - final HashMap<String, List<String>> expBigrams = new HashMap<String, List<String>>(); + final HashMap<String, Set<String>> expBigrams = new HashMap<String, Set<String>>(); for (int i = 0; i < expectedBigrams.size(); ++i) { final String word1 = expectedWords.get(expectedBigrams.keyAt(i)); for (int w2 : expectedBigrams.valueAt(i)) { if (expBigrams.get(word1) == null) { - expBigrams.put(word1, new ArrayList<String>()); + expBigrams.put(word1, new HashSet<String>()); } expBigrams.get(word1).add(expectedWords.get(w2)); } } - final HashMap<String, List<String>> actBigrams = new HashMap<String, List<String>>(); + final HashMap<String, Set<String>> actBigrams = new HashMap<String, Set<String>>(); for (Entry<Integer, ArrayList<PendingAttribute>> entry : resultBigrams.entrySet()) { final String word1 = resultWords.get(entry.getKey()); final int unigramFreq = resultFrequencies.get(entry.getKey()); for (PendingAttribute attr : entry.getValue()) { final String word2 = resultWords.get(attr.mAddress); if (actBigrams.get(word1) == null) { - actBigrams.put(word1, new ArrayList<String>()); + actBigrams.put(word1, new HashSet<String>()); } actBigrams.get(word1).add(word2); - final int bigramFreq = BinaryDictIOUtils.reconstructBigramFrequency( - unigramFreq, attr.mFrequency); - assertTrue(Math.abs(bigramFreq - BIGRAM_FREQ) < TOLERANCE_OF_BIGRAM_FREQ); + if (checkProbability) { + final int bigramFreq = BinaryDictIOUtils.reconstructBigramFrequency( + unigramFreq, attr.mFrequency); + assertTrue(Math.abs(bigramFreq - BIGRAM_FREQ) < TOLERANCE_OF_BIGRAM_FREQ); + } } } - assertEquals(actBigrams, expBigrams); } private long timeAndCheckReadUnigramsAndBigramsBinary(final File file, final List<String> words, final SparseArray<List<Integer>> bigrams, final int bufferType, - final FormatOptions formatOptions, final DictionaryOptions dictOptions) { - FileInputStream inStream = null; - + final boolean checkProbability) { final TreeMap<Integer, String> resultWords = CollectionUtils.newTreeMap(); final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams = CollectionUtils.newTreeMap(); @@ -448,8 +414,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions, - dictOptions); + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(), + bufferType); now = System.currentTimeMillis(); dictDecoder.readUnigramsAndBigramsBinary(resultWords, resultFreqs, resultBigrams); diff = System.currentTimeMillis() - now; @@ -457,17 +423,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { Log.e(TAG, "IOException", e); } catch (UnsupportedFormatException e) { Log.e(TAG, "UnsupportedFormatException", e); - } finally { - if (inStream != null) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } } - checkWordMap(words, bigrams, resultWords, resultFreqs, resultBigrams); + checkWordMap(words, bigrams, resultWords, resultFreqs, resultBigrams, checkProbability); return diff; } @@ -476,20 +434,24 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final FormatSpec.FormatOptions formatOptions, final String message) { final String dictName = "runReadUnigrams"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); // making the dictionary from lists of words. final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(words.size(), dict, words, null /* shortcutMap */); addBigrams(dict, words, bigrams); timeWritingDictToFile(file, dict, formatOptions); + // Caveat: Currently, the Java code to read a v4 dictionary doesn't calculate the + // probability when there's a timestamp for the entry. + // TODO: Abandon the Java code, and implement the v4 dictionary reading code in native. long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType, - formatOptions, dict.mOptions); + !formatOptions.mHasTimestamp /* checkProbability */); long fullReading = timeReadingAndCheckDict(file, words, bigrams, null /* shortcutMap */, - bufferType, formatOptions, dict.mOptions); + bufferType); return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap + " : " + message + " : " + outputOptions(bufferType, formatOptions); @@ -508,13 +470,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadUnigramsAndBigramsBinaryWithByteBuffer() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION2); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, - VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); @@ -524,13 +481,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testReadUnigramsAndBigramsBinaryWithByteArray() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION2); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, - VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); @@ -541,7 +493,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private String getWordFromBinary(final DictDecoder dictDecoder, final int address) { if (dictDecoder.getPosition() != 0) dictDecoder.setPosition(0); - FileHeader fileHeader = null; + DictionaryHeader fileHeader = null; try { fileHeader = dictDecoder.readHeader(); } catch (IOException e) { @@ -550,8 +502,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { return null; } if (fileHeader == null) return null; - return BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize, - address, fileHeader.mFormatOptions).mWord; + return BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mBodyOffset, + address).mWord; } private long checkGetTerminalPosition(final DictDecoder dictDecoder, final String word, @@ -578,20 +530,22 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final FormatOptions formatOptions, final String message) { final String dictName = "testGetTerminalPosition"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - getDictionaryOptions(dictName, dictVersion)); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */); addBigrams(dict, words, bigrams); timeWritingDictToFile(file, dict, formatOptions); - final DictDecoder dictDecoder = getDictDecoder(file, DictDecoder.USE_BYTEARRAY, - formatOptions, dict.mOptions); + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length(), + DictDecoder.USE_BYTEARRAY); try { dictDecoder.openDictBuffer(); } catch (IOException e) { - // ignore + Log.e(TAG, "IOException while opening the buffer", e); + } catch (UnsupportedFormatException e) { Log.e(TAG, "IOException while opening the buffer", e); } assertTrue("Can't get the buffer", dictDecoder.isDictBufferOpen()); @@ -638,65 +592,110 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testGetTerminalPosition() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION2); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); - - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION2); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, + BinaryDictUtils.VERSION2_OPTIONS); + runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, + BinaryDictUtils.VERSION2_OPTIONS); for (final String result : results) { Log.d(TAG, result); } } - private void runTestDeleteWord(final FormatOptions formatOptions) { - final String dictName = "testDeleteWord"; + public void testVer2DictGetWordProperty() { + final FormatOptions formatOptions = BinaryDictUtils.VERSION2_OPTIONS; + final ArrayList<String> words = sWords; + final HashMap<String, List<String>> shortcuts = sShortcuts; + final String dictName = "testGetWordProperty"; final String dictVersion = Long.toString(System.currentTimeMillis()); - final File file = setUpDictionaryFile(dictName, dictVersion); - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions( - new HashMap<String, String>(), false, false)); - addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */); + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); + addUnigrams(words.size(), dict, words, shortcuts); + addBigrams(dict, words, sEmptyBigrams); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); + file.delete(); timeWritingDictToFile(file, dict, formatOptions); - - final DictUpdater dictUpdater; - if (formatOptions.mVersion == 3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else if (formatOptions.mVersion == 4) { - dictUpdater = new Ver4DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatOptions.mVersion - + " doesn't exist."); - } - - try { - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(0))); - dictUpdater.deleteWord(sWords.get(0)); - assertEquals(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(0))); - - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(5))); - dictUpdater.deleteWord(sWords.get(5)); - assertEquals(FormatSpec.NOT_VALID_WORD, - dictUpdater.getTerminalPosition(sWords.get(5))); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { + final BinaryDictionary binaryDictionary = new BinaryDictionary(file.getAbsolutePath(), + 0 /* offset */, file.length(), true /* useFullEditDistance */, + Locale.ENGLISH, dictName, false /* isUpdatable */); + for (final String word : words) { + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals(word, wordProperty.mWord); + assertEquals(UNIGRAM_FREQ, wordProperty.getProbability()); + if (shortcuts.containsKey(word)) { + assertEquals(shortcuts.get(word).size(), wordProperty.mShortcutTargets.size()); + final List<String> shortcutList = shortcuts.get(word); + assertTrue(wordProperty.mHasShortcuts); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutList.contains(shortcutTarget.mWord)); + assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability()); + shortcutList.remove(shortcutTarget.mWord); + } + assertTrue(shortcutList.isEmpty()); + } } } - public void testDeleteWord() { - runTestDeleteWord(VERSION3_WITH_DYNAMIC_UPDATE); - runTestDeleteWord(VERSION4_WITH_DYNAMIC_UPDATE); + public void testVer2DictIteration() { + final FormatOptions formatOptions = BinaryDictUtils.VERSION2_OPTIONS; + final ArrayList<String> words = sWords; + final HashMap<String, List<String>> shortcuts = sShortcuts; + final SparseArray<List<Integer>> bigrams = sEmptyBigrams; + final String dictName = "testGetWordProperty"; + final String dictVersion = Long.toString(System.currentTimeMillis()); + final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); + addUnigrams(words.size(), dict, words, shortcuts); + addBigrams(dict, words, bigrams); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); + timeWritingDictToFile(file, dict, formatOptions); + Log.d(TAG, file.getAbsolutePath()); + final BinaryDictionary binaryDictionary = new BinaryDictionary(file.getAbsolutePath(), + 0 /* offset */, file.length(), true /* useFullEditDistance */, + Locale.ENGLISH, dictName, false /* isUpdatable */); + + final HashSet<String> wordSet = new HashSet<String>(words); + final HashSet<Pair<String, String>> bigramSet = new HashSet<Pair<String,String>>(); + + for (int i = 0; i < words.size(); i++) { + final List<Integer> bigramList = bigrams.get(i); + if (bigramList != null) { + for (final Integer word1Index : bigramList) { + final String word1 = words.get(word1Index); + bigramSet.add(new Pair<String, String>(words.get(i), word1)); + } + } + } + int token = 0; + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + final String word0 = wordProperty.mWord; + assertEquals(UNIGRAM_FREQ, wordProperty.mProbabilityInfo.mProbability); + wordSet.remove(word0); + if (shortcuts.containsKey(word0)) { + assertEquals(shortcuts.get(word0).size(), wordProperty.mShortcutTargets.size()); + final List<String> shortcutList = shortcuts.get(word0); + assertNotNull(wordProperty.mShortcutTargets); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutList.contains(shortcutTarget.mWord)); + assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability()); + shortcutList.remove(shortcutTarget.mWord); + } + assertTrue(shortcutList.isEmpty()); + } + for (int j = 0; j < wordProperty.mBigrams.size(); j++) { + final String word1 = wordProperty.mBigrams.get(j).mWord; + final Pair<String, String> bigram = new Pair<String, String>(word0, word1); + assertTrue(bigramSet.contains(bigram)); + bigramSet.remove(bigram); + } + token = result.mNextToken; + } while (token != 0); + assertTrue(wordSet.isEmpty()); + assertTrue(bigramSet.isEmpty()); } } diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java new file mode 100644 index 000000000..6f8b07a34 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +/** + * Decodes binary files for a FusionDictionary. + * + * All the methods in this class are static. + * + * TODO: Move this file to makedict/internal. + * TODO: Rename this class to DictDecoderUtils. + */ +public final class BinaryDictDecoderUtils { + + private static final boolean DBG = MakedictLog.DBG; + + private BinaryDictDecoderUtils() { + // This utility class is not publicly instantiable. + } + + @UsedForTesting + public interface DictBuffer { + public int readUnsignedByte(); + public int readUnsignedShort(); + public int readUnsignedInt24(); + public int readInt(); + public int position(); + public void position(int newPosition); + @UsedForTesting + public void put(final byte b); + public int limit(); + @UsedForTesting + public int capacity(); + } + + public static final class ByteBufferDictBuffer implements DictBuffer { + private ByteBuffer mBuffer; + + public ByteBufferDictBuffer(final ByteBuffer buffer) { + mBuffer = buffer; + } + + @Override + public int readUnsignedByte() { + return mBuffer.get() & 0xFF; + } + + @Override + public int readUnsignedShort() { + return mBuffer.getShort() & 0xFFFF; + } + + @Override + public int readUnsignedInt24() { + final int retval = readUnsignedByte(); + return (retval << 16) + readUnsignedShort(); + } + + @Override + public int readInt() { + return mBuffer.getInt(); + } + + @Override + public int position() { + return mBuffer.position(); + } + + @Override + public void position(int newPos) { + mBuffer.position(newPos); + } + + @Override + public void put(final byte b) { + mBuffer.put(b); + } + + @Override + public int limit() { + return mBuffer.limit(); + } + + @Override + public int capacity() { + return mBuffer.capacity(); + } + } + + /** + * A class grouping utility function for our specific character encoding. + */ + static final class CharEncoding { + private static final int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20; + private static final int MAXIMAL_ONE_BYTE_CHARACTER_VALUE = 0xFF; + + /** + * Helper method to find out whether this code fits on one byte + */ + private static boolean fitsOnOneByte(final int character) { + return character >= MINIMAL_ONE_BYTE_CHARACTER_VALUE + && character <= MAXIMAL_ONE_BYTE_CHARACTER_VALUE; + } + + /** + * Compute the size of a character given its character code. + * + * Char format is: + * 1 byte = bbbbbbbb match + * case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte + * else: if 00011111 (= 0x1F) : this is the terminator. This is a relevant choice because + * unicode code points range from 0 to 0x10FFFF, so any 3-byte value starting with + * 00011111 would be outside unicode. + * else: iso-latin-1 code + * This allows for the whole unicode range to be encoded, including chars outside of + * the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control + * characters which should never happen anyway (and still work, but take 3 bytes). + * + * @param character the character code. + * @return the size in binary encoded-form, either 1 or 3 bytes. + */ + static int getCharSize(final int character) { + // See char encoding in FusionDictionary.java + if (fitsOnOneByte(character)) return 1; + if (FormatSpec.INVALID_CHARACTER == character) return 1; + return 3; + } + + /** + * Compute the byte size of a character array. + */ + static int getCharArraySize(final int[] chars) { + int size = 0; + for (int character : chars) size += getCharSize(character); + return size; + } + + /** + * Writes a char array to a byte buffer. + * + * @param codePoints the code point array to write. + * @param buffer the byte buffer to write to. + * @param index the index in buffer to write the character array to. + * @return the index after the last character. + */ + static int writeCharArray(final int[] codePoints, final byte[] buffer, int index) { + for (int codePoint : codePoints) { + if (1 == getCharSize(codePoint)) { + buffer[index++] = (byte)codePoint; + } else { + buffer[index++] = (byte)(0xFF & (codePoint >> 16)); + buffer[index++] = (byte)(0xFF & (codePoint >> 8)); + buffer[index++] = (byte)(0xFF & codePoint); + } + } + return index; + } + + /** + * Writes a string with our character format to a byte buffer. + * + * This will also write the terminator byte. + * + * @param buffer the byte buffer to write to. + * @param origin the offset to write from. + * @param word the string to write. + * @return the size written, in bytes. + */ + static int writeString(final byte[] buffer, final int origin, final String word) { + final int length = word.length(); + int index = origin; + for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { + final int codePoint = word.codePointAt(i); + if (1 == getCharSize(codePoint)) { + buffer[index++] = (byte)codePoint; + } else { + buffer[index++] = (byte)(0xFF & (codePoint >> 16)); + buffer[index++] = (byte)(0xFF & (codePoint >> 8)); + buffer[index++] = (byte)(0xFF & codePoint); + } + } + buffer[index++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR; + return index - origin; + } + + /** + * Writes a string with our character format to an OutputStream. + * + * This will also write the terminator byte. + * + * @param stream the OutputStream to write to. + * @param word the string to write. + * @return the size written, in bytes. + */ + static int writeString(final OutputStream stream, final String word) throws IOException { + final int length = word.length(); + int written = 0; + for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) { + final int codePoint = word.codePointAt(i); + final int charSize = getCharSize(codePoint); + if (1 == charSize) { + stream.write((byte) codePoint); + } else { + stream.write((byte) (0xFF & (codePoint >> 16))); + stream.write((byte) (0xFF & (codePoint >> 8))); + stream.write((byte) (0xFF & codePoint)); + } + written += charSize; + } + stream.write(FormatSpec.PTNODE_CHARACTERS_TERMINATOR); + written += FormatSpec.PTNODE_TERMINATOR_SIZE; + return written; + } + + /** + * Reads a string from a DictBuffer. This is the converse of the above method. + */ + static String readString(final DictBuffer dictBuffer) { + final StringBuilder s = new StringBuilder(); + int character = readChar(dictBuffer); + while (character != FormatSpec.INVALID_CHARACTER) { + s.appendCodePoint(character); + character = readChar(dictBuffer); + } + return s.toString(); + } + + /** + * Reads a character from the buffer. + * + * This follows the character format documented earlier in this source file. + * + * @param dictBuffer the buffer, positioned over an encoded character. + * @return the character code. + */ + static int readChar(final DictBuffer dictBuffer) { + int character = dictBuffer.readUnsignedByte(); + if (!fitsOnOneByte(character)) { + if (FormatSpec.PTNODE_CHARACTERS_TERMINATOR == character) { + return FormatSpec.INVALID_CHARACTER; + } + character <<= 16; + character += dictBuffer.readUnsignedShort(); + } + return character; + } + } + + /** + * Reads and returns the PtNode count out of a buffer and forwards the pointer. + */ + /* package */ static int readPtNodeCount(final DictBuffer dictBuffer) { + final int msb = dictBuffer.readUnsignedByte(); + if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= msb) { + return msb; + } else { + return ((FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT & msb) << 8) + + dictBuffer.readUnsignedByte(); + } + } + + /** + * Finds, as a string, the word at the position passed as an argument. + * + * @param dictDecoder the dict decoder. + * @param headerSize the size of the header. + * @param pos the position to seek. + * @return the word with its frequency, as a weighted string. + */ + @UsedForTesting + /* package for tests */ static WeightedString getWordAtPosition(final DictDecoder dictDecoder, + final int headerSize, final int pos) { + final WeightedString result; + final int originalPos = dictDecoder.getPosition(); + dictDecoder.setPosition(pos); + result = getWordAtPositionWithoutParentAddress(dictDecoder, headerSize, pos); + dictDecoder.setPosition(originalPos); + return result; + } + + private static WeightedString getWordAtPositionWithoutParentAddress( + final DictDecoder dictDecoder, final int headerSize, final int pos) { + dictDecoder.setPosition(headerSize); + final int count = dictDecoder.readPtNodeCount(); + int groupPos = dictDecoder.getPosition(); + final StringBuilder builder = new StringBuilder(); + WeightedString result = null; + + PtNodeInfo last = null; + for (int i = count - 1; i >= 0; --i) { + PtNodeInfo info = dictDecoder.readPtNode(groupPos); + groupPos = info.mEndAddress; + if (info.mOriginalAddress == pos) { + builder.append(new String(info.mCharacters, 0, info.mCharacters.length)); + result = new WeightedString(builder.toString(), info.mProbabilityInfo); + break; // and return + } + if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) { + if (info.mChildrenAddress > pos) { + if (null == last) continue; + builder.append(new String(last.mCharacters, 0, last.mCharacters.length)); + dictDecoder.setPosition(last.mChildrenAddress); + i = dictDecoder.readPtNodeCount(); + groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i); + last = null; + continue; + } + last = info; + } + if (0 == i && BinaryDictIOUtils.hasChildrenAddress(last.mChildrenAddress)) { + builder.append(new String(last.mCharacters, 0, last.mCharacters.length)); + dictDecoder.setPosition(last.mChildrenAddress); + i = dictDecoder.readPtNodeCount(); + groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i); + last = null; + continue; + } + } + return result; + } + + /** + * Helper method to pass a file name instead of a File object to isBinaryDictionary. + */ + public static boolean isBinaryDictionary(final String filename) { + final File file = new File(filename); + return isBinaryDictionary(file); + } + + /** + * Basic test to find out whether the file is a binary dictionary or not. + * + * @param file The file to test. + * @return true if it's a binary dictionary, false otherwise + */ + public static boolean isBinaryDictionary(final File file) { + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length()); + if (dictDecoder == null) { + return false; + } + return dictDecoder.hasValidRawBinaryDictionary(); + } +} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java index f761829de..39bd98bad 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java @@ -16,12 +16,12 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; +import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -121,18 +121,13 @@ public class BinaryDictEncoderUtils { * Compute the maximum size of a PtNode, assuming 3-byte addresses for everything. * * @param ptNode the PtNode to compute the size of. - * @param options file format options. * @return the maximum size of the PtNode. */ - private static int getPtNodeMaximumSize(final PtNode ptNode, final FormatOptions options) { - int size = getNodeHeaderSize(ptNode, options); + private static int getPtNodeMaximumSize(final PtNode ptNode) { + int size = getNodeHeaderSize(ptNode); if (ptNode.isTerminal()) { - // If terminal, one byte for the frequency or four bytes for the terminal id. - if (options.mHasTerminalId) { - size += FormatSpec.PTNODE_TERMINAL_ID_SIZE; - } else { - size += FormatSpec.PTNODE_FREQUENCY_SIZE; - } + // If terminal, one byte for the frequency. + size += FormatSpec.PTNODE_FREQUENCY_SIZE; } size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address size += getShortcutListSize(ptNode.mShortcutTargets); @@ -150,19 +145,14 @@ public class BinaryDictEncoderUtils { * the containing node array, and cache it it its 'mCachedSize' member. * * @param ptNodeArray the node array to compute the maximum size of. - * @param options file format options. */ - private static void calculatePtNodeArrayMaximumSize(final PtNodeArray ptNodeArray, - final FormatOptions options) { + private static void calculatePtNodeArrayMaximumSize(final PtNodeArray ptNodeArray) { int size = getPtNodeCountSize(ptNodeArray); for (PtNode node : ptNodeArray.mData) { - final int nodeSize = getPtNodeMaximumSize(node, options); + final int nodeSize = getPtNodeMaximumSize(node); node.mCachedSize = nodeSize; size += nodeSize; } - if (options.mSupportsDynamicUpdate) { - size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; - } ptNodeArray.mCachedSize = size; } @@ -170,15 +160,9 @@ public class BinaryDictEncoderUtils { * Compute the size of the header (flag + [parent address] + characters size) of a PtNode. * * @param ptNode the PtNode of which to compute the size of the header - * @param options file format options. */ - private static int getNodeHeaderSize(final PtNode ptNode, final FormatOptions options) { - if (BinaryDictIOUtils.supportsDynamicUpdate(options)) { - return FormatSpec.PTNODE_FLAGS_SIZE + FormatSpec.PARENT_ADDRESS_SIZE - + getPtNodeCharactersSize(ptNode); - } else { - return FormatSpec.PTNODE_FLAGS_SIZE + getPtNodeCharactersSize(ptNode); - } + private static int getNodeHeaderSize(final PtNode ptNode) { + return FormatSpec.PTNODE_FLAGS_SIZE + getPtNodeCharactersSize(ptNode); } /** @@ -245,6 +229,27 @@ public class BinaryDictEncoderUtils { } } + @UsedForTesting + static void writeUIntToDictBuffer(final DictBuffer dictBuffer, final int value, + final int size) { + switch(size) { + case 4: + dictBuffer.put((byte) ((value >> 24) & 0xFF)); + /* fall through */ + case 3: + dictBuffer.put((byte) ((value >> 16) & 0xFF)); + /* fall through */ + case 2: + dictBuffer.put((byte) ((value >> 8) & 0xFF)); + /* fall through */ + case 1: + dictBuffer.put((byte) (value & 0xFF)); + break; + default: + /* nop */ + } + } + // End utility methods // This method is responsible for finding a nice ordering of the nodes that favors run-time @@ -357,11 +362,10 @@ public class BinaryDictEncoderUtils { * * @param ptNodeArray the node array to compute the size of. * @param dict the dictionary in which the word/attributes are to be found. - * @param formatOptions file format options. * @return false if none of the cached addresses inside the node array changed, true otherwise. */ private static boolean computeActualPtNodeArraySize(final PtNodeArray ptNodeArray, - final FusionDictionary dict, final FormatOptions formatOptions) { + final FusionDictionary dict) { boolean changed = false; int size = getPtNodeCountSize(ptNodeArray); for (PtNode ptNode : ptNodeArray.mData) { @@ -369,37 +373,26 @@ public class BinaryDictEncoderUtils { if (ptNode.mCachedAddressAfterUpdate != ptNode.mCachedAddressBeforeUpdate) { changed = true; } - int nodeSize = getNodeHeaderSize(ptNode, formatOptions); + int nodeSize = getNodeHeaderSize(ptNode); if (ptNode.isTerminal()) { - if (formatOptions.mHasTerminalId) { - nodeSize += FormatSpec.PTNODE_TERMINAL_ID_SIZE; - } else { - nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE; - } + nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE; } - if (formatOptions.mSupportsDynamicUpdate) { - nodeSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; - } else if (null != ptNode.mChildren) { + if (null != ptNode.mChildren) { nodeSize += getByteSize(getOffsetToTargetNodeArrayDuringUpdate(ptNodeArray, nodeSize + size, ptNode.mChildren)); } - if (formatOptions.mVersion < FormatSpec.FIRST_VERSION_WITH_TERMINAL_ID) { - nodeSize += getShortcutListSize(ptNode.mShortcutTargets); - if (null != ptNode.mBigrams) { - for (WeightedString bigram : ptNode.mBigrams) { - final int offset = getOffsetToTargetPtNodeDuringUpdate(ptNodeArray, - nodeSize + size + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE, - FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord)); - nodeSize += getByteSize(offset) + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE; - } + nodeSize += getShortcutListSize(ptNode.mShortcutTargets); + if (null != ptNode.mBigrams) { + for (WeightedString bigram : ptNode.mBigrams) { + final int offset = getOffsetToTargetPtNodeDuringUpdate(ptNodeArray, + nodeSize + size + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE, + FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord)); + nodeSize += getByteSize(offset) + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE; } } ptNode.mCachedSize = nodeSize; size += nodeSize; } - if (formatOptions.mSupportsDynamicUpdate) { - size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; - } if (ptNodeArray.mCachedSize != size) { ptNodeArray.mCachedSize = size; changed = true; @@ -411,11 +404,10 @@ public class BinaryDictEncoderUtils { * Initializes the cached addresses of node arrays and their containing nodes from their size. * * @param flatNodes the list of node arrays. - * @param formatOptions file format options. * @return the byte size of the entire stack. */ - private static int initializePtNodeArraysCachedAddresses(final ArrayList<PtNodeArray> flatNodes, - final FormatOptions formatOptions) { + private static int initializePtNodeArraysCachedAddresses( + final ArrayList<PtNodeArray> flatNodes) { int nodeArrayOffset = 0; for (final PtNodeArray nodeArray : flatNodes) { nodeArray.mCachedAddressBeforeUpdate = nodeArrayOffset; @@ -446,28 +438,6 @@ public class BinaryDictEncoderUtils { } /** - * Compute the cached parent addresses after all has been updated. - * - * The parent addresses are used by some binary formats at write-to-disk time. Not all formats - * need them. In particular, version 2 does not need them, and version 3 does. - * - * @param flatNodes the flat array of node arrays to fill in - */ - private static void computeParentAddresses(final ArrayList<PtNodeArray> flatNodes) { - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (null != ptNode.mChildren) { - // Assign my address to children's parent address - // Here BeforeUpdate and AfterUpdate addresses have the same value, so it - // does not matter which we use. - ptNode.mChildren.mCachedParentAddress = ptNode.mCachedAddressAfterUpdate - - ptNode.mChildren.mCachedAddressAfterUpdate; - } - } - } - } - - /** * Compute the addresses and sizes of an ordered list of PtNode arrays. * * This method takes a list of PtNode arrays and will update their cached address and size @@ -479,14 +449,15 @@ public class BinaryDictEncoderUtils { * * @param dict the dictionary * @param flatNodes the ordered list of PtNode arrays - * @param formatOptions file format options. * @return the same array it was passed. The nodes have been updated for address and size. */ /* package */ static ArrayList<PtNodeArray> computeAddresses(final FusionDictionary dict, - final ArrayList<PtNodeArray> flatNodes, final FormatOptions formatOptions) { + final ArrayList<PtNodeArray> flatNodes) { // First get the worst possible sizes and offsets - for (final PtNodeArray n : flatNodes) calculatePtNodeArrayMaximumSize(n, formatOptions); - final int offset = initializePtNodeArraysCachedAddresses(flatNodes, formatOptions); + for (final PtNodeArray n : flatNodes) { + calculatePtNodeArrayMaximumSize(n); + } + final int offset = initializePtNodeArraysCachedAddresses(flatNodes); MakedictLog.i("Compressing the array addresses. Original size : " + offset); MakedictLog.i("(Recursively seen size : " + offset + ")"); @@ -499,8 +470,7 @@ public class BinaryDictEncoderUtils { for (final PtNodeArray ptNodeArray : flatNodes) { ptNodeArray.mCachedAddressAfterUpdate = ptNodeArrayStartOffset; final int oldNodeArraySize = ptNodeArray.mCachedSize; - final boolean changed = - computeActualPtNodeArraySize(ptNodeArray, dict, formatOptions); + final boolean changed = computeActualPtNodeArraySize(ptNodeArray, dict); final int newNodeArraySize = ptNodeArray.mCachedSize; if (oldNodeArraySize < newNodeArraySize) { throw new RuntimeException("Increased size ?!"); @@ -513,9 +483,6 @@ public class BinaryDictEncoderUtils { if (passes > MAX_PASSES) throw new RuntimeException("Too many passes - probably a bug"); } while (changesDone); - if (formatOptions.mSupportsDynamicUpdate) { - computeParentAddresses(flatNodes); - } final PtNodeArray lastPtNodeArray = flatNodes.get(flatNodes.size() - 1); MakedictLog.i("Compression complete in " + passes + " passes."); MakedictLog.i("After address compression : " @@ -612,35 +579,29 @@ public class BinaryDictEncoderUtils { * @param hasBigrams whether the PtNode has bigrams. * @param isNotAWord whether the PtNode is not a word. * @param isBlackListEntry whether the PtNode is a blacklist entry. - * @param formatOptions file format options. * @return the flags */ static int makePtNodeFlags(final boolean hasMultipleChars, final boolean isTerminal, final int childrenAddressSize, final boolean hasShortcuts, final boolean hasBigrams, - final boolean isNotAWord, final boolean isBlackListEntry, - final FormatOptions formatOptions) { + final boolean isNotAWord, final boolean isBlackListEntry) { byte flags = 0; if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS; if (isTerminal) flags |= FormatSpec.FLAG_IS_TERMINAL; - if (formatOptions.mSupportsDynamicUpdate) { - flags |= FormatSpec.FLAG_IS_NOT_MOVED; - } else if (true) { - switch (childrenAddressSize) { - case 1: - flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE; - break; - case 2: - flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES; - break; - case 3: - flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES; - break; - case 0: - flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS; - break; - default: - throw new RuntimeException("Node with a strange address"); - } + switch (childrenAddressSize) { + case 1: + flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE; + break; + case 2: + flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES; + break; + case 3: + flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES; + break; + case 0: + flags |= FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS; + break; + default: + throw new RuntimeException("Node with a strange address"); } if (hasShortcuts) flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS; if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS; @@ -649,12 +610,12 @@ public class BinaryDictEncoderUtils { return flags; } - /* package */ static byte makePtNodeFlags(final PtNode node, final int childrenOffset, - final FormatOptions formatOptions) { - return (byte) makePtNodeFlags(node.mChars.length > 1, node.mFrequency >= 0, + /* package */ static byte makePtNodeFlags(final PtNode node, final int childrenOffset) { + return (byte) makePtNodeFlags(node.mChars.length > 1, node.isTerminal(), getByteSize(childrenOffset), node.mShortcutTargets != null && !node.mShortcutTargets.isEmpty(), - node.mBigrams != null, node.mIsNotAWord, node.mIsBlacklistEntry, formatOptions); + node.mBigrams != null && !node.mBigrams.isEmpty(), + node.mIsNotAWord, node.mIsBlacklistEntry); } /** @@ -690,6 +651,13 @@ public class BinaryDictEncoderUtils { + word + " is " + unigramFrequency); bigramFrequency = unigramFrequency; } + bigramFlags += getBigramFrequencyDiff(unigramFrequency, bigramFrequency) + & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY; + return bigramFlags; + } + + public static int getBigramFrequencyDiff(final int unigramFrequency, + final int bigramFrequency) { // We compute the difference between 255 (which means probability = 1) and the // unigram score. We split this into a number of discrete steps. // Now, the steps are numbered 0~15; 0 represents an increase of 1 step while 15 @@ -723,22 +691,7 @@ public class BinaryDictEncoderUtils { // include this bigram in the dictionary. For now, register as 0, and live with the // small over-estimation that we get in this case. TODO: actually remove this bigram // if discretizedFrequency < 0. - final int finalBigramFrequency = discretizedFrequency > 0 ? discretizedFrequency : 0; - bigramFlags += finalBigramFrequency & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY; - return bigramFlags; - } - - /** - * Makes the 2-byte value for options flags. - */ - private static final int makeOptionsValue(final FusionDictionary dictionary, - final FormatOptions formatOptions) { - final DictionaryOptions options = dictionary.mOptions; - final boolean hasBigrams = dictionary.hasBigrams(); - return (options.mFrenchLigatureProcessing ? FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG : 0) - + (options.mGermanUmlautProcessing ? FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG : 0) - + (hasBigrams ? FormatSpec.CONTAINS_BIGRAMS_FLAG : 0) - + (formatOptions.mSupportsDynamicUpdate ? FormatSpec.SUPPORTS_DYNAMIC_UPDATE : 0); + return discretizedFrequency > 0 ? discretizedFrequency : 0; } /** @@ -753,38 +706,14 @@ public class BinaryDictEncoderUtils { + (frequency & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY); } - /* package */ static final int writeParentAddress(final byte[] buffer, final int index, - final int address, final FormatOptions formatOptions) { - if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) { - if (address == FormatSpec.NO_PARENT_ADDRESS) { - buffer[index] = buffer[index + 1] = buffer[index + 2] = 0; - } else { - final int absAddress = Math.abs(address); - assert(absAddress <= FormatSpec.SINT24_MAX); - buffer[index] = (byte)((address < 0 ? FormatSpec.MSB8 : 0) - | ((absAddress >> 16) & 0xFF)); - buffer[index + 1] = (byte)((absAddress >> 8) & 0xFF); - buffer[index + 2] = (byte)(absAddress & 0xFF); - } - return index + 3; - } else { - return index; - } - } - - /* package */ static final int getChildrenPosition(final PtNode ptNode, - final FormatOptions formatOptions) { + /* package */ static final int getChildrenPosition(final PtNode ptNode) { int positionOfChildrenPosField = ptNode.mCachedAddressAfterUpdate - + getNodeHeaderSize(ptNode, formatOptions); + + getNodeHeaderSize(ptNode); if (ptNode.isTerminal()) { - // A terminal node has either the terminal id or the frequency. + // A terminal node has the frequency. // If positionOfChildrenPosField is incorrect, we may crash when jumping to the children // position. - if (formatOptions.mHasTerminalId) { - positionOfChildrenPosField += FormatSpec.PTNODE_TERMINAL_ID_SIZE; - } else { - positionOfChildrenPosField += FormatSpec.PTNODE_FREQUENCY_SIZE; - } + positionOfChildrenPosField += FormatSpec.PTNODE_FREQUENCY_SIZE; } return null == ptNode.mChildren ? FormatSpec.NO_CHILDREN_ADDRESS : ptNode.mChildren.mCachedAddressAfterUpdate - positionOfChildrenPosField; @@ -796,12 +725,10 @@ public class BinaryDictEncoderUtils { * @param dict the dictionary the node array is a part of (for relative offsets). * @param dictEncoder the dictionary encoder. * @param ptNodeArray the node array to write. - * @param formatOptions file format options. */ @SuppressWarnings("unused") /* package */ static void writePlacedPtNodeArray(final FusionDictionary dict, - final DictEncoder dictEncoder, final PtNodeArray ptNodeArray, - final FormatOptions formatOptions) { + final DictEncoder dictEncoder, final PtNodeArray ptNodeArray) { // TODO: Make the code in common with BinaryDictIOUtils#writePtNode dictEncoder.setPosition(ptNodeArray.mCachedAddressAfterUpdate); @@ -819,15 +746,12 @@ public class BinaryDictEncoderUtils { + ptNode.mCachedAddressAfterUpdate); } // Sanity checks. - if (DBG && ptNode.mFrequency > FormatSpec.MAX_TERMINAL_FREQUENCY) { + if (DBG && ptNode.getProbability() > FormatSpec.MAX_TERMINAL_FREQUENCY) { throw new RuntimeException("A node has a frequency > " + FormatSpec.MAX_TERMINAL_FREQUENCY - + " : " + ptNode.mFrequency); + + " : " + ptNode.mProbabilityInfo.toString()); } - dictEncoder.writePtNode(ptNode, parentPosition, formatOptions, dict); - } - if (formatOptions.mSupportsDynamicUpdate) { - dictEncoder.writeForwardLinkAddress(FormatSpec.NO_FORWARD_LINK_ADDRESS); + dictEncoder.writePtNode(ptNode, dict); } if (dictEncoder.getPosition() != ptNodeArray.mCachedAddressAfterUpdate + ptNodeArray.mCachedSize) { @@ -857,7 +781,7 @@ public class BinaryDictEncoderUtils { for (final PtNode ptNode : ptNodeArray.mData) { ++ptNodes; if (ptNode.mChars.length > maxRuns) maxRuns = ptNode.mChars.length; - if (ptNode.mFrequency >= 0) { + if (ptNode.isTerminal()) { if (ptNodeArray.mCachedAddressAfterUpdate < firstTerminalAddress) firstTerminalAddress = ptNodeArray.mCachedAddressAfterUpdate; if (ptNodeArray.mCachedAddressAfterUpdate > lastTerminalAddress) @@ -927,7 +851,8 @@ public class BinaryDictEncoderUtils { headerBuffer.write((byte) (0xFF & version)); // Options flags - final int options = makeOptionsValue(dict, formatOptions); + // TODO: Remove this field. + final int options = 0; headerBuffer.write((byte) (0xFF & (options >> 8))); headerBuffer.write((byte) (0xFF & options)); final int headerSizeOffset = headerBuffer.size(); diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java new file mode 100644 index 000000000..42a50be66 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -0,0 +1,306 @@ +/* + * 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Map; +import java.util.Stack; + +public final class BinaryDictIOUtils { + private static final boolean DBG = false; + + private BinaryDictIOUtils() { + // This utility class is not publicly instantiable. + } + + /** + * Returns new dictionary decoder. + * + * @param dictFile the dictionary file. + * @param bufferType The type of buffer, as one of USE_* in DictDecoder. + * @return new dictionary decoder if the dictionary file exists, otherwise null. + */ + public static DictDecoder getDictDecoder(final File dictFile, final long offset, + final long length, final int bufferType) { + if (dictFile.isDirectory()) { + return new Ver4DictDecoder(dictFile, bufferType); + } else if (dictFile.isFile()) { + return new Ver2DictDecoder(dictFile, offset, length, bufferType); + } + return null; + } + + public static DictDecoder getDictDecoder(final File dictFile, final long offset, + final long length, final DictionaryBufferFactory factory) { + if (dictFile.isDirectory()) { + return new Ver4DictDecoder(dictFile, factory); + } else if (dictFile.isFile()) { + return new Ver2DictDecoder(dictFile, offset, length, factory); + } + return null; + } + + public static DictDecoder getDictDecoder(final File dictFile, final long offset, + final long length) { + return getDictDecoder(dictFile, offset, length, DictDecoder.USE_READONLY_BYTEBUFFER); + } + + private static final class Position { + public static final int NOT_READ_PTNODE_COUNT = -1; + + public int mAddress; + public int mNumOfPtNode; + public int mPosition; + public int mLength; + + public Position(int address, int length) { + mAddress = address; + mLength = length; + mNumOfPtNode = NOT_READ_PTNODE_COUNT; + } + } + + /** + * Retrieves all node arrays without recursive call. + */ + private static void readUnigramsAndBigramsBinaryInner(final DictDecoder dictDecoder, + final int bodyOffset, final Map<Integer, String> words, + final Map<Integer, Integer> frequencies, + final Map<Integer, ArrayList<PendingAttribute>> bigrams) { + int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1]; + + Stack<Position> stack = new Stack<Position>(); + int index = 0; + + Position initPos = new Position(bodyOffset, 0); + stack.push(initPos); + + while (!stack.empty()) { + Position p = stack.peek(); + + if (DBG) { + MakedictLog.d("read: address=" + p.mAddress + ", numOfPtNode=" + + p.mNumOfPtNode + ", position=" + p.mPosition + ", length=" + p.mLength); + } + + if (dictDecoder.getPosition() != p.mAddress) dictDecoder.setPosition(p.mAddress); + if (index != p.mLength) index = p.mLength; + + if (p.mNumOfPtNode == Position.NOT_READ_PTNODE_COUNT) { + p.mNumOfPtNode = dictDecoder.readPtNodeCount(); + p.mAddress = dictDecoder.getPosition(); + p.mPosition = 0; + } + if (p.mNumOfPtNode == 0) { + stack.pop(); + continue; + } + final PtNodeInfo ptNodeInfo = dictDecoder.readPtNode(p.mAddress); + for (int i = 0; i < ptNodeInfo.mCharacters.length; ++i) { + pushedChars[index++] = ptNodeInfo.mCharacters[i]; + } + p.mPosition++; + if (ptNodeInfo.isTerminal()) {// found word + words.put(ptNodeInfo.mOriginalAddress, new String(pushedChars, 0, index)); + frequencies.put( + ptNodeInfo.mOriginalAddress, ptNodeInfo.mProbabilityInfo.mProbability); + if (ptNodeInfo.mBigrams != null) { + bigrams.put(ptNodeInfo.mOriginalAddress, ptNodeInfo.mBigrams); + } + } + + if (p.mPosition == p.mNumOfPtNode) { + stack.pop(); + } else { + // The PtNode array has more PtNodes. + p.mAddress = dictDecoder.getPosition(); + } + + if (hasChildrenAddress(ptNodeInfo.mChildrenAddress)) { + final Position childrenPos = new Position(ptNodeInfo.mChildrenAddress, index); + stack.push(childrenPos); + } + } + } + + /** + * Reads unigrams and bigrams from the binary file. + * Doesn't store a full memory representation of the dictionary. + * + * @param dictDecoder the dict decoder. + * @param words the map to store the address as a key and the word as a value. + * @param frequencies the map to store the address as a key and the frequency as a value. + * @param bigrams the map to store the address as a key and the list of address as a value. + * @throws IOException if the file can't be read. + * @throws UnsupportedFormatException if the format of the file is not recognized. + */ + /* package */ static void readUnigramsAndBigramsBinary(final DictDecoder dictDecoder, + final Map<Integer, String> words, final Map<Integer, Integer> frequencies, + final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException, + UnsupportedFormatException { + // Read header + final DictionaryHeader header = dictDecoder.readHeader(); + readUnigramsAndBigramsBinaryInner(dictDecoder, header.mBodyOffset, words, + frequencies, bigrams); + } + + /** + * Gets the address of the last PtNode of the exact matching word in the dictionary. + * If no match is found, returns NOT_VALID_WORD. + * + * @param dictDecoder the dict decoder. + * @param word the word we search for. + * @return the address of the terminal node. + * @throws IOException if the file can't be read. + * @throws UnsupportedFormatException if the format of the file is not recognized. + */ + @UsedForTesting + /* package */ static int getTerminalPosition(final DictDecoder dictDecoder, + final String word) throws IOException, UnsupportedFormatException { + if (word == null) return FormatSpec.NOT_VALID_WORD; + dictDecoder.setPosition(0); + dictDecoder.readHeader(); + int wordPos = 0; + final int wordLen = word.codePointCount(0, word.length()); + for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { + if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD; + + do { + final int ptNodeCount = dictDecoder.readPtNodeCount(); + boolean foundNextPtNode = false; + for (int i = 0; i < ptNodeCount; ++i) { + final int ptNodePos = dictDecoder.getPosition(); + final PtNodeInfo currentInfo = dictDecoder.readPtNode(ptNodePos); + boolean same = true; + for (int p = 0, j = word.offsetByCodePoints(0, wordPos); + p < currentInfo.mCharacters.length; + ++p, j = word.offsetByCodePoints(j, 1)) { + if (wordPos + p >= wordLen + || word.codePointAt(j) != currentInfo.mCharacters[p]) { + same = false; + break; + } + } + + if (same) { + // found the PtNode matches the word. + if (wordPos + currentInfo.mCharacters.length == wordLen) { + if (!currentInfo.isTerminal()) { + return FormatSpec.NOT_VALID_WORD; + } else { + return ptNodePos; + } + } + wordPos += currentInfo.mCharacters.length; + if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { + return FormatSpec.NOT_VALID_WORD; + } + foundNextPtNode = true; + dictDecoder.setPosition(currentInfo.mChildrenAddress); + break; + } + } + if (foundNextPtNode) break; + return FormatSpec.NOT_VALID_WORD; + } while(true); + } + return FormatSpec.NOT_VALID_WORD; + } + + /** + * Writes a PtNodeCount to the stream. + * + * @param destination the stream to write. + * @param ptNodeCount the count. + * @return the size written in bytes. + */ + @UsedForTesting + static int writePtNodeCount(final OutputStream destination, final int ptNodeCount) + throws IOException { + final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount); + // the count must fit on one byte or two bytes. + // Please see comments in FormatSpec. + if (countSize != 1 && countSize != 2) { + throw new RuntimeException("Strange size from getPtNodeCountSize : " + countSize); + } + final int encodedPtNodeCount = (countSize == 2) ? + (ptNodeCount | FormatSpec.LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG) : ptNodeCount; + BinaryDictEncoderUtils.writeUIntToStream(destination, encodedPtNodeCount, countSize); + return countSize; + } + + /** + * Helper method to hide the actual value of the no children address. + */ + public static boolean hasChildrenAddress(final int address) { + return FormatSpec.NO_CHILDREN_ADDRESS != address; + } + + /** + * Compute the binary size of the node count + * @param count the node count + * @return the size of the node count, either 1 or 2 bytes. + */ + public static int getPtNodeCountSize(final int count) { + if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= count) { + return 1; + } else if (FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY >= count) { + return 2; + } else { + throw new RuntimeException("Can't have more than " + + FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY + " PtNode in a PtNodeArray (found " + + count + ")"); + } + } + + static int getChildrenAddressSize(final int optionFlags) { + switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: + return 1; + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES: + return 2; + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES: + return 3; + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS: + default: + return 0; + } + } + + /** + * Calculate bigram frequency from compressed value + * + * @param unigramFrequency + * @param bigramFrequency compressed frequency + * @return approximate bigram frequency + */ + @UsedForTesting + public static int reconstructBigramFrequency(final int unigramFrequency, + final int bigramFrequency) { + final float stepSize = (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency) + / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY); + final float resultFreqFloat = unigramFrequency + stepSize * (bigramFrequency + 1.0f); + return (int)resultFreqFloat; + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java deleted file mode 100644 index afe5adb73..000000000 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * 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.makedict; - -import android.test.AndroidTestCase; -import android.test.MoreAsserts; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Random; - -@LargeTest -public class BinaryDictIOUtilsTests extends AndroidTestCase { - private static final String TAG = BinaryDictIOUtilsTests.class.getSimpleName(); - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = - new FormatSpec.FormatOptions(3, true); - - private static final ArrayList<String> sWords = CollectionUtils.newArrayList(); - public static final int DEFAULT_MAX_UNIGRAMS = 1500; - private final int mMaxUnigrams; - - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - - private static final int VERSION3 = 3; - private static final int VERSION4 = 4; - - private static final String[] CHARACTERS = { - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", - "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "\u00FC" /* ü */, "\u00E2" /* â */, "\u00F1" /* ñ */, // accented characters - "\u4E9C" /* 亜 */, "\u4F0A" /* 伊 */, "\u5B87" /* 宇 */, // kanji - "\uD841\uDE28" /* 𠘨 */, "\uD840\uDC0B" /* 𠀋 */, "\uD861\uDED7" /* 𨛗 */ // surrogate pair - }; - - public BinaryDictIOUtilsTests() { - // 1500 is the default max unigrams - this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS); - } - - public BinaryDictIOUtilsTests(final long seed, final int maxUnigrams) { - super(); - Log.d(TAG, "Seed for test is " + seed + ", maxUnigrams is " + maxUnigrams); - mMaxUnigrams = maxUnigrams; - final Random random = new Random(seed); - sWords.clear(); - for (int i = 0; i < maxUnigrams; ++i) { - sWords.add(generateWord(random.nextInt())); - } - } - - // Utilities for test - private String generateWord(final int value) { - final int lengthOfChars = CHARACTERS.length; - StringBuilder builder = new StringBuilder(""); - long lvalue = Math.abs((long)value); - while (lvalue > 0) { - builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]); - lvalue /= lengthOfChars; - } - if (builder.toString().equals("")) return "a"; - return builder.toString(); - } - - private static void printPtNode(final PtNodeInfo info) { - Log.d(TAG, " PtNode at " + info.mOriginalAddress); - Log.d(TAG, " flags = " + info.mFlags); - Log.d(TAG, " parentAddress = " + info.mParentAddress); - Log.d(TAG, " characters = " + new String(info.mCharacters, 0, - info.mCharacters.length)); - if (info.mFrequency != -1) Log.d(TAG, " frequency = " + info.mFrequency); - if (info.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { - Log.d(TAG, " children address = no children address"); - } else { - Log.d(TAG, " children address = " + info.mChildrenAddress); - } - if (info.mShortcutTargets != null) { - for (final WeightedString ws : info.mShortcutTargets) { - Log.d(TAG, " shortcuts = " + ws.mWord); - } - } - if (info.mBigrams != null) { - for (final PendingAttribute attr : info.mBigrams) { - Log.d(TAG, " bigram = " + attr.mAddress); - } - } - Log.d(TAG, " end address = " + info.mEndAddress); - } - - private static void printNode(final Ver3DictDecoder dictDecoder, - final FormatSpec.FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); - Log.d(TAG, "Node at " + dictBuffer.position()); - final int count = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer); - Log.d(TAG, " ptNodeCount = " + count); - for (int i = 0; i < count; ++i) { - final PtNodeInfo currentInfo = dictDecoder.readPtNode(dictBuffer.position(), - formatOptions); - printPtNode(currentInfo); - } - if (formatOptions.mSupportsDynamicUpdate) { - final int forwardLinkAddress = dictBuffer.readUnsignedInt24(); - Log.d(TAG, " forwardLinkAddress = " + forwardLinkAddress); - } - } - - @SuppressWarnings("unused") - private static void printBinaryFile(final Ver3DictDecoder dictDecoder) - throws IOException, UnsupportedFormatException { - final FileHeader fileHeader = dictDecoder.readHeader(); - final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); - while (dictBuffer.position() < dictBuffer.limit()) { - printNode(dictDecoder, fileHeader.mFormatOptions); - } - } - - private int getWordPosition(final File file, final String word) { - int position = FormatSpec.NOT_VALID_WORD; - - try { - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file, - DictDecoder.USE_READONLY_BYTEBUFFER); - position = dictDecoder.getTerminalPosition(word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - return position; - } - - /** - * Find a word using the DictDecoder. - * - * @param dictDecoder the dict decoder - * @param word the word searched - * @return the found ptNodeInfo - * @throws IOException - * @throws UnsupportedFormatException - */ - private static PtNodeInfo findWordByBinaryDictReader(final DictDecoder dictDecoder, - final String word) throws IOException, UnsupportedFormatException { - int position = dictDecoder.getTerminalPosition(word); - if (position != FormatSpec.NOT_VALID_WORD) { - dictDecoder.setPosition(0); - final FileHeader header = dictDecoder.readHeader(); - dictDecoder.setPosition(position); - return dictDecoder.readPtNode(position, header.mFormatOptions); - } - return null; - } - - private PtNodeInfo findWordFromFile(final File file, final String word) { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file); - PtNodeInfo info = null; - try { - dictDecoder.openDictBuffer(); - info = findWordByBinaryDictReader(dictDecoder, word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - return info; - } - - // return amount of time to insert a word - private long insertAndCheckWord(final File file, final String word, final int frequency, - final boolean exist, final ArrayList<WeightedString> bigrams, - final ArrayList<WeightedString> shortcuts, final int formatVersion) { - long amountOfTime = -1; - try { - final DictUpdater dictUpdater; - if (formatVersion == VERSION3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatVersion + " doesn't" - + " exist."); - } - - if (!exist) { - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } - final long now = System.nanoTime(); - dictUpdater.insertWord(word, frequency, bigrams, shortcuts, false, false); - amountOfTime = System.nanoTime() - now; - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } catch (IOException e) { - Log.e(TAG, "Raised an IOException while inserting a word", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Raised an UnsupportedFormatException error while inserting a word", e); - } - return amountOfTime; - } - - private void deleteWord(final File file, final String word, final int formatVersion) { - try { - final DictUpdater dictUpdater; - if (formatVersion == VERSION3) { - dictUpdater = new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else { - throw new RuntimeException("DictUpdater for version " + formatVersion + " doesn't" - + " exist."); - } - dictUpdater.deleteWord(word); - } catch (IOException e) { - } catch (UnsupportedFormatException e) { - } - } - - private void checkReverseLookup(final File file, final String word, final int position) { - - try { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file); - final FileHeader fileHeader = dictDecoder.readHeader(); - assertEquals(word, - BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize, - position, fileHeader.mFormatOptions).mWord); - } catch (IOException e) { - Log.e(TAG, "Raised an IOException while looking up a word", e); - } catch (UnsupportedFormatException e) { - Log.e(TAG, "Raised an UnsupportedFormatException error while looking up a word", e); - } - } - - private void runTestInsertWord(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testInsertWord", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - fail("IOException while creating temporary file: " + e); - } - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); - dict.add("abcd", 10, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - fail("IOException while writing an initial dictionary : " + e); - } catch (UnsupportedFormatException e) { - fail("UnsupportedFormatException while writing an initial dictionary : " + e); - } - - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "abcd")); - insertAndCheckWord(file, "abcde", 10, false, null, null, formatVersion); - - insertAndCheckWord(file, "abcdefghijklmn", 10, false, null, null, formatVersion); - checkReverseLookup(file, "abcdefghijklmn", getWordPosition(file, "abcdefghijklmn")); - - insertAndCheckWord(file, "abcdabcd", 10, false, null, null, formatVersion); - checkReverseLookup(file, "abcdabcd", getWordPosition(file, "abcdabcd")); - - // update the existing word. - insertAndCheckWord(file, "abcdabcd", 15, true, null, null, formatVersion); - - // split 1 - insertAndCheckWord(file, "ab", 20, false, null, null, formatVersion); - - // split 2 - insertAndCheckWord(file, "ami", 30, false, null, null, formatVersion); - - deleteWord(file, "ami", formatVersion); - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "ami")); - - insertAndCheckWord(file, "abcdabfg", 30, false, null, null, formatVersion); - - deleteWord(file, "abcd", formatVersion); - assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, "abcd")); - } - - public void testInsertWord() { - runTestInsertWord(VERSION3); - } - - private void runTestInsertWordWithBigrams(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testInsertWordWithBigrams", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - fail("IOException while creating temporary file: " + e); - } - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); - dict.add("abcd", 10, null, false); - dict.add("efgh", 15, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - fail("IOException while writing an initial dictionary : " + e); - } catch (UnsupportedFormatException e) { - fail("UnsupportedFormatException while writing an initial dictionary : " + e); - } - - final ArrayList<WeightedString> banana = new ArrayList<WeightedString>(); - banana.add(new WeightedString("banana", 10)); - - insertAndCheckWord(file, "banana", 0, false, null, null, formatVersion); - insertAndCheckWord(file, "recursive", 60, true, banana, null, formatVersion); - - final PtNodeInfo info = findWordFromFile(file, "recursive"); - int bananaPos = getWordPosition(file, "banana"); - assertNotNull(info.mBigrams); - assertEquals(info.mBigrams.size(), 1); - assertEquals(info.mBigrams.get(0).mAddress, bananaPos); - } - - public void testInsertWordWithBigrams() { - runTestInsertWordWithBigrams(VERSION3); - } - - private void runTestRandomWords(final int formatVersion) { - File file = null; - try { - file = File.createTempFile("testRandomWord", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - } - assertNotNull(file); - - // set an initial dictionary. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false, - false)); - dict.add("initial", 10, null, false); - - try { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - dictEncoder.writeDictionary(dict, FORMAT_OPTIONS); - } catch (IOException e) { - assertTrue(false); - } catch (UnsupportedFormatException e) { - assertTrue(false); - } - - long maxTimeToInsert = 0, sum = 0; - long minTimeToInsert = 100000000; // 1000000000 is an upper bound for minTimeToInsert. - int cnt = 0; - for (final String word : sWords) { - final long diff = insertAndCheckWord(file, word, - cnt % FormatSpec.MAX_TERMINAL_FREQUENCY, false, null, null, formatVersion); - maxTimeToInsert = Math.max(maxTimeToInsert, diff); - minTimeToInsert = Math.min(minTimeToInsert, diff); - sum += diff; - cnt++; - } - cnt = 0; - for (final String word : sWords) { - MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word)); - } - - Log.d(TAG, "Test version " + formatVersion); - Log.d(TAG, "max = " + ((double)maxTimeToInsert/1000000) + " ms."); - Log.d(TAG, "min = " + ((double)minTimeToInsert/1000000) + " ms."); - Log.d(TAG, "avg = " + ((double)sum/mMaxUnigrams/1000000) + " ms."); - } - - public void testRandomWords() { - runTestRandomWords(VERSION3); - } -} diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java new file mode 100644 index 000000000..5a3eba801 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; + +import java.io.File; +import java.util.HashMap; + +public class BinaryDictUtils { + public static final int USE_BYTE_ARRAY = 1; + public static final int USE_BYTE_BUFFER = 2; + + public static final String TEST_DICT_FILE_EXTENSION = ".testDict"; + + public static final FormatSpec.FormatOptions VERSION2_OPTIONS = + new FormatSpec.FormatOptions(FormatSpec.VERSION2); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITHOUT_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, false /* hasTimestamp */); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITH_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, true /* hasTimestamp */); + + public static DictionaryOptions makeDictionaryOptions(final String id, final String version, + final FormatSpec.FormatOptions formatOptions) { + final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>()); + options.mAttributes.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, "en_US"); + options.mAttributes.put(DictionaryHeader.DICTIONARY_ID_KEY, id); + options.mAttributes.put(DictionaryHeader.DICTIONARY_VERSION_KEY, version); + if (formatOptions.mHasTimestamp) { + options.mAttributes.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + options.mAttributes.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + } + return options; + } + + public static File getDictFile(final String name, final String version, + final FormatOptions formatOptions, final File directory) { + if (formatOptions.mVersion == FormatSpec.VERSION2) { + return new File(directory, name + "." + version + TEST_DICT_FILE_EXTENSION); + } else if (formatOptions.mVersion == FormatSpec.VERSION4) { + return new File(directory, name + "." + version); + } else { + throw new RuntimeException("the format option has a wrong version : " + + formatOptions.mVersion); + } + } + + public static DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) { + if (formatOptions.mVersion == FormatSpec.VERSION4) { + if (!file.isDirectory()) { + file.mkdir(); + } + return new Ver4DictEncoder(file); + } else if (formatOptions.mVersion == FormatSpec.VERSION2) { + return new Ver2DictEncoder(file); + } else { + throw new RuntimeException("The format option has a wrong version : " + + formatOptions.mVersion); + } + } +} diff --git a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/DictDecoder.java index 3dbeee099..a3b28a702 100644 --- a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java +++ b/tests/src/com/android/inputmethod/latin/makedict/DictDecoder.java @@ -18,8 +18,6 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; import java.io.File; @@ -35,37 +33,34 @@ import java.util.TreeMap; /** * An interface of binary dictionary decoders. */ +// TODO: Straighten out responsibility for the buffer's file pointer. public interface DictDecoder { /** * Reads and returns the file header. */ - public FileHeader readHeader() throws IOException, UnsupportedFormatException; + public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException; /** - * Reads PtNode from nodeAddress. + * Reads PtNode from ptNodePos. * @param ptNodePos the position of PtNode. - * @param formatOptions the format options. * @return PtNodeInfo. */ - public PtNodeInfo readPtNode(final int ptNodePos, final FormatOptions formatOptions); + public PtNodeInfo readPtNode(final int ptNodePos); /** * Reads a buffer and returns the memory representation of the dictionary. * * This high-level method takes a buffer and reads its contents, populating a - * FusionDictionary structure. The optional dict argument is an existing dictionary to - * which words from the buffer should be added. If it is null, a new dictionary is created. + * FusionDictionary structure. * - * @param dict an optional dictionary to add words to, or null. * @param deleteDictIfBroken a flag indicating whether this method should remove the broken * dictionary or not. - * @return the created (or merged) dictionary. + * @return the created dictionary. */ @UsedForTesting - public FusionDictionary readDictionaryBinary(final FusionDictionary dict, - final boolean deleteDictIfBroken) - throws FileNotFoundException, IOException, UnsupportedFormatException; + public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) + throws FileNotFoundException, IOException, UnsupportedFormatException; /** * Gets the address of the last PtNode of the exact matching word in the dictionary. @@ -116,18 +111,11 @@ public interface DictDecoder { public int readPtNodeCount(); /** - * Reads the forward link and advances the position. - * - * @return true if this method moves the file pointer, false otherwise. - */ - public boolean readAndFollowForwardLink(); - public boolean hasNextPtNodeArray(); - - /** * Opens the dictionary file and makes DictBuffer. */ @UsedForTesting - public void openDictBuffer() throws FileNotFoundException, IOException; + public void openDictBuffer() throws FileNotFoundException, IOException, + UnsupportedFormatException; @UsedForTesting public boolean isDictBufferOpen(); @@ -227,5 +215,8 @@ public interface DictDecoder { } } - public void skipPtNode(final FormatOptions formatOptions); + /** + * @return whether this decoder has a valid binary dictionary that it can decode. + */ + public boolean hasValidRawBinaryDictionary(); } diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/DictEncoder.java index ea5d492d8..678c5ca6b 100644 --- a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java +++ b/tests/src/com/android/inputmethod/latin/makedict/DictEncoder.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; @@ -25,6 +26,7 @@ import java.io.IOException; * An interface of binary dictionary encoder. */ public interface DictEncoder { + @UsedForTesting public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) throws IOException, UnsupportedFormatException; @@ -32,7 +34,5 @@ public interface DictEncoder { public int getPosition(); public void writePtNodeCount(final int ptNodeCount); public void writeForwardLinkAddress(final int forwardLinkAddress); - - public void writePtNode(final PtNode ptNode, final int parentPosition, - final FormatOptions formatOptions, final FusionDictionary dict); + public void writePtNode(final PtNode ptNode, final FusionDictionary dict); } diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 3bb218bea..f60b3af4f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -18,12 +18,11 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Date; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -31,7 +30,7 @@ import java.util.LinkedList; * A dictionary that can fusion heads and tails of words for more compression. */ @UsedForTesting -public final class FusionDictionary implements Iterable<Word> { +public final class FusionDictionary implements Iterable<WordProperty> { private static final boolean DBG = MakedictLog.DBG; private static int CHARACTER_NOT_FOUND_INDEX = -1; @@ -61,56 +60,32 @@ public final class FusionDictionary implements Iterable<Word> { mData = new ArrayList<PtNode>(); } public PtNodeArray(ArrayList<PtNode> data) { + Collections.sort(data, PTNODE_COMPARATOR); mData = data; } } /** - * A string with a frequency. - * - * This represents an "attribute", that is either a bigram or a shortcut. - */ - public static final class WeightedString { - public final String mWord; - public int mFrequency; - public WeightedString(String word, int frequency) { - mWord = word; - mFrequency = frequency; - } - - @Override - public int hashCode() { - return Arrays.hashCode(new Object[] { mWord, mFrequency }); - } - - @Override - public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof WeightedString)) return false; - WeightedString w = (WeightedString)o; - return mWord.equals(w.mWord) && mFrequency == w.mFrequency; - } - } - - /** - * PtNode is a group of characters, with a frequency, shortcut targets, bigrams, and children - * (Pt means Patricia Trie). + * PtNode is a group of characters, with probability information, shortcut targets, bigrams, + * and children (Pt means Patricia Trie). * * This is the central class of the in-memory representation. A PtNode is what can * be seen as a traditional "trie node", except it can hold several characters at the * same time. A PtNode essentially represents one or several characters in the middle * of the trie tree; as such, it can be a terminal, and it can have children. * In this in-memory representation, whether the PtNode is a terminal or not is represented - * in the frequency, where NOT_A_TERMINAL (= -1) means this is not a terminal and any other - * value is the frequency of this terminal. A terminal may have non-null shortcuts and/or - * bigrams, but a non-terminal may not. Moreover, children, if present, are null. + * by mProbabilityInfo. The PtNode is a terminal when the mProbabilityInfo is not null and the + * PtNode is not a terminal when the mProbabilityInfo is null. A terminal may have non-null + * shortcuts and/or bigrams, but a non-terminal may not. Moreover, children, if present, + * are non-null. */ public static final class PtNode { - public static final int NOT_A_TERMINAL = -1; + private static final int NOT_A_TERMINAL = -1; final int mChars[]; ArrayList<WeightedString> mShortcutTargets; ArrayList<WeightedString> mBigrams; - int mFrequency; // NOT_A_TERMINAL == mFrequency indicates this is not a terminal. + // null == mProbabilityInfo indicates this is not a terminal. + ProbabilityInfo mProbabilityInfo; int mTerminalId; // NOT_A_TERMINAL == mTerminalId indicates this is not a terminal. PtNodeArray mChildren; boolean mIsNotAWord; // Only a shortcut @@ -126,11 +101,11 @@ public final class FusionDictionary implements Iterable<Word> { int mCachedAddressAfterUpdate; // The address of this PtNode (after update) public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets, - final ArrayList<WeightedString> bigrams, final int frequency, + final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo, final boolean isNotAWord, final boolean isBlacklistEntry) { mChars = chars; - mFrequency = frequency; - mTerminalId = frequency; + mProbabilityInfo = probabilityInfo; + mTerminalId = probabilityInfo == null ? NOT_A_TERMINAL : probabilityInfo.mProbability; mShortcutTargets = shortcutTargets; mBigrams = bigrams; mChildren = null; @@ -139,11 +114,11 @@ public final class FusionDictionary implements Iterable<Word> { } public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets, - final ArrayList<WeightedString> bigrams, final int frequency, + final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo, final boolean isNotAWord, final boolean isBlacklistEntry, final PtNodeArray children) { mChars = chars; - mFrequency = frequency; + mProbabilityInfo = probabilityInfo; mShortcutTargets = shortcutTargets; mBigrams = bigrams; mChildren = children; @@ -163,11 +138,15 @@ public final class FusionDictionary implements Iterable<Word> { } public boolean isTerminal() { - return NOT_A_TERMINAL != mFrequency; + return mProbabilityInfo != null; } - public int getFrequency() { - return mFrequency; + public int getProbability() { + if (isTerminal()) { + return mProbabilityInfo.mProbability; + } else { + return NOT_A_TERMINAL; + } } public boolean getIsNotAWord() { @@ -199,18 +178,18 @@ public final class FusionDictionary implements Iterable<Word> { } /** - * Adds a word to the bigram list. Updates the frequency if the word already + * Adds a word to the bigram list. Updates the probability information if the word already * exists. */ - public void addBigram(final String word, final int frequency) { + public void addBigram(final String word, final ProbabilityInfo probabilityInfo) { if (mBigrams == null) { mBigrams = new ArrayList<WeightedString>(); } WeightedString bigram = getBigram(word); if (bigram != null) { - bigram.mFrequency = frequency; + bigram.mProbabilityInfo = probabilityInfo; } else { - bigram = new WeightedString(word, frequency); + bigram = new WeightedString(word, probabilityInfo); mBigrams.add(bigram); } } @@ -256,12 +235,11 @@ public final class FusionDictionary implements Iterable<Word> { * the existing ones if any. Note: unigram, bigram, and shortcut frequencies are only * updated if they are higher than the existing ones. */ - public void update(final int frequency, final ArrayList<WeightedString> shortcutTargets, + private void update(final ProbabilityInfo probabilityInfo, + final ArrayList<WeightedString> shortcutTargets, final ArrayList<WeightedString> bigrams, final boolean isNotAWord, final boolean isBlacklistEntry) { - if (frequency > mFrequency) { - mFrequency = frequency; - } + mProbabilityInfo = ProbabilityInfo.max(mProbabilityInfo, probabilityInfo); if (shortcutTargets != null) { if (mShortcutTargets == null) { mShortcutTargets = shortcutTargets; @@ -272,8 +250,9 @@ public final class FusionDictionary implements Iterable<Word> { final WeightedString existingShortcut = getShortcut(shortcut.mWord); if (existingShortcut == null) { mShortcutTargets.add(shortcut); - } else if (existingShortcut.mFrequency < shortcut.mFrequency) { - existingShortcut.mFrequency = shortcut.mFrequency; + } else { + existingShortcut.mProbabilityInfo = ProbabilityInfo.max( + existingShortcut.mProbabilityInfo, shortcut.mProbabilityInfo); } } } @@ -288,8 +267,9 @@ public final class FusionDictionary implements Iterable<Word> { final WeightedString existingBigram = getBigram(bigram.mWord); if (existingBigram == null) { mBigrams.add(bigram); - } else if (existingBigram.mFrequency < bigram.mFrequency) { - existingBigram.mFrequency = bigram.mFrequency; + } else { + existingBigram.mProbabilityInfo = ProbabilityInfo.max( + existingBigram.mProbabilityInfo, bigram.mProbabilityInfo); } } } @@ -299,58 +279,6 @@ public final class FusionDictionary implements Iterable<Word> { } } - /** - * Options global to the dictionary. - */ - public static final class DictionaryOptions { - public final boolean mGermanUmlautProcessing; - public final boolean mFrenchLigatureProcessing; - public final HashMap<String, String> mAttributes; - public DictionaryOptions(final HashMap<String, String> attributes, - final boolean germanUmlautProcessing, final boolean frenchLigatureProcessing) { - mAttributes = attributes; - mGermanUmlautProcessing = germanUmlautProcessing; - mFrenchLigatureProcessing = frenchLigatureProcessing; - } - @Override - public String toString() { // Convenience method - return toString(0, false); - } - public String toString(final int indentCount, final boolean plumbing) { - final StringBuilder indent = new StringBuilder(); - if (plumbing) { - indent.append("H:"); - } else { - for (int i = 0; i < indentCount; ++i) { - indent.append(" "); - } - } - final StringBuilder s = new StringBuilder(); - for (final String optionKey : mAttributes.keySet()) { - s.append(indent); - s.append(optionKey); - s.append(" = "); - if ("date".equals(optionKey) && !plumbing) { - // Date needs a number of milliseconds, but the dictionary contains seconds - s.append(new Date( - 1000 * Long.parseLong(mAttributes.get(optionKey))).toString()); - } else { - s.append(mAttributes.get(optionKey)); - } - s.append("\n"); - } - if (mGermanUmlautProcessing) { - s.append(indent); - s.append("Needs German umlaut processing\n"); - } - if (mFrenchLigatureProcessing) { - s.append(indent); - s.append("Needs French ligature processing\n"); - } - return s.toString(); - } - } - public final DictionaryOptions mOptions; public final PtNodeArray mRootNodeArray; @@ -392,13 +320,13 @@ public final class FusionDictionary implements Iterable<Word> { * they will be added to the dictionary as necessary. * * @param word the word to add. - * @param frequency the frequency of the word, in the range [0..255]. + * @param probabilityInfo probability information of the word. * @param shortcutTargets a list of shortcut targets for this word, or null. * @param isNotAWord true if this should not be considered a word (e.g. shortcut only) */ - public void add(final String word, final int frequency, + public void add(final String word, final ProbabilityInfo probabilityInfo, final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord) { - add(getCodePoints(word), frequency, shortcutTargets, isNotAWord, + add(getCodePoints(word), probabilityInfo, shortcutTargets, isNotAWord, false /* isBlacklistEntry */); } @@ -411,7 +339,8 @@ public final class FusionDictionary implements Iterable<Word> { */ public void addBlacklistEntry(final String word, final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord) { - add(getCodePoints(word), 0, shortcutTargets, isNotAWord, true /* isBlacklistEntry */); + add(getCodePoints(word), new ProbabilityInfo(0), shortcutTargets, isNotAWord, + true /* isBlacklistEntry */); } /** @@ -435,25 +364,26 @@ public final class FusionDictionary implements Iterable<Word> { /** * Helper method to add a new bigram to the dictionary. * - * @param word1 the previous word of the context - * @param word2 the next word of the context - * @param frequency the bigram frequency + * @param word0 the previous word of the context + * @param word1 the next word of the context + * @param probabilityInfo the bigram probability info */ - public void setBigram(final String word1, final String word2, final int frequency) { - PtNode ptNode = findWordInTree(mRootNodeArray, word1); - if (ptNode != null) { - final PtNode ptNode2 = findWordInTree(mRootNodeArray, word2); - if (ptNode2 == null) { - add(getCodePoints(word2), 0, null, false /* isNotAWord */, + public void setBigram(final String word0, final String word1, + final ProbabilityInfo probabilityInfo) { + PtNode ptNode0 = findWordInTree(mRootNodeArray, word0); + if (ptNode0 != null) { + final PtNode ptNode1 = findWordInTree(mRootNodeArray, word1); + if (ptNode1 == null) { + add(getCodePoints(word1), new ProbabilityInfo(0), null, false /* isNotAWord */, false /* isBlacklistEntry */); // The PtNode for the first word may have moved by the above insertion, // if word1 and word2 share a common stem that happens not to have been // a cutting point until now. In this case, we need to refresh ptNode. - ptNode = findWordInTree(mRootNodeArray, word1); + ptNode0 = findWordInTree(mRootNodeArray, word0); } - ptNode.addBigram(word2, frequency); + ptNode0.addBigram(word1, probabilityInfo); } else { - throw new RuntimeException("First word of bigram not found"); + throw new RuntimeException("First word of bigram not found " + word0); } } @@ -464,15 +394,15 @@ public final class FusionDictionary implements Iterable<Word> { * 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 probabilityInfo the probability information of the word. * @param shortcutTargets an optional list of shortcut targets for this word (null if none). * @param isNotAWord true if this is not a word for spellcheking purposes (shortcut only or so) * @param isBlacklistEntry true if this is a blacklisted word, false otherwise */ - private void add(final int[] word, final int frequency, + private void add(final int[] word, final ProbabilityInfo probabilityInfo, final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord, final boolean isBlacklistEntry) { - assert(frequency >= 0 && frequency <= 255); + assert(probabilityInfo.mProbability <= FormatSpec.MAX_TERMINAL_FREQUENCY); if (word.length >= Constants.DICTIONARY_MAX_WORD_LENGTH) { MakedictLog.w("Ignoring a word that is too long: word.length = " + word.length); return; @@ -500,7 +430,8 @@ public final class FusionDictionary implements Iterable<Word> { // No node at this point to accept the word. Create one. final int insertionIndex = findInsertionIndex(currentNodeArray, word[charIndex]); final PtNode newPtNode = new PtNode(Arrays.copyOfRange(word, charIndex, word.length), - shortcutTargets, null /* bigrams */, frequency, isNotAWord, isBlacklistEntry); + shortcutTargets, null /* bigrams */, probabilityInfo, isNotAWord, + isBlacklistEntry); currentNodeArray.mData.add(insertionIndex, newPtNode); if (DBG) checkStack(currentNodeArray); } else { @@ -510,15 +441,15 @@ public final class FusionDictionary implements Iterable<Word> { // The new word is a prefix of an existing word, but the node on which it // should end already exists as is. Since the old PtNode was not a terminal, // make it one by filling in its frequency and other attributes - currentPtNode.update(frequency, shortcutTargets, null, isNotAWord, + currentPtNode.update(probabilityInfo, shortcutTargets, null, isNotAWord, isBlacklistEntry); } else { // The new word matches the full old word and extends past it. // We only have to create a new node and add it to the end of this. final PtNode newNode = new PtNode( Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length), - shortcutTargets, null /* bigrams */, frequency, isNotAWord, - isBlacklistEntry); + shortcutTargets, null /* bigrams */, probabilityInfo, + isNotAWord, isBlacklistEntry); currentPtNode.mChildren = new PtNodeArray(); currentPtNode.mChildren.mData.add(newNode); } @@ -526,7 +457,7 @@ public final class FusionDictionary implements Iterable<Word> { if (0 == differentCharIndex) { // Exact same word. Update the frequency if higher. This will also add the // new shortcuts to the existing shortcut list if it already exists. - currentPtNode.update(frequency, shortcutTargets, null, + currentPtNode.update(probabilityInfo, shortcutTargets, null, currentPtNode.mIsNotAWord && isNotAWord, currentPtNode.mIsBlacklistEntry || isBlacklistEntry); } else { @@ -536,7 +467,7 @@ public final class FusionDictionary implements Iterable<Word> { final PtNode newOldWord = new PtNode( Arrays.copyOfRange(currentPtNode.mChars, differentCharIndex, currentPtNode.mChars.length), currentPtNode.mShortcutTargets, - currentPtNode.mBigrams, currentPtNode.mFrequency, + currentPtNode.mBigrams, currentPtNode.mProbabilityInfo, currentPtNode.mIsNotAWord, currentPtNode.mIsBlacklistEntry, currentPtNode.mChildren); newChildren.mData.add(newOldWord); @@ -545,16 +476,17 @@ public final class FusionDictionary implements Iterable<Word> { if (charIndex + differentCharIndex >= word.length) { newParent = new PtNode( Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex), - shortcutTargets, null /* bigrams */, frequency, + shortcutTargets, null /* bigrams */, probabilityInfo, isNotAWord, isBlacklistEntry, newChildren); } else { newParent = new PtNode( Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex), - null /* shortcutTargets */, null /* bigrams */, -1, - false /* isNotAWord */, false /* isBlacklistEntry */, newChildren); + null /* shortcutTargets */, null /* bigrams */, + null /* probabilityInfo */, false /* isNotAWord */, + false /* isBlacklistEntry */, newChildren); final PtNode newWord = new PtNode(Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length), - shortcutTargets, null /* bigrams */, frequency, + shortcutTargets, null /* bigrams */, probabilityInfo, isNotAWord, isBlacklistEntry); final int addIndex = word[charIndex + differentCharIndex] > currentPtNode.mChars[differentCharIndex] ? 1 : 0; @@ -616,8 +548,8 @@ public final class FusionDictionary implements Iterable<Word> { private static int findInsertionIndex(final PtNodeArray nodeArray, int character) { final ArrayList<PtNode> data = nodeArray.mData; final PtNode reference = new PtNode(new int[] { character }, - null /* shortcutTargets */, null /* bigrams */, 0, false /* isNotAWord */, - false /* isBlacklistEntry */); + null /* shortcutTargets */, null /* bigrams */, null /* probabilityInfo */, + false /* isNotAWord */, false /* isBlacklistEntry */); int result = Collections.binarySearch(data, reference, PTNODE_COMPARATOR); return result >= 0 ? result : -result - 1; } @@ -701,143 +633,11 @@ public final class FusionDictionary implements Iterable<Word> { } /** - * Recursively count the number of nodes in a given branch of the trie. - * - * @param nodeArray the node array to count. - * @return the number of nodes in this branch. - */ - public static int countNodeArrays(final PtNodeArray nodeArray) { - int size = 1; - for (int i = nodeArray.mData.size() - 1; i >= 0; --i) { - PtNode ptNode = nodeArray.mData.get(i); - if (null != ptNode.mChildren) - size += countNodeArrays(ptNode.mChildren); - } - return size; - } - - // Recursively find out whether there are any bigrams. - // This can be pretty expensive especially if there aren't any (we return as soon - // as we find one, so it's much cheaper if there are bigrams) - private static boolean hasBigramsInternal(final PtNodeArray nodeArray) { - if (null == nodeArray) return false; - for (int i = nodeArray.mData.size() - 1; i >= 0; --i) { - PtNode ptNode = nodeArray.mData.get(i); - if (null != ptNode.mBigrams) return true; - if (hasBigramsInternal(ptNode.mChildren)) return true; - } - return false; - } - - /** - * Finds out whether there are any bigrams in this dictionary. - * - * @return true if there is any bigram, false otherwise. - */ - // TODO: this is expensive especially for large dictionaries without any bigram. - // The up side is, this is always accurate and correct and uses no memory. We should - // find a more efficient way of doing this, without compromising too much on memory - // and ease of use. - public boolean hasBigrams() { - return hasBigramsInternal(mRootNodeArray); - } - - // Historically, the tails of the words were going to be merged to save space. - // However, that would prevent the code to search for a specific address in log(n) - // time so this was abandoned. - // The code is still of interest as it does add some compression to any dictionary - // that has no need for attributes. Implementations that does not read attributes should be - // able to read a dictionary with merged tails. - // Also, the following code does support frequencies, as in, it will only merges - // tails that share the same frequency. Though it would result in the above loss of - // performance while searching by address, it is still technically possible to merge - // tails that contain attributes, but this code does not take that into account - it does - // not compare attributes and will merge terminals with different attributes regardless. - public void mergeTails() { - MakedictLog.i("Do not merge tails"); - return; - -// MakedictLog.i("Merging PtNodes. Number of PtNodes : " + countPtNodes(root)); -// MakedictLog.i("Number of PtNodes : " + countPtNodes(root)); -// -// final HashMap<String, ArrayList<PtNodeArray>> repository = -// new HashMap<String, ArrayList<PtNodeArray>>(); -// mergeTailsInner(repository, root); -// -// MakedictLog.i("Number of different pseudohashes : " + repository.size()); -// int size = 0; -// for (ArrayList<PtNodeArray> a : repository.values()) { -// size += a.size(); -// } -// MakedictLog.i("Number of nodes after merge : " + (1 + size)); -// MakedictLog.i("Recursively seen nodes : " + countNodes(root)); - } - - // The following methods are used by the deactivated mergeTails() -// private static boolean isEqual(PtNodeArray a, PtNodeArray b) { -// if (null == a && null == b) return true; -// if (null == a || null == b) return false; -// if (a.data.size() != b.data.size()) return false; -// final int size = a.data.size(); -// for (int i = size - 1; i >= 0; --i) { -// PtNode aPtNode = a.data.get(i); -// PtNode bPtNode = b.data.get(i); -// if (aPtNode.frequency != bPtNode.frequency) return false; -// if (aPtNode.alternates == null && bPtNode.alternates != null) return false; -// if (aPtNode.alternates != null && !aPtNode.equals(bPtNode.alternates)) return false; -// if (!Arrays.equals(aPtNode.chars, bPtNode.chars)) return false; -// if (!isEqual(aPtNode.children, bPtNode.children)) return false; -// } -// return true; -// } - -// static private HashMap<String, ArrayList<PtNodeArray>> mergeTailsInner( -// final HashMap<String, ArrayList<PtNodeArray>> map, final PtNodeArray nodeArray) { -// final ArrayList<PtNode> branches = nodeArray.data; -// final int nodeSize = branches.size(); -// for (int i = 0; i < nodeSize; ++i) { -// PtNode ptNode = branches.get(i); -// if (null != ptNode.children) { -// String pseudoHash = getPseudoHash(ptNode.children); -// ArrayList<PtNodeArray> similarList = map.get(pseudoHash); -// if (null == similarList) { -// similarList = new ArrayList<PtNodeArray>(); -// map.put(pseudoHash, similarList); -// } -// boolean merged = false; -// for (PtNodeArray similar : similarList) { -// if (isEqual(ptNode.children, similar)) { -// ptNode.children = similar; -// merged = true; -// break; -// } -// } -// if (!merged) { -// similarList.add(ptNode.children); -// } -// mergeTailsInner(map, ptNode.children); -// } -// } -// return map; -// } - -// private static String getPseudoHash(final PtNodeArray nodeArray) { -// StringBuilder s = new StringBuilder(); -// for (PtNode ptNode : nodeArray.data) { -// s.append(ptNode.frequency); -// for (int ch : ptNode.chars) { -// s.append(Character.toChars(ch)); -// } -// } -// return s.toString(); -// } - - /** * Iterator to walk through a dictionary. * * This is purely for convenience. */ - public static final class DictionaryIterator implements Iterator<Word> { + public static final class DictionaryIterator implements Iterator<WordProperty> { private static final class Position { public Iterator<PtNode> pos; public int length; @@ -867,7 +667,7 @@ public final class FusionDictionary implements Iterable<Word> { } @Override - public Word next() { + public WordProperty next() { Position currentPos = mPositions.getLast(); mCurrentString.setLength(currentPos.length); @@ -883,8 +683,9 @@ public final class FusionDictionary implements Iterable<Word> { currentPos.length = mCurrentString.length(); mPositions.addLast(currentPos); } - if (currentPtNode.mFrequency >= 0) { - return new Word(mCurrentString.toString(), currentPtNode.mFrequency, + if (currentPtNode.isTerminal()) { + return new WordProperty(mCurrentString.toString(), + currentPtNode.mProbabilityInfo, currentPtNode.mShortcutTargets, currentPtNode.mBigrams, currentPtNode.mIsNotAWord, currentPtNode.mIsBlacklistEntry); } @@ -910,7 +711,7 @@ public final class FusionDictionary implements Iterable<Word> { * and say : for (Word w : x) {} */ @Override - public Iterator<Word> iterator() { + public Iterator<WordProperty> iterator() { return new DictionaryIterator(mRootNodeArray.mData); } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/makedict/MakedictLog.java b/tests/src/com/android/inputmethod/latin/makedict/MakedictLog.java index 7eccff2b4..7eccff2b4 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/makedict/MakedictLog.java +++ b/tests/src/com/android/inputmethod/latin/makedict/MakedictLog.java diff --git a/java/src/com/android/inputmethod/latin/makedict/PendingAttribute.java b/tests/src/com/android/inputmethod/latin/makedict/PendingAttribute.java index 70e24cc98..70e24cc98 100644 --- a/java/src/com/android/inputmethod/latin/makedict/PendingAttribute.java +++ b/tests/src/com/android/inputmethod/latin/makedict/PendingAttribute.java diff --git a/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java b/tests/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java index 188de7a0f..862e8c101 100644 --- a/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java +++ b/tests/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java @@ -16,37 +16,36 @@ package com.android.inputmethod.latin.makedict; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - import java.util.ArrayList; /** * Raw PtNode info straight out of a file. This will contain numbers for addresses. */ public final class PtNodeInfo { - public final int mOriginalAddress; public final int mEndAddress; public final int mFlags; public final int[] mCharacters; - public final int mFrequency; + public final ProbabilityInfo mProbabilityInfo; public final int mChildrenAddress; - public final int mParentAddress; public final ArrayList<WeightedString> mShortcutTargets; public final ArrayList<PendingAttribute> mBigrams; public PtNodeInfo(final int originalAddress, final int endAddress, final int flags, - final int[] characters, final int frequency, final int parentAddress, + final int[] characters, final ProbabilityInfo probabilityInfo, final int childrenAddress, final ArrayList<WeightedString> shortcutTargets, final ArrayList<PendingAttribute> bigrams) { mOriginalAddress = originalAddress; mEndAddress = endAddress; mFlags = flags; mCharacters = characters; - mFrequency = frequency; - mParentAddress = parentAddress; + mProbabilityInfo = probabilityInfo; mChildrenAddress = childrenAddress; mShortcutTargets = shortcutTargets; mBigrams = bigrams; } + + public boolean isTerminal() { + return mProbabilityInfo != null; + } } diff --git a/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java b/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java deleted file mode 100644 index aeb8552bd..000000000 --- a/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Random; - -/** - * Unit tests for SparseTable. - */ -@LargeTest -public class SparseTableTests extends AndroidTestCase { - private static final String TAG = SparseTableTests.class.getSimpleName(); - - private final Random mRandom; - private final ArrayList<Integer> mRandomIndex; - - private static final int DEFAULT_SIZE = 10000; - private static final int BLOCK_SIZE = 8; - - public SparseTableTests() { - this(System.currentTimeMillis(), DEFAULT_SIZE); - } - - public SparseTableTests(final long seed, final int tableSize) { - super(); - Log.d(TAG, "Seed for test is " + seed + ", size is " + tableSize); - mRandom = new Random(seed); - mRandomIndex = new ArrayList<Integer>(tableSize); - for (int i = 0; i < tableSize; ++i) { - mRandomIndex.add(SparseTable.NOT_EXIST); - } - } - - public void testSet() { - final SparseTable table = new SparseTable(16, BLOCK_SIZE, 1); - table.set(0, 3, 6); - table.set(0, 8, 16); - for (int i = 0; i < 16; ++i) { - if (i == 3 || i == 8) { - assertEquals(i * 2, table.get(0, i)); - } else { - assertEquals(SparseTable.NOT_EXIST, table.get(0, i)); - } - } - } - - private void generateRandomIndex(final int size, final int prop) { - for (int i = 0; i < size; ++i) { - if (mRandom.nextInt(100) < prop) { - mRandomIndex.set(i, mRandom.nextInt()); - } else { - mRandomIndex.set(i, SparseTable.NOT_EXIST); - } - } - } - - private void runTestRandomSet() { - final SparseTable table = new SparseTable(DEFAULT_SIZE, BLOCK_SIZE, 1); - int elementCount = 0; - for (int i = 0; i < DEFAULT_SIZE; ++i) { - if (mRandomIndex.get(i) != SparseTable.NOT_EXIST) { - table.set(0, i, mRandomIndex.get(i)); - elementCount++; - } - } - - Log.d(TAG, "table size = " + table.getLookupTableSize() + " + " - + table.getContentTableSize()); - Log.d(TAG, "the table has " + elementCount + " elements"); - for (int i = 0; i < DEFAULT_SIZE; ++i) { - assertEquals(table.get(0, i), (int)mRandomIndex.get(i)); - } - - // flush and reload - OutputStream lookupOutStream = null; - OutputStream contentOutStream = null; - try { - final File lookupIndexFile = File.createTempFile("testRandomSet", ".small"); - final File contentFile = File.createTempFile("testRandomSet", ".big"); - lookupOutStream = new FileOutputStream(lookupIndexFile); - contentOutStream = new FileOutputStream(contentFile); - table.write(lookupOutStream, new OutputStream[] { contentOutStream }); - lookupOutStream.flush(); - contentOutStream.flush(); - final SparseTable newTable = SparseTable.readFromFiles(lookupIndexFile, - new File[] { contentFile }, BLOCK_SIZE); - for (int i = 0; i < DEFAULT_SIZE; ++i) { - assertEquals(table.get(0, i), newTable.get(0, i)); - } - } catch (IOException e) { - Log.d(TAG, "IOException while flushing and realoding", e); - } finally { - if (lookupOutStream != null) { - try { - lookupOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream", e); - } - } - if (contentOutStream != null) { - try { - contentOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing contentStream.", e); - } - } - } - } - - public void testRandomSet() { - for (int i = 0; i <= 100; i += 10) { - generateRandomIndex(DEFAULT_SIZE, i); - runTestRandomSet(); - } - } - - public void testMultipleContents() { - final int numOfContents = 5; - generateRandomIndex(DEFAULT_SIZE, 20); - final SparseTable table = new SparseTable(DEFAULT_SIZE, BLOCK_SIZE, numOfContents); - for (int i = 0; i < mRandomIndex.size(); ++i) { - if (mRandomIndex.get(i) != SparseTable.NOT_EXIST) { - for (int j = 0; j < numOfContents; ++j) { - table.set(j, i, mRandomIndex.get(i)); - } - } - } - - OutputStream lookupOutStream = null; - OutputStream[] contentsOutStream = new OutputStream[numOfContents]; - try { - final File lookupIndexFile = File.createTempFile("testMultipleContents", "small"); - lookupOutStream = new FileOutputStream(lookupIndexFile); - final File[] contentFiles = new File[numOfContents]; - for (int i = 0; i < numOfContents; ++i) { - contentFiles[i] = File.createTempFile("testMultipleContents", "big" + i); - contentsOutStream[i] = new FileOutputStream(contentFiles[i]); - } - table.write(lookupOutStream, contentsOutStream); - lookupOutStream.flush(); - for (int i = 0; i < numOfContents; ++i) { - contentsOutStream[i].flush(); - } - final SparseTable newTable = SparseTable.readFromFiles(lookupIndexFile, contentFiles, - BLOCK_SIZE); - for (int i = 0; i < numOfContents; ++i) { - for (int j = 0; j < DEFAULT_SIZE; ++j) { - assertEquals(table.get(i, j), newTable.get(i, j)); - } - } - } catch (IOException e) { - Log.d(TAG, "IOException while flushing and reloading", e); - } finally { - if (lookupOutStream != null) { - try { - lookupOutStream.close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream", e); - } - } - for (int i = 0; i < numOfContents; ++i) { - if (contentsOutStream[i] != null) { - try { - contentsOutStream[i].close(); - } catch (IOException e) { - Log.d(TAG, "IOException while closing the stream.", e); - } - } - } - } - } -} diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java new file mode 100644 index 000000000..7091c119e --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; +import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * An implementation of DictDecoder for version 2 binary dictionary. + */ +// TODO: Separate logics that are used only for testing. +@UsedForTesting +public class Ver2DictDecoder extends AbstractDictDecoder { + private static final String TAG = Ver2DictDecoder.class.getSimpleName(); + + /** + * A utility class for reading a PtNode. + */ + protected static class PtNodeReader { + private static ProbabilityInfo readProbabilityInfo(final DictBuffer dictBuffer) { + // Ver2 dicts don't contain historical information. + return new ProbabilityInfo(dictBuffer.readUnsignedByte()); + } + + protected static int readPtNodeOptionFlags(final DictBuffer dictBuffer) { + return dictBuffer.readUnsignedByte(); + } + + protected static int readChildrenAddress(final DictBuffer dictBuffer, + final int ptNodeFlags) { + switch (ptNodeFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: + return dictBuffer.readUnsignedByte(); + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES: + return dictBuffer.readUnsignedShort(); + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES: + return dictBuffer.readUnsignedInt24(); + case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS: + default: + return FormatSpec.NO_CHILDREN_ADDRESS; + } + } + + // Reads shortcuts and returns the read length. + protected static int readShortcut(final DictBuffer dictBuffer, + final ArrayList<WeightedString> shortcutTargets) { + final int pointerBefore = dictBuffer.position(); + dictBuffer.readUnsignedShort(); // skip the size + while (true) { + final int targetFlags = dictBuffer.readUnsignedByte(); + final String word = CharEncoding.readString(dictBuffer); + shortcutTargets.add(new WeightedString(word, + targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY)); + if (0 == (targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; + } + return dictBuffer.position() - pointerBefore; + } + + protected static int readBigramAddresses(final DictBuffer dictBuffer, + final ArrayList<PendingAttribute> bigrams, final int baseAddress) { + int readLength = 0; + int bigramCount = 0; + while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { + final int bigramFlags = dictBuffer.readUnsignedByte(); + ++readLength; + final int sign = 0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE) + ? 1 : -1; + int bigramAddress = baseAddress + readLength; + switch (bigramFlags & FormatSpec.MASK_BIGRAM_ATTR_ADDRESS_TYPE) { + case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE: + bigramAddress += sign * dictBuffer.readUnsignedByte(); + readLength += 1; + break; + case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES: + bigramAddress += sign * dictBuffer.readUnsignedShort(); + readLength += 2; + break; + case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES: + bigramAddress += sign * dictBuffer.readUnsignedInt24(); + readLength += 3; + break; + default: + throw new RuntimeException("Has bigrams with no address"); + } + bigrams.add(new PendingAttribute( + bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY, + bigramAddress)); + if (0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break; + } + return readLength; + } + } + + protected final File mDictionaryBinaryFile; + protected final long mOffset; + protected final long mLength; + // TODO: Remove mBufferFactory and mDictBuffer from this class members because they are now + // used only for testing. + private final DictionaryBufferFactory mBufferFactory; + protected DictBuffer mDictBuffer; + + @UsedForTesting + /* package */ Ver2DictDecoder(final File file, final long offset, final long length, + final int factoryFlag) { + mDictionaryBinaryFile = file; + mOffset = offset; + mLength = length; + mDictBuffer = null; + if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) { + mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); + } else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) { + mBufferFactory = new DictionaryBufferFromByteArrayFactory(); + } else if ((factoryFlag & MASK_DICTBUFFER) == USE_WRITABLE_BYTEBUFFER) { + mBufferFactory = new DictionaryBufferFromWritableByteBufferFactory(); + } else { + mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory(); + } + } + + /* package */ Ver2DictDecoder(final File file, final long offset, final long length, + final DictionaryBufferFactory factory) { + mDictionaryBinaryFile = file; + mOffset = offset; + mLength = length; + mBufferFactory = factory; + } + + @Override + public void openDictBuffer() throws FileNotFoundException, IOException { + mDictBuffer = mBufferFactory.getDictionaryBuffer(mDictionaryBinaryFile); + } + + @Override + public boolean isDictBufferOpen() { + return mDictBuffer != null; + } + + /* package */ DictBuffer getDictBuffer() { + return mDictBuffer; + } + + @UsedForTesting + /* package */ DictBuffer openAndGetDictBuffer() throws FileNotFoundException, IOException { + openDictBuffer(); + return getDictBuffer(); + } + + @Override + public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictionaryBinaryFile.getAbsolutePath(), mOffset, mLength, + true /* useFullEditDistance */, null /* locale */, "" /* dictType */, + false /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); + if (header == null) { + throw new IOException("Cannot read the dictionary header."); + } + if (header.mFormatOptions.mVersion != FormatSpec.VERSION2) { + throw new UnsupportedFormatException("File header has a wrong version : " + + header.mFormatOptions.mVersion); + } + if (!isDictBufferOpen()) { + openDictBuffer(); + } + // Advance buffer reading position to the head of dictionary body. + setPosition(header.mBodyOffset); + return header; + } + + // TODO: Make this buffer multi thread safe. + private final int[] mCharacterBuffer = new int[FormatSpec.MAX_WORD_LENGTH]; + @Override + public PtNodeInfo readPtNode(final int ptNodePos) { + int addressPointer = ptNodePos; + final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); + addressPointer += FormatSpec.PTNODE_FLAGS_SIZE; + final int characters[]; + if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) { + int index = 0; + int character = CharEncoding.readChar(mDictBuffer); + addressPointer += CharEncoding.getCharSize(character); + while (FormatSpec.INVALID_CHARACTER != character) { + // FusionDictionary is making sure that the length of the word is smaller than + // MAX_WORD_LENGTH. + // So we'll never write past the end of mCharacterBuffer. + mCharacterBuffer[index++] = character; + character = CharEncoding.readChar(mDictBuffer); + addressPointer += CharEncoding.getCharSize(character); + } + characters = Arrays.copyOfRange(mCharacterBuffer, 0, index); + } else { + final int character = CharEncoding.readChar(mDictBuffer); + addressPointer += CharEncoding.getCharSize(character); + characters = new int[] { character }; + } + final ProbabilityInfo probabilityInfo; + if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) { + probabilityInfo = PtNodeReader.readProbabilityInfo(mDictBuffer); + addressPointer += FormatSpec.PTNODE_FREQUENCY_SIZE; + } else { + probabilityInfo = null; + } + int childrenAddress = PtNodeReader.readChildrenAddress(mDictBuffer, flags); + if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { + childrenAddress += addressPointer; + } + addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags); + final ArrayList<WeightedString> shortcutTargets; + if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) { + // readShortcut will add shortcuts to shortcutTargets. + shortcutTargets = new ArrayList<WeightedString>(); + addressPointer += PtNodeReader.readShortcut(mDictBuffer, shortcutTargets); + } else { + shortcutTargets = null; + } + + final ArrayList<PendingAttribute> bigrams; + if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) { + bigrams = new ArrayList<PendingAttribute>(); + addressPointer += PtNodeReader.readBigramAddresses(mDictBuffer, bigrams, + addressPointer); + if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { + throw new RuntimeException("Too many bigrams in a PtNode (" + bigrams.size() + + " but max is " + FormatSpec.MAX_BIGRAMS_IN_A_PTNODE + ")"); + } + } else { + bigrams = null; + } + return new PtNodeInfo(ptNodePos, addressPointer, flags, characters, probabilityInfo, + childrenAddress, shortcutTargets, bigrams); + } + + @Override + public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) + throws FileNotFoundException, IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictionaryBinaryFile.getAbsolutePath(), 0 /* offset */, + mDictionaryBinaryFile.length() /* length */, true /* useFullEditDistance */, + null /* locale */, "" /* dictType */, false /* isUpdatable */); + final DictionaryHeader header = readHeader(); + final FusionDictionary fusionDict = + new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions); + int token = 0; + final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList(); + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + if (wordProperty == null) { + binaryDictionary.close(); + if (deleteDictIfBroken) { + mDictionaryBinaryFile.delete(); + } + return null; + } + wordProperties.add(wordProperty); + token = result.mNextToken; + } while (token != 0); + + // Insert unigrams into the fusion dictionary. + for (final WordProperty wordProperty : wordProperties) { + if (wordProperty.mIsBlacklistEntry) { + fusionDict.addBlacklistEntry(wordProperty.mWord, wordProperty.mShortcutTargets, + wordProperty.mIsNotAWord); + } else { + fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo, + wordProperty.mShortcutTargets, wordProperty.mIsNotAWord); + } + } + // Insert bigrams into the fusion dictionary. + for (final WordProperty wordProperty : wordProperties) { + if (wordProperty.mBigrams == null) { + continue; + } + final String word0 = wordProperty.mWord; + for (final WeightedString bigram : wordProperty.mBigrams) { + fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo); + } + } + binaryDictionary.close(); + return fusionDict; + } + + @Override + public void setPosition(int newPos) { + mDictBuffer.position(newPos); + } + + @Override + public int getPosition() { + return mDictBuffer.position(); + } + + @Override + public int readPtNodeCount() { + return BinaryDictDecoderUtils.readPtNodeCount(mDictBuffer); + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java index 9611599b9..9dc2b1058 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java @@ -32,10 +32,10 @@ import java.io.FileOutputStream; import java.io.IOException; /** - * Unit tests for Ver3DictDecoder + * Unit tests for Ver2DictDecoder */ -public class Ver3DictDecoderTests extends AndroidTestCase { - private static final String TAG = Ver3DictDecoderTests.class.getSimpleName(); +public class Ver2DictDecoderTests extends AndroidTestCase { + private static final String TAG = Ver2DictDecoderTests.class.getSimpleName(); private final byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -68,7 +68,8 @@ public class Ver3DictDecoderTests extends AndroidTestCase { } assertNotNull(testFile); - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, 0, testFile.length(), + factory); try { dictDecoder.openDictBuffer(); } catch (Exception e) { @@ -110,7 +111,8 @@ public class Ver3DictDecoderTests extends AndroidTestCase { Log.e(TAG, "IOException while the creating temporary file", e); } - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, 0, testFile.length(), + factory); // the default return value of getBuffer() must be null. assertNull("the default return value of getBuffer() is not null", diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java index 5da34534e..a286190cb 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java @@ -16,11 +16,11 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; import java.io.File; import java.io.FileNotFoundException; @@ -31,16 +31,18 @@ import java.util.ArrayList; import java.util.Iterator; /** - * An implementation of DictEncoder for version 3 binary dictionary. + * An implementation of DictEncoder for version 2 binary dictionary. */ -public class Ver3DictEncoder implements DictEncoder { +@UsedForTesting +public class Ver2DictEncoder implements DictEncoder { private final File mDictFile; private OutputStream mOutStream; private byte[] mBuffer; private int mPosition; - public Ver3DictEncoder(final File dictFile) { + @UsedForTesting + public Ver2DictEncoder(final File dictFile) { mDictFile = dictFile; mOutStream = null; mBuffer = null; @@ -49,7 +51,8 @@ public class Ver3DictEncoder implements DictEncoder { // This constructor is used only by BinaryDictOffdeviceUtilsTests. // If you want to use this in the production code, you should consider keeping consistency of // the interface of Ver3DictDecoder by using factory. - public Ver3DictEncoder(final OutputStream outStream) { + @UsedForTesting + public Ver2DictEncoder(final OutputStream outStream) { mDictFile = null; mOutStream = outStream; } @@ -68,7 +71,7 @@ public class Ver3DictEncoder implements DictEncoder { @Override public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) throws IOException, UnsupportedFormatException { - if (formatOptions.mVersion > FormatSpec.VERSION3) { + if (formatOptions.mVersion > FormatSpec.VERSION2) { throw new UnsupportedFormatException( "The given format options has wrong version number : " + formatOptions.mVersion); @@ -91,7 +94,7 @@ public class Ver3DictEncoder implements DictEncoder { ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray); MakedictLog.i("Computing addresses..."); - BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions); + BinaryDictEncoderUtils.computeAddresses(dict, flatNodes); MakedictLog.i("Checking PtNode array..."); if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes); @@ -103,7 +106,7 @@ public class Ver3DictEncoder implements DictEncoder { MakedictLog.i("Writing file..."); for (PtNodeArray nodeArray : flatNodes) { - BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions); + BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray); } if (MakedictLog.DBG) BinaryDictEncoderUtils.showStatistics(flatNodes); mOutStream.write(mBuffer, 0, mPosition); @@ -135,24 +138,13 @@ public class Ver3DictEncoder implements DictEncoder { countSize); } - private void writePtNodeFlags(final PtNode ptNode, final FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); + private void writePtNodeFlags(final PtNode ptNode) { + final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode); mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, - BinaryDictEncoderUtils.makePtNodeFlags(ptNode, childrenPos, formatOptions), + BinaryDictEncoderUtils.makePtNodeFlags(ptNode, childrenPos), FormatSpec.PTNODE_FLAGS_SIZE); } - private void writeParentPosition(final int parentPosition, final PtNode ptNode, - final FormatOptions formatOptions) { - if (parentPosition == FormatSpec.NO_PARENT_ADDRESS) { - mPosition = BinaryDictEncoderUtils.writeParentAddress(mBuffer, mPosition, - parentPosition, formatOptions); - } else { - mPosition = BinaryDictEncoderUtils.writeParentAddress(mBuffer, mPosition, - parentPosition - ptNode.mCachedAddressAfterUpdate, formatOptions); - } - } - private void writeCharacters(final int[] codePoints, final boolean hasSeveralChars) { mPosition = CharEncoding.writeCharArray(codePoints, mBuffer, mPosition); if (hasSeveralChars) { @@ -167,15 +159,10 @@ public class Ver3DictEncoder implements DictEncoder { } } - private void writeChildrenPosition(final PtNode ptNode, final FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - if (formatOptions.mSupportsDynamicUpdate) { - mPosition += BinaryDictEncoderUtils.writeSignedChildrenPosition(mBuffer, mPosition, - childrenPos); - } else { - mPosition += BinaryDictEncoderUtils.writeChildrenPosition(mBuffer, mPosition, - childrenPos); - } + private void writeChildrenPosition(final PtNode ptNode) { + final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode); + mPosition += BinaryDictEncoderUtils.writeChildrenPosition(mBuffer, mPosition, + childrenPos); } /** @@ -193,7 +180,7 @@ public class Ver3DictEncoder implements DictEncoder { final WeightedString target = shortcutIterator.next(); final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags( shortcutIterator.hasNext(), - target.mFrequency); + target.getProbability()); mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, shortcutFlags, FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); final int shortcutShift = CharEncoding.writeString(mBuffer, mPosition, target.mWord); @@ -223,11 +210,11 @@ public class Ver3DictEncoder implements DictEncoder { final PtNode target = FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord); final int addressOfBigram = target.mCachedAddressAfterUpdate; - final int unigramFrequencyForThisWord = target.mFrequency; + final int unigramFrequencyForThisWord = target.getProbability(); final int offset = addressOfBigram - (mPosition + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); final int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(), - offset, bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord); + offset, bigram.getProbability(), unigramFrequencyForThisWord, bigram.mWord); mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, bigramFlags, FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); mPosition += BinaryDictEncoderUtils.writeChildrenPosition(mBuffer, mPosition, @@ -242,13 +229,11 @@ public class Ver3DictEncoder implements DictEncoder { } @Override - public void writePtNode(final PtNode ptNode, final int parentPosition, - final FormatOptions formatOptions, final FusionDictionary dict) { - writePtNodeFlags(ptNode, formatOptions); - writeParentPosition(parentPosition, ptNode, formatOptions); + public void writePtNode(final PtNode ptNode, final FusionDictionary dict) { + writePtNodeFlags(ptNode); writeCharacters(ptNode.mChars, ptNode.hasSeveralChars()); - writeFrequency(ptNode.mFrequency); - writeChildrenPosition(ptNode, formatOptions); + writeFrequency(ptNode.getProbability()); + writeChildrenPosition(ptNode); writeShortcuts(ptNode.mShortcutTargets); writeBigrams(ptNode.mBigrams, dict); } diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java new file mode 100644 index 000000000..f3fad7e99 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; + +/** + * An implementation of binary dictionary decoder for version 4 binary dictionary. + */ +@UsedForTesting +public class Ver4DictDecoder extends AbstractDictDecoder { + private static final String TAG = Ver4DictDecoder.class.getSimpleName(); + + final File mDictDirectory; + + @UsedForTesting + /* package */ Ver4DictDecoder(final File dictDirectory, final int factoryFlag) { + this(dictDirectory, null /* factory */); + } + + @UsedForTesting + /* package */ Ver4DictDecoder(final File dictDirectory, final DictionaryBufferFactory factory) { + mDictDirectory = dictDirectory; + + } + + @Override + public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary= new BinaryDictionary( + mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */, + true /* useFullEditDistance */, null /* locale */, + "" /* dictType */, true /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); + if (header == null) { + throw new IOException("Cannot read the dictionary header."); + } + return header; + } + + @Override + public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) + throws FileNotFoundException, IOException, UnsupportedFormatException { + // dictType is not being used in dicttool. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + mDictDirectory.getAbsolutePath(), 0 /* offset */, 0 /* length */, + true /* useFullEditDistance */, null /* locale */, + "" /* dictType */, true /* isUpdatable */); + final DictionaryHeader header = readHeader(); + final FusionDictionary fusionDict = + new FusionDictionary(new FusionDictionary.PtNodeArray(), header.mDictionaryOptions); + int token = 0; + final ArrayList<WordProperty> wordProperties = CollectionUtils.newArrayList(); + do { + final BinaryDictionary.GetNextWordPropertyResult result = + binaryDictionary.getNextWordProperty(token); + final WordProperty wordProperty = result.mWordProperty; + if (wordProperty == null) { + binaryDictionary.close(); + if (deleteDictIfBroken) { + FileUtils.deleteRecursively(mDictDirectory); + } + return null; + } + wordProperties.add(wordProperty); + token = result.mNextToken; + } while (token != 0); + + // Insert unigrams into the fusion dictionary. + for (final WordProperty wordProperty : wordProperties) { + if (wordProperty.mIsBlacklistEntry) { + fusionDict.addBlacklistEntry(wordProperty.mWord, wordProperty.mShortcutTargets, + wordProperty.mIsNotAWord); + } else { + fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo, + wordProperty.mShortcutTargets, wordProperty.mIsNotAWord); + } + } + // Insert bigrams into the fusion dictionary. + for (final WordProperty wordProperty : wordProperties) { + if (wordProperty.mBigrams == null) { + continue; + } + final String word0 = wordProperty.mWord; + for (final WeightedString bigram : wordProperty.mBigrams) { + fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo); + } + } + binaryDictionary.close(); + return fusionDict; + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java new file mode 100644 index 000000000..dab9a4315 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2013 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.makedict; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; +import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; +import com.android.inputmethod.latin.utils.LocaleUtils; + +import java.io.File; +import java.io.IOException; + +/** + * An implementation of DictEncoder for version 4 binary dictionary. + */ +@UsedForTesting +public class Ver4DictEncoder implements DictEncoder { + private final File mDictPlacedDir; + + @UsedForTesting + public Ver4DictEncoder(final File dictPlacedDir) { + mDictPlacedDir = dictPlacedDir; + } + + // TODO: This builds a FusionDictionary first and iterates it to add words to the binary + // dictionary. However, it is possible to just add words directly to the binary dictionary + // instead. + // In the long run, when we stop supporting version 2, FusionDictionary will become deprecated + // and we can remove it. Then we'll be able to just call BinaryDictionary directly. + @Override + public void writeDictionary(FusionDictionary dict, FormatOptions formatOptions) + throws IOException, UnsupportedFormatException { + if (formatOptions.mVersion != FormatSpec.VERSION4) { + throw new UnsupportedFormatException("File header has a wrong version number : " + + formatOptions.mVersion); + } + if (!mDictPlacedDir.isDirectory()) { + throw new UnsupportedFormatException("Given path is not a directory."); + } + if (!BinaryDictionaryUtils.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), + FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString( + dict.mOptions.mAttributes.get(DictionaryHeader.DICTIONARY_LOCALE_KEY)), + dict.mOptions.mAttributes)) { + throw new IOException("Cannot create dictionary file : " + + mDictPlacedDir.getAbsolutePath()); + } + final BinaryDictionary binaryDict = new BinaryDictionary(mDictPlacedDir.getAbsolutePath(), + 0l, mDictPlacedDir.length(), true /* useFullEditDistance */, + LocaleUtils.constructLocaleFromString(dict.mOptions.mAttributes.get( + DictionaryHeader.DICTIONARY_LOCALE_KEY)), + Dictionary.TYPE_USER /* Dictionary type. Does not matter for us */, + true /* isUpdatable */); + if (!binaryDict.isValidDictionary()) { + // Somehow createEmptyDictFile returned true, but the file was not created correctly + throw new IOException("Cannot create dictionary file"); + } + for (final WordProperty wordProperty : dict) { + // TODO: switch to addMultipleDictionaryEntries when they support shortcuts + if (null == wordProperty.mShortcutTargets || wordProperty.mShortcutTargets.isEmpty()) { + binaryDict.addUnigramWord(wordProperty.mWord, wordProperty.getProbability(), + null /* shortcutTarget */, 0 /* shortcutProbability */, + wordProperty.mIsNotAWord, wordProperty.mIsBlacklistEntry, + 0 /* timestamp */); + } else { + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + binaryDict.addUnigramWord(wordProperty.mWord, wordProperty.getProbability(), + shortcutTarget.mWord, shortcutTarget.getProbability(), + wordProperty.mIsNotAWord, wordProperty.mIsBlacklistEntry, + 0 /* timestamp */); + } + } + if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDict.flushWithGC(); + } + } + for (final WordProperty word0Property : dict) { + if (null == word0Property.mBigrams) continue; + for (final WeightedString word1 : word0Property.mBigrams) { + binaryDict.addBigramWords(word0Property.mWord, word1.mWord, word1.getProbability(), + 0 /* timestamp */); + if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDict.flushWithGC(); + } + } + } + binaryDict.flushWithGC(); + binaryDict.close(); + } + + @Override + public void setPosition(int position) { + } + + @Override + public int getPosition() { + return 0; + } + + @Override + public void writePtNodeCount(int ptNodeCount) { + } + + @Override + public void writeForwardLinkAddress(int forwardLinkAddress) { + } + + @Override + public void writePtNode(PtNode ptNode, FusionDictionary dict) { + } +} diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index 7c1decb71..f2d7b76b2 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -16,18 +16,19 @@ package com.android.inputmethod.latin.personalization; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import com.android.inputmethod.latin.ExpandableBinaryDictionary; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; +import com.android.inputmethod.latin.utils.FileUtils; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -38,25 +39,57 @@ import java.util.concurrent.TimeUnit; @LargeTest public class UserHistoryDictionaryTests extends AndroidTestCase { private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName(); - private SharedPreferences mPrefs; private static final String[] CHARACTERS = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" }; - private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000; - private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100; + private int mCurrentTime = 0; @Override - public void setUp() { - mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + protected void setUp() throws Exception { + super.setUp(); + resetCurrentTimeForTestMode(); + } + + @Override + protected void tearDown() throws Exception { + stopTestModeInNativeCode(); + super.tearDown(); + } + + private void resetCurrentTimeForTestMode() { + mCurrentTime = 0; + setCurrentTimeForTestMode(mCurrentTime); + } + + private void forcePassingShortTime() { + // 3 days. + final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(3); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + } + + private void forcePassingLongTime() { + // 365 days. + final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(365); + mCurrentTime += timeToElapse; + setCurrentTimeForTestMode(mCurrentTime); + } + + private static int setCurrentTimeForTestMode(final int currentTime) { + return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime); + } + + private static int stopTestModeInNativeCode() { + return BinaryDictionaryUtils.setCurrentTimeForTest(-1); } /** * Generates a random word. */ - private String generateWord(final int value) { + private static String generateWord(final int value) { final int lengthOfChars = CHARACTERS.length; StringBuilder builder = new StringBuilder(); long lvalue = Math.abs((long)value); @@ -67,7 +100,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { return builder.toString(); } - private List<String> generateWords(final int number, final Random random) { + private static List<String> generateWords(final int number, final Random random) { final Set<String> wordSet = CollectionUtils.newHashSet(); while (wordSet.size() < number) { wordSet.add(generateWord(random.nextInt())); @@ -75,10 +108,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { return new ArrayList<String>(wordSet); } - private void addToDict(final UserHistoryDictionary dict, final List<String> words) { + private static void addToDict(final UserHistoryDictionary dict, final List<String> words) { String prevWord = null; for (String word : words) { - dict.addToDictionary(prevWord, word, true); + UserHistoryDictionary.addToDictionary(dict, prevWord, word, true, + (int)TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); prevWord = word; } } @@ -87,22 +121,18 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { * @param checkContents if true, checks whether written words are actually in the dictionary * or not. */ - private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords, + private void addAndWriteRandomWords(final Locale locale, final int numberOfWords, final Random random, final boolean checkContents) { final List<String> words = generateWords(numberOfWords, random); - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix /* locale */, mPrefs); + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); // Add random words to the user history dictionary. addToDict(dict, words); if (checkContents) { - try { - Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - } + dict.waitAllTasksForTests(); for (int i = 0; i < numberOfWords; ++i) { final String word = words.get(i); - assertTrue(dict.isInDictionaryForTests(word)); + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); } } // write to file. @@ -111,57 +141,48 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { /** * Clear all entries in the user history dictionary. - * @param testFilenameSuffix file name suffix used for testing. + * @param locale dummy locale for testing. */ - private void clearHistory(final String testFilenameSuffix) { - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix /* locale */, mPrefs); - dict.clearAndFlushDictionary(); + private void clearHistory(final Locale locale) { + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); + dict.waitAllTasksForTests(); + dict.clear(); dict.close(); + dict.waitAllTasksForTests(); } /** * Shut down executer and wait until all operations of user history are done. - * @param testFilenameSuffix file name suffix used for testing. + * @param locale dummy locale for testing. */ - private void waitForWriting(final String testFilenameSuffix) { - try { - final UserHistoryDictionary dict = - PersonalizationHelper.getUserHistoryDictionary(getContext(), - testFilenameSuffix, mPrefs); - dict.shutdownExecutorForTests(); - while (!dict.isTerminatedForTests()) { - Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS); - } - } catch (InterruptedException e) { - Log.d(TAG, "InterruptedException: ", e); - } + private void waitForWriting(final Locale locale) { + final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary( + mContext, locale); + dict.waitAllTasksForTests(); } public void testRandomWords() { Log.d(TAG, "This test can be used for profiling."); Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true."); - final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; + final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); + final File dictFile = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); final int numberOfWords = 1000; final Random random = new Random(123456); try { - clearHistory(testFilenameSuffix); - addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, + clearHistory(dummyLocale); + addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */); } finally { Log.d(TAG, "waiting for writing ..."); - waitForWriting(testFilenameSuffix); - final File dictFile = new File(getContext().getFilesDir(), fileName); - if (dictFile != null) { - assertTrue(dictFile.exists()); - assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - dictFile.delete(); - } + waitForWriting(dummyLocale); + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } @@ -171,17 +192,18 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { final int numberOfWordsInsertedForEachLanguageSwitch = 100; final File dictFiles[] = new File[numberOfLanguages]; - final String testFilenameSuffixes[] = new String[numberOfLanguages]; + final Locale dummyLocales[] = new Locale[numberOfLanguages]; try { final Random random = new Random(123456); // Create filename suffixes for this test. for (int i = 0; i < numberOfLanguages; i++) { - testFilenameSuffixes[i] = "testSwitchingLanguages" + i; - final String fileName = UserHistoryDictionary.NAME + "." + - testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; - dictFiles[i] = new File(getContext().getFilesDir(), fileName); - clearHistory(testFilenameSuffixes[i]); + dummyLocales[i] = new Locale("test_switching_languages" + i); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocales[i], null /* dictFile */); + dictFiles[i] = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); + clearHistory(dummyLocales[i]); } final long start = System.currentTimeMillis(); @@ -189,7 +211,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { for (int i = 0; i < numberOfLanguageSwitching; i++) { final int index = i % numberOfLanguages; // Switch languages to testFilenameSuffixes[index]. - addAndWriteRandomWords(testFilenameSuffixes[index], + addAndWriteRandomWords(dummyLocales[index], numberOfWordsInsertedForEachLanguageSwitch, random, false /* checksContents */); } @@ -200,40 +222,62 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { } finally { Log.d(TAG, "waiting for writing ..."); for (int i = 0; i < numberOfLanguages; i++) { - waitForWriting(testFilenameSuffixes[i]); + waitForWriting(dummyLocales[i]); } - for (final File file : dictFiles) { - if (file != null) { - assertTrue(file.exists()); - assertTrue(file.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - file.delete(); - } + for (final File dictFile : dictFiles) { + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } } public void testAddManyWords() { - final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis(); - final int numberOfWords = - ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ? - 10000 : 1000; + final Locale dummyLocale = new Locale("test_random_words" + System.currentTimeMillis()); + final String dictName = ExpandableBinaryDictionary.getDictName( + UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */); + final File dictFile = ExpandableBinaryDictionary.getDictFile( + mContext, dictName, null /* dictFile */); + final int numberOfWords = 10000; final Random random = new Random(123456); - clearHistory(testFilenameSuffix); + clearHistory(dummyLocale); try { - addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random, - true /* checksContents */); + addAndWriteRandomWords(dummyLocale, numberOfWords, random, true /* checksContents */); } finally { Log.d(TAG, "waiting for writing ..."); - waitForWriting(testFilenameSuffix); - final String fileName = UserHistoryDictionary.NAME + "." + testFilenameSuffix - + ExpandableBinaryDictionary.DICT_FILE_EXTENSION; - final File dictFile = new File(getContext().getFilesDir(), fileName); - if (dictFile != null) { - assertTrue(dictFile.exists()); - assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE); - dictFile.delete(); - } + waitForWriting(dummyLocale); + assertTrue("check exisiting of " + dictFile, dictFile.exists()); + FileUtils.deleteRecursively(dictFile); } } + public void testDecaying() { + final Locale dummyLocale = new Locale("test_decaying" + System.currentTimeMillis()); + final int numberOfWords = 5000; + final Random random = new Random(123456); + resetCurrentTimeForTestMode(); + clearHistory(dummyLocale); + final List<String> words = generateWords(numberOfWords, random); + final UserHistoryDictionary dict = + PersonalizationHelper.getUserHistoryDictionary(getContext(), dummyLocale); + dict.waitAllTasksForTests(); + String prevWord = null; + for (final String word : words) { + UserHistoryDictionary.addToDictionary(dict, prevWord, word, true, mCurrentTime); + prevWord = word; + dict.waitAllTasksForTests(); + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + forcePassingShortTime(); + dict.runGCIfRequired(); + dict.waitAllTasksForTests(); + for (final String word : words) { + assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + forcePassingLongTime(); + dict.runGCIfRequired(); + dict.waitAllTasksForTests(); + for (final String word : words) { + assertFalse(dict.isInUnderlyingBinaryDictionaryForTests(word)); + } + } } diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java new file mode 100644 index 000000000..2cc22fae4 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2014 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.settings; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.utils.RunInLocale; + +import junit.framework.AssertionFailedError; + +import java.util.Locale; + +@SmallTest +public class SpacingAndPunctuationsTests extends AndroidTestCase { + private static final int ARMENIAN_FULL_STOP = '\u0589'; + private static final int ARMENIAN_COMMA = '\u055D'; + + private int mScreenMetrics; + + private boolean isPhone() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; + } + + private boolean isTablet() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET; + } + + private SpacingAndPunctuations ENGLISH; + private SpacingAndPunctuations FRENCH; + private SpacingAndPunctuations GERMAN; + private SpacingAndPunctuations ARMENIAN; + private SpacingAndPunctuations THAI; + private SpacingAndPunctuations KHMER; + private SpacingAndPunctuations LAO; + private SpacingAndPunctuations ARABIC; + private SpacingAndPunctuations PERSIAN; + private SpacingAndPunctuations HEBREW; + + private SpacingAndPunctuations UNITED_STATES; + private SpacingAndPunctuations UNITED_KINGDOM; + private SpacingAndPunctuations CANADA_FRENCH; + private SpacingAndPunctuations SWISS_GERMAN; + private SpacingAndPunctuations INDIA_ENGLISH; + private SpacingAndPunctuations ARMENIA_ARMENIAN; + private SpacingAndPunctuations CAMBODIA_KHMER; + private SpacingAndPunctuations LAOS_LAO; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics); + + // Language only + ENGLISH = getSpacingAndPunctuations(Locale.ENGLISH); + FRENCH = getSpacingAndPunctuations(Locale.FRENCH); + GERMAN = getSpacingAndPunctuations(Locale.GERMAN); + THAI = getSpacingAndPunctuations(new Locale("th")); + ARMENIAN = getSpacingAndPunctuations(new Locale("hy")); + KHMER = getSpacingAndPunctuations(new Locale("km")); + LAO = getSpacingAndPunctuations(new Locale("lo")); + ARABIC = getSpacingAndPunctuations(new Locale("ar")); + PERSIAN = getSpacingAndPunctuations(new Locale("fa")); + HEBREW = getSpacingAndPunctuations(new Locale("iw")); + + // Language and Country + UNITED_STATES = getSpacingAndPunctuations(Locale.US); + UNITED_KINGDOM = getSpacingAndPunctuations(Locale.UK); + CANADA_FRENCH = getSpacingAndPunctuations(Locale.CANADA_FRENCH); + SWISS_GERMAN = getSpacingAndPunctuations(new Locale("de", "CH")); + INDIA_ENGLISH = getSpacingAndPunctuations(new Locale("en", "IN")); + ARMENIA_ARMENIAN = getSpacingAndPunctuations(new Locale("hy", "AM")); + CAMBODIA_KHMER = getSpacingAndPunctuations(new Locale("km", "KH")); + LAOS_LAO = getSpacingAndPunctuations(new Locale("lo", "LA")); + } + + private SpacingAndPunctuations getSpacingAndPunctuations(final Locale locale) { + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(Resources res) { + return new SpacingAndPunctuations(res); + } + }; + return job.runInLocale(getContext().getResources(), locale); + } + + private static void testingStandardWordSeparator(final SpacingAndPunctuations sp) { + assertTrue("Tab", sp.isWordSeparator('\t')); + assertTrue("Newline", sp.isWordSeparator('\n')); + assertTrue("Space", sp.isWordSeparator(' ')); + assertTrue("Exclamation", sp.isWordSeparator('!')); + assertTrue("Quotation", sp.isWordSeparator('"')); + assertFalse("Number", sp.isWordSeparator('#')); + assertFalse("Dollar", sp.isWordSeparator('$')); + assertFalse("Percent", sp.isWordSeparator('%')); + assertTrue("Ampersand", sp.isWordSeparator('&')); + assertFalse("Apostrophe", sp.isWordSeparator('\'')); + assertTrue("L Paren", sp.isWordSeparator('(')); + assertTrue("R Paren", sp.isWordSeparator(')')); + assertTrue("Asterisk", sp.isWordSeparator('*')); + assertTrue("Plus", sp.isWordSeparator('+')); + assertTrue("Comma", sp.isWordSeparator(',')); + assertFalse("Minus", sp.isWordSeparator('-')); + assertTrue("Period", sp.isWordSeparator('.')); + assertTrue("Slash", sp.isWordSeparator('/')); + assertTrue("Colon", sp.isWordSeparator(':')); + assertTrue("Semicolon", sp.isWordSeparator(';')); + assertTrue("L Angle", sp.isWordSeparator('<')); + assertTrue("Equal", sp.isWordSeparator('=')); + assertTrue("R Angle", sp.isWordSeparator('>')); + assertTrue("Question", sp.isWordSeparator('?')); + assertFalse("Atmark", sp.isWordSeparator('@')); + assertTrue("L S Bracket", sp.isWordSeparator('[')); + assertFalse("B Slash", sp.isWordSeparator('\\')); + assertTrue("R S Bracket", sp.isWordSeparator(']')); + assertFalse("Circumflex", sp.isWordSeparator('^')); + assertTrue("Underscore", sp.isWordSeparator('_')); + assertFalse("Grave", sp.isWordSeparator('`')); + assertTrue("L C Brace", sp.isWordSeparator('{')); + assertTrue("V Line", sp.isWordSeparator('|')); + assertTrue("R C Brace", sp.isWordSeparator('}')); + assertFalse("Tilde", sp.isWordSeparator('~')); + } + + public void testWordSeparator() { + testingStandardWordSeparator(ENGLISH); + testingStandardWordSeparator(FRENCH); + testingStandardWordSeparator(CANADA_FRENCH); + testingStandardWordSeparator(ARMENIA_ARMENIAN); + assertTrue(ARMENIA_ARMENIAN.isWordSeparator(ARMENIAN_FULL_STOP)); + assertTrue(ARMENIA_ARMENIAN.isWordSeparator(ARMENIAN_COMMA)); + // TODO: We should fix these. + testingStandardWordSeparator(ARMENIAN); + assertFalse(ARMENIAN.isWordSeparator(ARMENIAN_FULL_STOP)); + assertFalse(ARMENIAN.isWordSeparator(ARMENIAN_COMMA)); + } + + private static void testingStandardWordConnector(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isWordConnector('\t')); + assertFalse("Newline", sp.isWordConnector('\n')); + assertFalse("Space", sp.isWordConnector(' ')); + assertFalse("Exclamation", sp.isWordConnector('!')); + assertFalse("Quotation", sp.isWordConnector('"')); + assertFalse("Number", sp.isWordConnector('#')); + assertFalse("Dollar", sp.isWordConnector('$')); + assertFalse("Percent", sp.isWordConnector('%')); + assertFalse("Ampersand", sp.isWordConnector('&')); + assertTrue("Apostrophe", sp.isWordConnector('\'')); + assertFalse("L Paren", sp.isWordConnector('(')); + assertFalse("R Paren", sp.isWordConnector(')')); + assertFalse("Asterisk", sp.isWordConnector('*')); + assertFalse("Plus", sp.isWordConnector('+')); + assertFalse("Comma", sp.isWordConnector(',')); + assertTrue("Minus", sp.isWordConnector('-')); + assertFalse("Period", sp.isWordConnector('.')); + assertFalse("Slash", sp.isWordConnector('/')); + assertFalse("Colon", sp.isWordConnector(':')); + assertFalse("Semicolon", sp.isWordConnector(';')); + assertFalse("L Angle", sp.isWordConnector('<')); + assertFalse("Equal", sp.isWordConnector('=')); + assertFalse("R Angle", sp.isWordConnector('>')); + assertFalse("Question", sp.isWordConnector('?')); + assertFalse("Atmark", sp.isWordConnector('@')); + assertFalse("L S Bracket", sp.isWordConnector('[')); + assertFalse("B Slash", sp.isWordConnector('\\')); + assertFalse("R S Bracket", sp.isWordConnector(']')); + assertFalse("Circumflex", sp.isWordConnector('^')); + assertFalse("Underscore", sp.isWordConnector('_')); + assertFalse("Grave", sp.isWordConnector('`')); + assertFalse("L C Brace", sp.isWordConnector('{')); + assertFalse("V Line", sp.isWordConnector('|')); + assertFalse("R C Brace", sp.isWordConnector('}')); + assertFalse("Tilde", sp.isWordConnector('~')); + + } + + public void testWordConnector() { + testingStandardWordConnector(ENGLISH); + testingStandardWordConnector(FRENCH); + testingStandardWordConnector(CANADA_FRENCH); + testingStandardWordConnector(ARMENIA_ARMENIAN); + } + + private static void testingCommonPrecededBySpace(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyPrecededBySpace('\t')); + assertFalse("Newline", sp.isUsuallyPrecededBySpace('\n')); + assertFalse("Space", sp.isUsuallyPrecededBySpace(' ')); + //assertFalse("Exclamation", sp.isUsuallyPrecededBySpace('!')); + assertFalse("Quotation", sp.isUsuallyPrecededBySpace('"')); + assertFalse("Number", sp.isUsuallyPrecededBySpace('#')); + assertFalse("Dollar", sp.isUsuallyPrecededBySpace('$')); + assertFalse("Percent", sp.isUsuallyPrecededBySpace('%')); + assertTrue("Ampersand", sp.isUsuallyPrecededBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyPrecededBySpace('\'')); + assertTrue("L Paren", sp.isUsuallyPrecededBySpace('(')); + assertFalse("R Paren", sp.isUsuallyPrecededBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyPrecededBySpace('*')); + assertFalse("Plus", sp.isUsuallyPrecededBySpace('+')); + assertFalse("Comma", sp.isUsuallyPrecededBySpace(',')); + assertFalse("Minus", sp.isUsuallyPrecededBySpace('-')); + assertFalse("Period", sp.isUsuallyPrecededBySpace('.')); + assertFalse("Slash", sp.isUsuallyPrecededBySpace('/')); + //assertFalse("Colon", sp.isUsuallyPrecededBySpace(':')); + //assertFalse("Semicolon", sp.isUsuallyPrecededBySpace(';')); + assertFalse("L Angle", sp.isUsuallyPrecededBySpace('<')); + assertFalse("Equal", sp.isUsuallyPrecededBySpace('=')); + assertFalse("R Angle", sp.isUsuallyPrecededBySpace('>')); + //assertFalse("Question", sp.isUsuallyPrecededBySpace('?')); + assertFalse("Atmark", sp.isUsuallyPrecededBySpace('@')); + assertTrue("L S Bracket", sp.isUsuallyPrecededBySpace('[')); + assertFalse("B Slash", sp.isUsuallyPrecededBySpace('\\')); + assertFalse("R S Bracket", sp.isUsuallyPrecededBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyPrecededBySpace('^')); + assertFalse("Underscore", sp.isUsuallyPrecededBySpace('_')); + assertFalse("Grave", sp.isUsuallyPrecededBySpace('`')); + assertTrue("L C Brace", sp.isUsuallyPrecededBySpace('{')); + assertFalse("V Line", sp.isUsuallyPrecededBySpace('|')); + assertFalse("R C Brace", sp.isUsuallyPrecededBySpace('}')); + assertFalse("Tilde", sp.isUsuallyPrecededBySpace('~')); + } + + private static void testingStandardPrecededBySpace(final SpacingAndPunctuations sp) { + testingCommonPrecededBySpace(sp); + assertFalse("Exclamation", sp.isUsuallyPrecededBySpace('!')); + assertFalse("Colon", sp.isUsuallyPrecededBySpace(':')); + assertFalse("Semicolon", sp.isUsuallyPrecededBySpace(';')); + assertFalse("Question", sp.isUsuallyPrecededBySpace('?')); + } + + public void testIsUsuallyPrecededBySpace() { + testingStandardPrecededBySpace(ENGLISH); + testingCommonPrecededBySpace(FRENCH); + assertTrue("Exclamation", FRENCH.isUsuallyPrecededBySpace('!')); + assertTrue("Colon", FRENCH.isUsuallyPrecededBySpace(':')); + assertTrue("Semicolon", FRENCH.isUsuallyPrecededBySpace(';')); + assertTrue("Question", FRENCH.isUsuallyPrecededBySpace('?')); + testingCommonPrecededBySpace(CANADA_FRENCH); + assertFalse("Exclamation", CANADA_FRENCH.isUsuallyPrecededBySpace('!')); + assertTrue("Colon", CANADA_FRENCH.isUsuallyPrecededBySpace(':')); + assertFalse("Semicolon", CANADA_FRENCH.isUsuallyPrecededBySpace(';')); + assertFalse("Question", CANADA_FRENCH.isUsuallyPrecededBySpace('?')); + testingStandardPrecededBySpace(ARMENIA_ARMENIAN); + } + + private static void testingStandardFollowedBySpace(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyFollowedBySpace('\t')); + assertFalse("Newline", sp.isUsuallyFollowedBySpace('\n')); + assertFalse("Space", sp.isUsuallyFollowedBySpace(' ')); + assertTrue("Exclamation", sp.isUsuallyFollowedBySpace('!')); + assertFalse("Quotation", sp.isUsuallyFollowedBySpace('"')); + assertFalse("Number", sp.isUsuallyFollowedBySpace('#')); + assertFalse("Dollar", sp.isUsuallyFollowedBySpace('$')); + assertFalse("Percent", sp.isUsuallyFollowedBySpace('%')); + assertTrue("Ampersand", sp.isUsuallyFollowedBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyFollowedBySpace('\'')); + assertFalse("L Paren", sp.isUsuallyFollowedBySpace('(')); + assertTrue("R Paren", sp.isUsuallyFollowedBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyFollowedBySpace('*')); + assertFalse("Plus", sp.isUsuallyFollowedBySpace('+')); + assertTrue("Comma", sp.isUsuallyFollowedBySpace(',')); + assertFalse("Minus", sp.isUsuallyFollowedBySpace('-')); + assertTrue("Period", sp.isUsuallyFollowedBySpace('.')); + assertFalse("Slash", sp.isUsuallyFollowedBySpace('/')); + assertTrue("Colon", sp.isUsuallyFollowedBySpace(':')); + assertTrue("Semicolon", sp.isUsuallyFollowedBySpace(';')); + assertFalse("L Angle", sp.isUsuallyFollowedBySpace('<')); + assertFalse("Equal", sp.isUsuallyFollowedBySpace('=')); + assertFalse("R Angle", sp.isUsuallyFollowedBySpace('>')); + assertTrue("Question", sp.isUsuallyFollowedBySpace('?')); + assertFalse("Atmark", sp.isUsuallyFollowedBySpace('@')); + assertFalse("L S Bracket", sp.isUsuallyFollowedBySpace('[')); + assertFalse("B Slash", sp.isUsuallyFollowedBySpace('\\')); + assertTrue("R S Bracket", sp.isUsuallyFollowedBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyFollowedBySpace('^')); + assertFalse("Underscore", sp.isUsuallyFollowedBySpace('_')); + assertFalse("Grave", sp.isUsuallyFollowedBySpace('`')); + assertFalse("L C Brace", sp.isUsuallyFollowedBySpace('{')); + assertFalse("V Line", sp.isUsuallyFollowedBySpace('|')); + assertTrue("R C Brace", sp.isUsuallyFollowedBySpace('}')); + assertFalse("Tilde", sp.isUsuallyFollowedBySpace('~')); + } + + public void testIsUsuallyFollowedBySpace() { + testingStandardFollowedBySpace(ENGLISH); + testingStandardFollowedBySpace(FRENCH); + testingStandardFollowedBySpace(CANADA_FRENCH); + testingStandardFollowedBySpace(ARMENIA_ARMENIAN); + assertTrue(ARMENIA_ARMENIAN.isUsuallyFollowedBySpace(ARMENIAN_FULL_STOP)); + assertTrue(ARMENIA_ARMENIAN.isUsuallyFollowedBySpace(ARMENIAN_COMMA)); + } + + private static void testingStandardSentenceSeparator(final SpacingAndPunctuations sp) { + assertFalse("Tab", sp.isUsuallyFollowedBySpace('\t')); + assertFalse("Newline", sp.isUsuallyFollowedBySpace('\n')); + assertFalse("Space", sp.isUsuallyFollowedBySpace(' ')); + assertFalse("Exclamation", sp.isUsuallyFollowedBySpace('!')); + assertFalse("Quotation", sp.isUsuallyFollowedBySpace('"')); + assertFalse("Number", sp.isUsuallyFollowedBySpace('#')); + assertFalse("Dollar", sp.isUsuallyFollowedBySpace('$')); + assertFalse("Percent", sp.isUsuallyFollowedBySpace('%')); + assertFalse("Ampersand", sp.isUsuallyFollowedBySpace('&')); + assertFalse("Apostrophe", sp.isUsuallyFollowedBySpace('\'')); + assertFalse("L Paren", sp.isUsuallyFollowedBySpace('(')); + assertFalse("R Paren", sp.isUsuallyFollowedBySpace(')')); + assertFalse("Asterisk", sp.isUsuallyFollowedBySpace('*')); + assertFalse("Plus", sp.isUsuallyFollowedBySpace('+')); + assertFalse("Comma", sp.isUsuallyFollowedBySpace(',')); + assertFalse("Minus", sp.isUsuallyFollowedBySpace('-')); + assertTrue("Period", sp.isUsuallyFollowedBySpace('.')); + assertFalse("Slash", sp.isUsuallyFollowedBySpace('/')); + assertFalse("Colon", sp.isUsuallyFollowedBySpace(':')); + assertFalse("Semicolon", sp.isUsuallyFollowedBySpace(';')); + assertFalse("L Angle", sp.isUsuallyFollowedBySpace('<')); + assertFalse("Equal", sp.isUsuallyFollowedBySpace('=')); + assertFalse("R Angle", sp.isUsuallyFollowedBySpace('>')); + assertFalse("Question", sp.isUsuallyFollowedBySpace('?')); + assertFalse("Atmark", sp.isUsuallyFollowedBySpace('@')); + assertFalse("L S Bracket", sp.isUsuallyFollowedBySpace('[')); + assertFalse("B Slash", sp.isUsuallyFollowedBySpace('\\')); + assertFalse("R S Bracket", sp.isUsuallyFollowedBySpace(']')); + assertFalse("Circumflex", sp.isUsuallyFollowedBySpace('^')); + assertFalse("Underscore", sp.isUsuallyFollowedBySpace('_')); + assertFalse("Grave", sp.isUsuallyFollowedBySpace('`')); + assertFalse("L C Brace", sp.isUsuallyFollowedBySpace('{')); + assertFalse("V Line", sp.isUsuallyFollowedBySpace('|')); + assertFalse("R C Brace", sp.isUsuallyFollowedBySpace('}')); + assertFalse("Tilde", sp.isUsuallyFollowedBySpace('~')); + } + + public void isSentenceSeparator() { + testingStandardSentenceSeparator(ENGLISH); + try { + testingStandardSentenceSeparator(ARMENIA_ARMENIAN); + fail("Armenian Sentence Separator"); + } catch (final AssertionFailedError e) { + assertEquals("Period", e.getMessage()); + } + assertTrue(ARMENIA_ARMENIAN.isSentenceSeparator(ARMENIAN_FULL_STOP)); + assertFalse(ARMENIA_ARMENIAN.isSentenceSeparator(ARMENIAN_COMMA)); + } + + public void testLanguageHasSpace() { + assertTrue(ENGLISH.mCurrentLanguageHasSpaces); + assertTrue(FRENCH.mCurrentLanguageHasSpaces); + assertTrue(GERMAN.mCurrentLanguageHasSpaces); + assertFalse(THAI.mCurrentLanguageHasSpaces); + assertFalse(CAMBODIA_KHMER.mCurrentLanguageHasSpaces); + assertFalse(LAOS_LAO.mCurrentLanguageHasSpaces); + // TODO: We should fix these. + assertTrue(KHMER.mCurrentLanguageHasSpaces); + assertTrue(LAO.mCurrentLanguageHasSpaces); + } + + public void testUsesAmericanTypography() { + assertTrue(ENGLISH.mUsesAmericanTypography); + assertTrue(UNITED_STATES.mUsesAmericanTypography); + assertTrue(UNITED_KINGDOM.mUsesAmericanTypography); + assertTrue(INDIA_ENGLISH.mUsesAmericanTypography); + assertFalse(FRENCH.mUsesAmericanTypography); + assertFalse(GERMAN.mUsesAmericanTypography); + assertFalse(SWISS_GERMAN.mUsesAmericanTypography); + } + + public void testUsesGermanRules() { + assertFalse(ENGLISH.mUsesGermanRules); + assertFalse(FRENCH.mUsesGermanRules); + assertTrue(GERMAN.mUsesGermanRules); + assertTrue(SWISS_GERMAN.mUsesGermanRules); + } + + // Punctuations for phone. + private static final String[] PUNCTUATION_LABELS_PHONE = { + "!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_PHONE_LTR = PUNCTUATION_LABELS_PHONE; + private static final String[] PUNCTUATION_WORDS_PHONE_HEBREW = { + "!", "?", ",", ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + // U+061F: "؟" ARABIC QUESTION MARK + // U+060C: "،" ARABIC COMMA + // U+061B: "؛" ARABIC SEMICOLON + private static final String[] PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + + // Punctuations for tablet. + private static final String[] PUNCTUATION_LABELS_TABLET = { + ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_TABLET_LTR = PUNCTUATION_LABELS_TABLET; + private static final String[] PUNCTUATION_WORDS_TABLET_HEBREW = { + ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN = { + "!", "\u061F", ":", "\u061B", "\"", "'", "(", ")", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN = { + "!", "\u061F", ":", "\u061B", "\"", "'", ")", "(", "-", "/", "@", "_" + }; + + private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp, + final String[] punctuationLabels, final String[] punctuationWords) { + final SuggestedWords suggestedWords = sp.mSuggestPuncList; + assertFalse("typedWordValid", suggestedWords.mTypedWordValid); + assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect); + assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions()); + assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions); + assertFalse("isPrediction", suggestedWords.mIsPrediction); + assertEquals("size", punctuationLabels.length, suggestedWords.size()); + for (int index = 0; index < suggestedWords.size(); index++) { + assertEquals("punctuation label at " + index, + punctuationLabels[index], suggestedWords.getLabel(index)); + assertEquals("punctuation word at " + index, + punctuationWords[index], suggestedWords.getWord(index)); + } + } + + public void testPhonePunctuationSuggestions() { + if (!isPhone()) { + return; + } + testingStandardPunctuationSuggestions(ENGLISH, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(FRENCH, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(GERMAN, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_LTR); + testingStandardPunctuationSuggestions(ARABIC, + PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(PERSIAN, + PUNCTUATION_LABELS_PHONE_ARABIC_PERSIAN, PUNCTUATION_WORDS_PHONE_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(HEBREW, + PUNCTUATION_LABELS_PHONE, PUNCTUATION_WORDS_PHONE_HEBREW); + } + + public void testTabletPunctuationSuggestions() { + if (!isTablet()) { + return; + } + testingStandardPunctuationSuggestions(ENGLISH, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(FRENCH, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(GERMAN, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_LTR); + testingStandardPunctuationSuggestions(ARABIC, + PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(PERSIAN, + PUNCTUATION_LABELS_TABLET_ARABIC_PERSIAN, PUNCTUATION_WORDS_TABLET_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(HEBREW, + PUNCTUATION_LABELS_TABLET, PUNCTUATION_WORDS_TABLET_HEBREW); + } +} diff --git a/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java new file mode 100644 index 000000000..d86639101 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtilsTests.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.FormatSpec; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@LargeTest +public class BinaryDictionaryUtilsTests extends AndroidTestCase { + private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; + private static final String TEST_LOCALE = "test"; + + private File createEmptyDictionaryAndGetFile(final String dictId, + final int formatVersion) throws IOException { + if (formatVersion == FormatSpec.VERSION4) { + return createEmptyVer4DictionaryAndGetFile(dictId); + } else { + throw new IOException("Dictionary format version " + formatVersion + + " is not supported."); + } + } + + private File createEmptyVer4DictionaryAndGetFile(final String dictId) throws IOException { + final File file = getDictFile(dictId); + FileUtils.deleteRecursively(file); + Map<String, String> attributeMap = new HashMap<String, String>(); + attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, dictId); + attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY, + String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()))); + attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { + return file; + } else { + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); + } + } + + private File getDictFile(final String dictId) { + return new File(getContext().getCacheDir(), dictId + TEST_DICT_FILE_EXTENSION); + } + + public void testRenameDictionary() { + final int formatVersion = FormatSpec.VERSION4; + File dictFile0 = null; + try { + dictFile0 = createEmptyDictionaryAndGetFile("MoveFromDictionary", formatVersion); + } catch (IOException e) { + fail("IOException while writing an initial dictionary : " + e); + } + final File dictFile1 = getDictFile("MoveToDictionary"); + FileUtils.deleteRecursively(dictFile1); + assertTrue(BinaryDictionaryUtils.renameDict(dictFile0, dictFile1)); + assertFalse(dictFile0.exists()); + assertTrue(dictFile1.exists()); + BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile1.getAbsolutePath(), + 0 /* offset */, dictFile1.length(), true /* useFullEditDistance */, + Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */); + assertTrue(binaryDictionary.isValidDictionary()); + assertTrue(binaryDictionary.getFormatVersion() == formatVersion); + binaryDictionary.close(); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java b/tests/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java index 2028298f2..2028298f2 100644 --- a/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java +++ b/tests/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java diff --git a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java index 1fd5c989a..020d63299 100644 --- a/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java @@ -16,75 +16,98 @@ package com.android.inputmethod.latin.utils; -import com.android.inputmethod.latin.settings.SettingsValues; - +import android.content.res.Resources; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.text.TextUtils; +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; + import java.util.Locale; @SmallTest public class CapsModeUtilsTests extends AndroidTestCase { private static void onePathForCaps(final CharSequence cs, final int expectedResult, - final int mask, final SettingsValues sv, final boolean hasSpaceBefore) { - int oneTimeResult = expectedResult & mask; + final int mask, final SpacingAndPunctuations sp, final boolean hasSpaceBefore) { + final int oneTimeResult = expectedResult & mask; assertEquals("After >" + cs + "<", oneTimeResult, - CapsModeUtils.getCapsMode(cs, mask, sv, hasSpaceBefore)); + CapsModeUtils.getCapsMode(cs, mask, sp, hasSpaceBefore)); } private static void allPathsForCaps(final CharSequence cs, final int expectedResult, - final SettingsValues sv, final boolean hasSpaceBefore) { + final SpacingAndPunctuations sp, final boolean hasSpaceBefore) { final int c = TextUtils.CAP_MODE_CHARACTERS; final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; - onePathForCaps(cs, expectedResult, c | w | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, w | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c | s, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c | w, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, c, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, w, sv, hasSpaceBefore); - onePathForCaps(cs, expectedResult, s, sv, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | w | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | s, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c | w, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, c, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, w, sp, hasSpaceBefore); + onePathForCaps(cs, expectedResult, s, sp, hasSpaceBefore); } public void testGetCapsMode() { final int c = TextUtils.CAP_MODE_CHARACTERS; final int w = TextUtils.CAP_MODE_WORDS; final int s = TextUtils.CAP_MODE_SENTENCES; - SettingsValues sv = SettingsValues.makeDummySettingsValuesForTest(Locale.ENGLISH); - allPathsForCaps("", c | w | s, sv, false); - allPathsForCaps("Word", c, sv, false); - allPathsForCaps("Word.", c, sv, false); - allPathsForCaps("Word ", c | w, sv, false); - allPathsForCaps("Word. ", c | w | s, sv, false); - allPathsForCaps("Word..", c, sv, false); - allPathsForCaps("Word.. ", c | w | s, sv, false); - allPathsForCaps("Word... ", c | w | s, sv, false); - allPathsForCaps("Word ... ", c | w | s, sv, false); - allPathsForCaps("Word . ", c | w, sv, false); - allPathsForCaps("In the U.S ", c | w, sv, false); - allPathsForCaps("In the U.S. ", c | w, sv, false); - allPathsForCaps("Some stuff (e.g. ", c | w, sv, false); - allPathsForCaps("In the U.S.. ", c | w | s, sv, false); - allPathsForCaps("\"Word.\" ", c | w | s, sv, false); - allPathsForCaps("\"Word\". ", c | w | s, sv, false); - allPathsForCaps("\"Word\" ", c | w, sv, false); + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + SpacingAndPunctuations sp = job.runInLocale(res, Locale.ENGLISH); + allPathsForCaps("", c | w | s, sp, false); + allPathsForCaps("Word", c, sp, false); + allPathsForCaps("Word.", c, sp, false); + allPathsForCaps("Word ", c | w, sp, false); + allPathsForCaps("Word. ", c | w | s, sp, false); + allPathsForCaps("Word..", c, sp, false); + allPathsForCaps("Word.. ", c | w | s, sp, false); + allPathsForCaps("Word... ", c | w | s, sp, false); + allPathsForCaps("Word ... ", c | w | s, sp, false); + allPathsForCaps("Word . ", c | w, sp, false); + allPathsForCaps("In the U.S ", c | w, sp, false); + allPathsForCaps("In the U.S. ", c | w, sp, false); + allPathsForCaps("Some stuff (e.g. ", c | w, sp, false); + allPathsForCaps("In the U.S.. ", c | w | s, sp, false); + allPathsForCaps("\"Word.\" ", c | w | s, sp, false); + allPathsForCaps("\"Word\". ", c | w | s, sp, false); + allPathsForCaps("\"Word\" ", c | w, sp, false); // Test for phantom space - allPathsForCaps("Word", c | w, sv, true); - allPathsForCaps("Word.", c | w | s, sv, true); + allPathsForCaps("Word", c | w, sp, true); + allPathsForCaps("Word.", c | w | s, sp, true); // Tests after some whitespace - allPathsForCaps("Word\n", c | w | s, sv, false); - allPathsForCaps("Word\n", c | w | s, sv, true); - allPathsForCaps("Word\n ", c | w | s, sv, true); - allPathsForCaps("Word.\n", c | w | s, sv, false); - allPathsForCaps("Word.\n", c | w | s, sv, true); - allPathsForCaps("Word.\n ", c | w | s, sv, true); + allPathsForCaps("Word\n", c | w | s, sp, false); + allPathsForCaps("Word\n", c | w | s, sp, true); + allPathsForCaps("Word\n ", c | w | s, sp, true); + allPathsForCaps("Word.\n", c | w | s, sp, false); + allPathsForCaps("Word.\n", c | w | s, sp, true); + allPathsForCaps("Word.\n ", c | w | s, sp, true); + + sp = job.runInLocale(res, Locale.FRENCH); + allPathsForCaps("\"Word.\" ", c | w, sp, false); + allPathsForCaps("\"Word\". ", c | w | s, sp, false); + allPathsForCaps("\"Word\" ", c | w, sp, false); - sv = SettingsValues.makeDummySettingsValuesForTest(Locale.FRENCH); - allPathsForCaps("\"Word.\" ", c | w, sv, false); - allPathsForCaps("\"Word\". ", c | w | s, sv, false); - allPathsForCaps("\"Word\" ", c | w, sv, false); + // Test special case for German. German does not capitalize at the start of a + // line when the previous line starts with a comma. It does in other cases. + sp = job.runInLocale(res, Locale.GERMAN); + allPathsForCaps("Liebe Sara,\n", c | w, sp, false); + allPathsForCaps("Liebe Sara,\n", c | w, sp, true); + allPathsForCaps("Liebe Sara, \n ", c | w, sp, false); + allPathsForCaps("Liebe Sara \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara.\n ", c | w | s, sp, false); + sp = job.runInLocale(res, Locale.ENGLISH); + allPathsForCaps("Liebe Sara,\n", c | w | s, sp, false); + allPathsForCaps("Liebe Sara,\n", c | w | s, sp, true); + allPathsForCaps("Liebe Sara, \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara \n ", c | w | s, sp, false); + allPathsForCaps("Liebe Sara.\n ", c | w | s, sp, false); } } diff --git a/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java new file mode 100644 index 000000000..6e716074c --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/utils/DictionaryInfoUtilsTests.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 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.utils; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.settings.SpacingAndPunctuations; + +import java.util.Locale; + +@SmallTest +public class DictionaryInfoUtilsTests extends AndroidTestCase { + public void testLooksValidForDictionaryInsertion() { + final RunInLocale<SpacingAndPunctuations> job = new RunInLocale<SpacingAndPunctuations>() { + @Override + protected SpacingAndPunctuations job(final Resources res) { + return new SpacingAndPunctuations(res); + } + }; + final Resources res = getContext().getResources(); + final SpacingAndPunctuations sp = job.runInLocale(res, Locale.ENGLISH); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("aochaueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("", sp)); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("ao-ch'aueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("2908743256", sp)); + assertTrue(DictionaryInfoUtils.looksValidForDictionaryInsertion("31aochaueo", sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("akeo raeoch oerch .", + sp)); + assertFalse(DictionaryInfoUtils.looksValidForDictionaryInsertion("!!!", sp)); + } +} diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java index 0b7fcbbe8..58312264b 100644 --- a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java @@ -14,23 +14,13 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @SmallTest public class EditDistanceTests extends AndroidTestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - /* * dist(kitten, sitting) == 3 * @@ -39,7 +29,7 @@ public class EditDistanceTests extends AndroidTestCase { * sitting */ public void testExample1() { - final int dist = BinaryDictionary.editDistance("kitten", "sitting"); + final int dist = BinaryDictionaryUtils.editDistance("kitten", "sitting"); assertEquals("edit distance between 'kitten' and 'sitting' is 3", 3, dist); } @@ -52,26 +42,26 @@ public class EditDistanceTests extends AndroidTestCase { * S--unday */ public void testExample2() { - final int dist = BinaryDictionary.editDistance("Saturday", "Sunday"); + final int dist = BinaryDictionaryUtils.editDistance("Saturday", "Sunday"); assertEquals("edit distance between 'Saturday' and 'Sunday' is 3", 3, dist); } public void testBothEmpty() { - final int dist = BinaryDictionary.editDistance("", ""); + final int dist = BinaryDictionaryUtils.editDistance("", ""); assertEquals("when both string are empty, no edits are needed", 0, dist); } public void testFirstArgIsEmpty() { - final int dist = BinaryDictionary.editDistance("", "aaaa"); + final int dist = BinaryDictionaryUtils.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 = BinaryDictionary.editDistance("aaaa", ""); + final int dist = BinaryDictionaryUtils.editDistance("aaaa", ""); assertEquals("when only one string of the arguments is empty," + " the edit distance is the length of the other.", 4, dist); @@ -80,27 +70,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 = BinaryDictionary.editDistance(arg1, arg2); + final int dist = BinaryDictionaryUtils.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 = BinaryDictionary.editDistance(arg, arg); + final int dist = BinaryDictionaryUtils.editDistance(arg, arg); assertEquals("when same string references are passed, the distance equals 0.", 0, dist); } public void testNullArg() { try { - BinaryDictionary.editDistance(null, "aaa"); + BinaryDictionaryUtils.editDistance(null, "aaa"); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { - BinaryDictionary.editDistance("aaa", null); + BinaryDictionaryUtils.editDistance("aaa", null); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); diff --git a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java b/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java deleted file mode 100644 index 823bd5d7d..000000000 --- a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.utils; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -@SmallTest -public class ForgettingCurveTests extends AndroidTestCase { - public void testFcToFreq() { - for (int i = 0; i < Byte.MAX_VALUE; ++i) { - final byte fc = (byte)i; - final int e = UserHistoryForgettingCurveUtils.fcToElapsedTime(fc); - final int c = UserHistoryForgettingCurveUtils.fcToCount(fc); - final int l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - final byte fc2 = UserHistoryForgettingCurveUtils.calcFc(e, c, l); - assertEquals(fc, fc2); - } - byte fc = 0; - int l; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, true); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(1, Math.min(i + 1, 3))); - } - fc = 0; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, false); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.min(i + 1, 3)); - } - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.ELAPSED_TIME_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushElapsedTime(fc); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(0, 2 - i)); - } - } -} diff --git a/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java index a52041264..ada80c3fa 100644 --- a/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java @@ -19,31 +19,35 @@ package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.Constants; + import java.util.Locale; @SmallTest public class RecapitalizeStatusTests extends AndroidTestCase { + private static final int[] SPACE = { Constants.CODE_SPACE }; + public void testTrim() { final RecapitalizeStatus status = new RecapitalizeStatus(); - status.initialize(30, 40, "abcdefghij", Locale.ENGLISH, " "); + status.initialize(30, 40, "abcdefghij", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); - status.initialize(30, 44, " abcdefghij", Locale.ENGLISH, " "); + status.initialize(30, 44, " abcdefghij", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(34, status.getNewCursorStart()); assertEquals(44, status.getNewCursorEnd()); - status.initialize(30, 40, "abcdefgh ", Locale.ENGLISH, " "); + status.initialize(30, 40, "abcdefgh ", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefgh", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(38, status.getNewCursorEnd()); - status.initialize(30, 45, " abcdefghij ", Locale.ENGLISH, " "); + status.initialize(30, 45, " abcdefghij ", Locale.ENGLISH, SPACE); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(33, status.getNewCursorStart()); @@ -52,7 +56,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { public void testRotate() { final RecapitalizeStatus status = new RecapitalizeStatus(); - status.initialize(29, 40, "abcd efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "abcd efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -64,7 +68,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); - status.initialize(29, 40, "Abcd Efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "Abcd Efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -76,7 +80,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); - status.initialize(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, " "); + status.initialize(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -88,7 +92,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); - status.initialize(29, 39, "AbCDefghij", Locale.ENGLISH, " "); + status.initialize(29, 39, "AbCDefghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -102,7 +106,7 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); - status.initialize(29, 40, "Abcd efghij", Locale.ENGLISH, " "); + status.initialize(29, 40, "Abcd efghij", Locale.ENGLISH, SPACE); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); @@ -116,7 +120,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); - status.initialize(30, 34, "grüß", Locale.GERMAN, " "); status.rotate(); + status.initialize(30, 34, "grüß", Locale.GERMAN, SPACE); + status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); @@ -133,7 +138,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); - status.initialize(30, 33, "œuf", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 33, "œuf", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); @@ -150,7 +156,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); - status.initialize(30, 33, "œUf", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 33, "œUf", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); @@ -171,7 +178,8 @@ public class RecapitalizeStatusTests extends AndroidTestCase { assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); - status.initialize(30, 35, "école", Locale.FRENCH, " "); status.rotate(); + status.initialize(30, 35, "école", Locale.FRENCH, SPACE); + status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); diff --git a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java index cad80d5ce..8f58e6873 100644 --- a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java @@ -39,7 +39,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { int[] array2 = null, array3 = null; final int limit = DEFAULT_CAPACITY * 2 + 10; for (int i = 0; i < limit; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == DEFAULT_CAPACITY) { array2 = src.getPrimitiveArray(); @@ -56,7 +57,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { } } for (int i = 0; i < limit; i++) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -64,11 +66,13 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int limit = DEFAULT_CAPACITY * 10, step = DEFAULT_CAPACITY * 2; for (int i = 0; i < limit; i += step) { - src.add(i, i); + final int value = i; + src.addAt(i, value); assertEquals("length after add at " + i, i + 1, src.getLength()); } for (int i = 0; i < limit; i += step) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -88,9 +92,10 @@ public class ResizableIntArrayTests extends AndroidTestCase { } final int index = DEFAULT_CAPACITY / 2; - src.add(index, 100); + final int valueAddAt = 100; + src.addAt(index, valueAddAt); assertEquals("legth after add at " + index, index + 1, src.getLength()); - assertEquals("value after add at " + index, 100, src.get(index)); + assertEquals("value after add at " + index, valueAddAt, src.get(index)); assertEquals("value after add at 0", 0, src.get(0)); try { final int value = src.get(src.getLength()); @@ -104,7 +109,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int[] array = src.getPrimitiveArray(); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); } @@ -116,7 +122,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { int[] array3 = null; for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); if (i == smallerLength) { array3 = src.getPrimitiveArray(); @@ -133,7 +140,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int[] array = src.getPrimitiveArray(); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); assertEquals("length after add " + i, i + 1, src.getLength()); } @@ -144,11 +152,11 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertNotSame("array after larger setLength", array, array2); assertEquals("array length after larger setLength", largerLength, array2.length); for (int i = 0; i < largerLength; i++) { - final int v = src.get(i); + final int value = i; if (i < DEFAULT_CAPACITY) { - assertEquals("value at " + i, i, v); + assertEquals("value at " + i, value, src.get(i)); } else { - assertEquals("value at " + i, 0, v); + assertEquals("value at " + i, 0, src.get(i)); } } @@ -159,7 +167,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { assertSame("array after smaller setLength", array2, array3); assertEquals("array length after smaller setLength", largerLength, array3.length); for (int i = 0; i < smallerLength; i++) { - assertEquals("value at " + i, i, src.get(i)); + final int value = i; + assertEquals("value at " + i, value, src.get(i)); } } @@ -167,7 +176,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); final int limit = DEFAULT_CAPACITY * 2 + 10; for (int i = 0; i < limit; i++) { - src.add(i); + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY); @@ -179,7 +189,8 @@ public class ResizableIntArrayTests extends AndroidTestCase { public void testCopy() { final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY); for (int i = 0; i < DEFAULT_CAPACITY; i++) { - src.add(i); + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY); @@ -204,119 +215,126 @@ public class ResizableIntArrayTests extends AndroidTestCase { } public void testAppend() { - final int srcLen = DEFAULT_CAPACITY; - final ResizableIntArray src = new ResizableIntArray(srcLen); - for (int i = 0; i < srcLen; i++) { - src.add(i); + final int srcLength = DEFAULT_CAPACITY; + final ResizableIntArray src = new ResizableIntArray(srcLength); + for (int i = 0; i < srcLength; i++) { + final int value = i; + src.add(value); } final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY * 2); final int[] array = dst.getPrimitiveArray(); - final int dstLen = DEFAULT_CAPACITY / 2; - for (int i = 0; i < dstLen; i++) { + final int dstLength = DEFAULT_CAPACITY / 2; + for (int i = 0; i < dstLength; i++) { final int value = -i - 1; dst.add(value); } final ResizableIntArray dstCopy = new ResizableIntArray(dst.getLength()); dstCopy.copy(dst); - dst.append(src, 0, 0); - assertEquals("length after append zero", dstLen, dst.getLength()); + final int startPos = 0; + dst.append(src, startPos, 0 /* length */); + assertEquals("length after append zero", dstLength, dst.getLength()); assertSame("array after append zero", array, dst.getPrimitiveArray()); - assertIntArrayEquals("values after append zero", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); + assertIntArrayEquals("values after append zero", dstCopy.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), startPos, dstLength); - dst.append(src, 0, srcLen); - assertEquals("length after append", dstLen + srcLen, dst.getLength()); + dst.append(src, startPos, srcLength); + assertEquals("length after append", dstLength + srcLength, dst.getLength()); assertSame("array after append", array, dst.getPrimitiveArray()); assertTrue("primitive length after append", - dst.getPrimitiveArray().length >= dstLen + srcLen); - assertIntArrayEquals("original values after append", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); - assertIntArrayEquals("appended values after append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen); + dst.getPrimitiveArray().length >= dstLength + srcLength); + assertIntArrayEquals("original values after append", dstCopy.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), startPos, dstLength); + assertIntArrayEquals("appended values after append", src.getPrimitiveArray(), startPos, + dst.getPrimitiveArray(), dstLength, srcLength); - dst.append(src, 0, srcLen); - assertEquals("length after 2nd append", dstLen + srcLen * 2, dst.getLength()); + dst.append(src, startPos, srcLength); + assertEquals("length after 2nd append", dstLength + srcLength * 2, dst.getLength()); assertNotSame("array after 2nd append", array, dst.getPrimitiveArray()); assertTrue("primitive length after 2nd append", - dst.getPrimitiveArray().length >= dstLen + srcLen * 2); + dst.getPrimitiveArray().length >= dstLength + srcLength * 2); assertIntArrayEquals("original values after 2nd append", - dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen); + dstCopy.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), startPos, + dstLength); assertIntArrayEquals("appended values after 2nd append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen); + src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength, + srcLength); assertIntArrayEquals("appended values after 2nd append", - src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen); + src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength + srcLength, + srcLength); } public void testFill() { - final int srcLen = DEFAULT_CAPACITY; - final ResizableIntArray src = new ResizableIntArray(srcLen); - for (int i = 0; i < srcLen; i++) { - src.add(i); + final int srcLength = DEFAULT_CAPACITY; + final ResizableIntArray src = new ResizableIntArray(srcLength); + for (int i = 0; i < srcLength; i++) { + final int value = i; + src.add(value); } final int[] array = src.getPrimitiveArray(); - final int startPos = srcLen / 3; - final int length = srcLen / 3; + final int startPos = srcLength / 3; + final int length = srcLength / 3; final int endPos = startPos + length; assertTrue(startPos >= 1); - final int value = 123; + final int fillValue = 123; try { - src.fill(value, -1, length); + src.fill(fillValue, -1 /* startPos */, length); fail("fill from -1 shouldn't succeed"); } catch (IllegalArgumentException e) { // success } try { - src.fill(value, startPos, -1); + src.fill(fillValue, startPos, -1 /* length */); fail("fill negative length shouldn't succeed"); } catch (IllegalArgumentException e) { // success } - src.fill(value, startPos, length); - assertEquals("length after fill", srcLen, src.getLength()); + src.fill(fillValue, startPos, length); + assertEquals("length after fill", srcLength, src.getLength()); assertSame("array after fill", array, src.getPrimitiveArray()); - for (int i = 0; i < srcLen; i++) { - final int v = src.get(i); + for (int i = 0; i < srcLength; i++) { + final int value = i; if (i >= startPos && i < endPos) { - assertEquals("new values after fill at " + i, value, v); + assertEquals("new values after fill at " + i, fillValue, src.get(i)); } else { - assertEquals("unmodified values after fill at " + i, i, v); + assertEquals("unmodified values after fill at " + i, value, src.get(i)); } } - final int length2 = srcLen * 2 - startPos; + final int length2 = srcLength * 2 - startPos; final int largeEnd = startPos + length2; - assertTrue(largeEnd > srcLen); - final int value2 = 456; - src.fill(value2, startPos, length2); + assertTrue(largeEnd > srcLength); + final int fillValue2 = 456; + src.fill(fillValue2, startPos, length2); assertEquals("length after large fill", largeEnd, src.getLength()); assertNotSame("array after large fill", array, src.getPrimitiveArray()); for (int i = 0; i < largeEnd; i++) { - final int v = src.get(i); + final int value = i; if (i >= startPos && i < largeEnd) { - assertEquals("new values after large fill at " + i, value2, v); + assertEquals("new values after large fill at " + i, fillValue2, src.get(i)); } else { - assertEquals("unmodified values after large fill at " + i, i, v); + assertEquals("unmodified values after large fill at " + i, value, src.get(i)); } } final int startPos2 = largeEnd + length2; final int endPos2 = startPos2 + length2; - final int value3 = 789; - src.fill(value3, startPos2, length2); + final int fillValue3 = 789; + src.fill(fillValue3, startPos2, length2); assertEquals("length after disjoint fill", endPos2, src.getLength()); for (int i = 0; i < endPos2; i++) { - final int v = src.get(i); + final int value = i; if (i >= startPos2 && i < endPos2) { - assertEquals("new values after disjoint fill at " + i, value3, v); + assertEquals("new values after disjoint fill at " + i, fillValue3, src.get(i)); } else if (i >= startPos && i < largeEnd) { - assertEquals("unmodified values after disjoint fill at " + i, value2, v); + assertEquals("unmodified values after disjoint fill at " + i, + fillValue2, src.get(i)); } else if (i < startPos) { - assertEquals("unmodified values after disjoint fill at " + i, i, v); + assertEquals("unmodified values after disjoint fill at " + i, value, src.get(i)); } else { - assertEquals("gap values after disjoint fill at " + i, 0, v); + assertEquals("gap values after disjoint fill at " + i, 0, src.get(i)); } } } @@ -346,12 +364,14 @@ public class ResizableIntArrayTests extends AndroidTestCase { final int limit = DEFAULT_CAPACITY * 10; final int shiftAmount = 20; for (int i = 0; i < limit; ++i) { - src.add(i, i); + final int value = i; + src.addAt(i, value); assertEquals("length after add at " + i, i + 1, src.getLength()); } src.shift(shiftAmount); for (int i = 0; i < limit - shiftAmount; ++i) { - assertEquals("value at " + i, i + shiftAmount, src.get(i)); + final int oldValue = i + shiftAmount; + assertEquals("value at " + i, oldValue, src.get(i)); } } } diff --git a/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java index 1ae22e307..3eb704093 100644 --- a/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java @@ -19,43 +19,10 @@ package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.inputmethod.latin.utils.ResourceUtils.DeviceOverridePatternSyntaxError; - import java.util.HashMap; @SmallTest public class ResourceUtilsTests extends AndroidTestCase { - public void testFindDefaultConstant() { - final String[] nullArray = null; - final String[] emptyArray = {}; - final String[] array = { - "HARDWARE=grouper,0.3", - "HARDWARE=mako,0.4", - ",defaultValue1", - "HARDWARE=manta,0.2", - ",defaultValue2", - }; - - try { - assertNull(ResourceUtils.findDefaultConstant(nullArray)); - assertNull(ResourceUtils.findDefaultConstant(emptyArray)); - assertEquals(ResourceUtils.findDefaultConstant(array), "defaultValue1"); - } catch (final DeviceOverridePatternSyntaxError e) { - fail(e.getMessage()); - } - - final String[] errorArray = { - "HARDWARE=grouper,0.3", - "no_comma" - }; - try { - final String defaultValue = ResourceUtils.findDefaultConstant(errorArray); - fail("exception should be thrown: defaultValue=" + defaultValue); - } catch (final DeviceOverridePatternSyntaxError e) { - assertEquals("Array element has no comma: no_comma", e.getMessage()); - } - } - public void testFindConstantForKeyValuePairsSimple() { final HashMap<String,String> anyKeyValue = CollectionUtils.newHashMap(); anyKeyValue.put("anyKey", "anyValue"); diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java new file mode 100644 index 000000000..ff1103e4f --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguagetUtilsTests.java @@ -0,0 +1,251 @@ +/* + * 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.utils; + +import android.content.Context; +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.RichInputMethodManager; + +import java.util.ArrayList; +import java.util.Locale; + +@SmallTest +public class SpacebarLanguagetUtilsTests extends AndroidTestCase { + // All input method subtypes of LatinIME. + private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList(); + + private RichInputMethodManager mRichImm; + private Resources mRes; + + InputMethodSubtype EN_US; + InputMethodSubtype EN_GB; + InputMethodSubtype ES_US; + InputMethodSubtype FR; + InputMethodSubtype FR_CA; + InputMethodSubtype FR_CH; + InputMethodSubtype DE; + InputMethodSubtype DE_CH; + InputMethodSubtype ZZ; + InputMethodSubtype DE_QWERTY; + InputMethodSubtype FR_QWERTZ; + InputMethodSubtype EN_US_AZERTY; + InputMethodSubtype EN_UK_DVORAK; + InputMethodSubtype ES_US_COLEMAK; + InputMethodSubtype ZZ_AZERTY; + InputMethodSubtype ZZ_PC; + + @Override + protected void setUp() throws Exception { + super.setUp(); + final Context context = getContext(); + RichInputMethodManager.init(context); + mRichImm = RichInputMethodManager.getInstance(); + mRes = context.getResources(); + SubtypeLocaleUtils.init(context); + + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + mSubtypesList.add(subtype); + } + + EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.US.toString(), "qwerty"); + EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.UK.toString(), "qwerty"); + ES_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "es_US", "spanish"); + FR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.FRENCH.toString(), "azerty"); + FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.CANADA_FRENCH.toString(), "qwerty"); + FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "fr_CH", "swiss"); + DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + Locale.GERMAN.toString(), "qwertz"); + DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "de_CH", "swiss"); + ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); + DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.GERMAN.toString(), "qwerty", null); + FR_QWERTZ = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.FRENCH.toString(), "qwertz", null); + EN_US_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.US.toString(), "azerty", null); + EN_UK_DVORAK = AdditionalSubtypeUtils.createAdditionalSubtype( + Locale.UK.toString(), "dvorak", null); + ES_US_COLEMAK = AdditionalSubtypeUtils.createAdditionalSubtype( + "es_US", "colemak", null); + ZZ_AZERTY = AdditionalSubtypeUtils.createAdditionalSubtype( + SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null); + ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype( + SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null); + } + + public void testAllFullDisplayNameForSpacebar() { + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + final String spacebarText = SpacebarLanguageUtils.getFullDisplayName(subtype); + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayName(subtype.getLocale()); + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + assertFalse(subtypeName, spacebarText.contains(languageName)); + } else { + assertTrue(subtypeName, spacebarText.contains(languageName)); + } + } + } + + public void testAllMiddleDisplayNameForSpacebar() { + for (final InputMethodSubtype subtype : mSubtypesList) { + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + final String spacebarText = SpacebarLanguageUtils.getMiddleDisplayName(subtype); + if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + assertEquals(subtypeName, + SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText); + } else { + final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); + assertEquals(subtypeName, + SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), + spacebarText); + } + } + } + + // InputMethodSubtype's display name for spacebar text in its locale. + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ ------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss F Deutsch Deutsch (Schweiz) + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // zz azerty T AZERTY AZERTY + + private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { + @Override + protected Void job(final Resources res) { + assertEquals("en_US", "English (US)", + SpacebarLanguageUtils.getFullDisplayName(EN_US)); + assertEquals("en_GB", "English (UK)", + SpacebarLanguageUtils.getFullDisplayName(EN_GB)); + assertEquals("es_US", "Español (EE.UU.)", + SpacebarLanguageUtils.getFullDisplayName(ES_US)); + assertEquals("fr", "Français", + SpacebarLanguageUtils.getFullDisplayName(FR)); + assertEquals("fr_CA", "Français (Canada)", + SpacebarLanguageUtils.getFullDisplayName(FR_CA)); + assertEquals("fr_CH", "Français (Suisse)", + SpacebarLanguageUtils.getFullDisplayName(FR_CH)); + assertEquals("de", "Deutsch", + SpacebarLanguageUtils.getFullDisplayName(DE)); + assertEquals("de_CH", "Deutsch (Schweiz)", + SpacebarLanguageUtils.getFullDisplayName(DE_CH)); + assertEquals("zz", "QWERTY", + SpacebarLanguageUtils.getFullDisplayName(ZZ)); + + assertEquals("en_US", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_US)); + assertEquals("en_GB", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_GB)); + assertEquals("es_US", "Español", + SpacebarLanguageUtils.getMiddleDisplayName(ES_US)); + assertEquals("fr", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR)); + assertEquals("fr_CA", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_CA)); + assertEquals("fr_CH", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_CH)); + assertEquals("de", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE)); + assertEquals("de_CH", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE_CH)); + assertEquals("zz", "QWERTY", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ)); + return null; + } + }; + + private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() { + @Override + protected Void job(final Resources res) { + assertEquals("fr qwertz", "Français", + SpacebarLanguageUtils.getFullDisplayName(FR_QWERTZ)); + assertEquals("de qwerty", "Deutsch", + SpacebarLanguageUtils.getFullDisplayName(DE_QWERTY)); + assertEquals("en_US azerty", "English (US)", + SpacebarLanguageUtils.getFullDisplayName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "English (UK)", + SpacebarLanguageUtils.getFullDisplayName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "Español (EE.UU.)", + SpacebarLanguageUtils.getFullDisplayName(ES_US_COLEMAK)); + assertEquals("zz azerty", "AZERTY", + SpacebarLanguageUtils.getFullDisplayName(ZZ_AZERTY)); + assertEquals("zz pc", "PC", + SpacebarLanguageUtils.getFullDisplayName(ZZ_PC)); + + assertEquals("fr qwertz", "Français", + SpacebarLanguageUtils.getMiddleDisplayName(FR_QWERTZ)); + assertEquals("de qwerty", "Deutsch", + SpacebarLanguageUtils.getMiddleDisplayName(DE_QWERTY)); + assertEquals("en_US azerty", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "English", + SpacebarLanguageUtils.getMiddleDisplayName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "Español", + SpacebarLanguageUtils.getMiddleDisplayName(ES_US_COLEMAK)); + assertEquals("zz azerty", "AZERTY", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ_AZERTY)); + assertEquals("zz pc", "PC", + SpacebarLanguageUtils.getMiddleDisplayName(ZZ_PC)); + return null; + } + }; + + public void testPredefinedSubtypesForSpacebarInEnglish() { + testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); + } + + public void testAdditionalSubtypeForSpacebarInEnglish() { + testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); + } + + public void testPredefinedSubtypesForSpacebarInFrench() { + testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); + } + + public void testAdditionalSubtypeForSpacebarInFrench() { + testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); + } +} diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java index 4e396a1cf..2a4ead383 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java @@ -16,17 +16,17 @@ package com.android.inputmethod.latin.utils; -import com.android.inputmethod.latin.settings.SettingsValues; - import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import com.android.inputmethod.latin.Constants; + import java.util.Arrays; import java.util.List; import java.util.Locale; @SmallTest -public class StringUtilsTests extends AndroidTestCase { +public class StringAndJsonUtilsTests extends AndroidTestCase { public void testContainsInArray() { assertFalse("empty array", StringUtils.containsInArray("key", new String[0])); assertFalse("not in 1 element", StringUtils.containsInArray("key", new String[] { @@ -44,7 +44,7 @@ public class StringUtilsTests extends AndroidTestCase { })); } - public void testContainsInExtraValues() { + public void testContainsInCommaSplittableText() { assertFalse("null", StringUtils.containsInCommaSplittableText("key", null)); assertFalse("empty", StringUtils.containsInCommaSplittableText("key", "")); assertFalse("not in 1 element", @@ -56,7 +56,28 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue("in 2 elements", StringUtils.containsInCommaSplittableText("key", "key1,key")); } - public void testAppendToExtraValuesIfNotExists() { + public void testJoinCommaSplittableText() { + assertEquals("2 nulls", "", + StringUtils.joinCommaSplittableText(null, null)); + assertEquals("null and empty", "", + StringUtils.joinCommaSplittableText(null, "")); + assertEquals("empty and null", "", + StringUtils.joinCommaSplittableText("", null)); + assertEquals("2 empties", "", + StringUtils.joinCommaSplittableText("", "")); + assertEquals("text and null", "text", + StringUtils.joinCommaSplittableText("text", null)); + assertEquals("text and empty", "text", + StringUtils.joinCommaSplittableText("text", "")); + assertEquals("null and text", "text", + StringUtils.joinCommaSplittableText(null, "text")); + assertEquals("empty and text", "text", + StringUtils.joinCommaSplittableText("", "text")); + assertEquals("2 texts", "text1,text2", + StringUtils.joinCommaSplittableText("text1", "text2")); + } + + public void testAppendToCommaSplittableTextIfNotExists() { assertEquals("null", "key", StringUtils.appendToCommaSplittableTextIfNotExists("key", null)); assertEquals("empty", "key", @@ -77,7 +98,7 @@ public class StringUtilsTests extends AndroidTestCase { StringUtils.appendToCommaSplittableTextIfNotExists("key", "key1,key,key3")); } - public void testRemoveFromExtraValuesIfExists() { + public void testRemoveFromCommaSplittableTextIfExists() { assertEquals("null", "", StringUtils.removeFromCommaSplittableTextIfExists("key", null)); assertEquals("empty", "", StringUtils.removeFromCommaSplittableTextIfExists("key", "")); @@ -187,54 +208,47 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(StringUtils.isIdenticalAfterDowncase("")); } - public void testLooksValidForDictionaryInsertion() { - final SettingsValues settings = - SettingsValues.makeDummySettingsValuesForTest(Locale.ENGLISH); - assertTrue(StringUtils.looksValidForDictionaryInsertion("aochaueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("", settings)); - assertTrue(StringUtils.looksValidForDictionaryInsertion("ao-ch'aueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("2908743256", settings)); - assertTrue(StringUtils.looksValidForDictionaryInsertion("31aochaueo", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("akeo raeoch oerch .", settings)); - assertFalse(StringUtils.looksValidForDictionaryInsertion("!!!", settings)); - } - - private static void checkCapitalize(final String src, final String dst, final String separators, - final Locale locale) { - assertEquals(dst, StringUtils.capitalizeEachWord(src, separators, locale)); + private static void checkCapitalize(final String src, final String dst, + final int[] sortedSeparators, final Locale locale) { + assertEquals(dst, StringUtils.capitalizeEachWord(src, sortedSeparators, locale)); assert(src.equals(dst) - == StringUtils.isIdenticalAfterCapitalizeEachWord(src, separators)); + == StringUtils.isIdenticalAfterCapitalizeEachWord(src, sortedSeparators)); } + private static final int[] SPACE = { Constants.CODE_SPACE }; + private static final int[] SPACE_PERIOD = StringUtils.toSortedCodePointArray(" ."); + private static final int[] SENTENCE_SEPARATORS = + StringUtils.toSortedCodePointArray(" \n.!?*()&"); + private static final int[] WORD_SEPARATORS = StringUtils.toSortedCodePointArray(" \n.!?*,();&"); + public void testCapitalizeEachWord() { - checkCapitalize("", "", " ", Locale.ENGLISH); - checkCapitalize("test", "Test", " ", Locale.ENGLISH); - checkCapitalize(" test", " Test", " ", Locale.ENGLISH); - checkCapitalize("Test", "Test", " ", Locale.ENGLISH); - checkCapitalize(" Test", " Test", " ", Locale.ENGLISH); - checkCapitalize(".Test", ".test", " ", Locale.ENGLISH); - checkCapitalize(".Test", ".Test", " .", Locale.ENGLISH); - checkCapitalize(".Test", ".Test", ". ", Locale.ENGLISH); - checkCapitalize("test and retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test and retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test And Retest", "Test And Retest", " .", Locale.ENGLISH); - checkCapitalize("Test And.Retest ", "Test And.Retest ", " .", Locale.ENGLISH); - checkCapitalize("Test And.retest ", "Test And.Retest ", " .", Locale.ENGLISH); - checkCapitalize("Test And.retest ", "Test And.retest ", " ", Locale.ENGLISH); - checkCapitalize("Test And.Retest ", "Test And.retest ", " ", Locale.ENGLISH); - checkCapitalize("test and ietest", "Test And İetest", " .", new Locale("tr")); - checkCapitalize("test and ietest", "Test And Ietest", " .", Locale.ENGLISH); - checkCapitalize("Test&Retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); - checkCapitalize("Test&retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); - checkCapitalize("test&Retest", "Test&Retest", " \n.!?*()&", Locale.ENGLISH); + checkCapitalize("", "", SPACE, Locale.ENGLISH); + checkCapitalize("test", "Test", SPACE, Locale.ENGLISH); + checkCapitalize(" test", " Test", SPACE, Locale.ENGLISH); + checkCapitalize("Test", "Test", SPACE, Locale.ENGLISH); + checkCapitalize(" Test", " Test", SPACE, Locale.ENGLISH); + checkCapitalize(".Test", ".test", SPACE, Locale.ENGLISH); + checkCapitalize(".Test", ".Test", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("test and retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test and retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And Retest", "Test And Retest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.Retest ", "Test And.Retest ", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.retest ", "Test And.Retest ", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test And.retest ", "Test And.retest ", SPACE, Locale.ENGLISH); + checkCapitalize("Test And.Retest ", "Test And.retest ", SPACE, Locale.ENGLISH); + checkCapitalize("test and ietest", "Test And İetest", SPACE_PERIOD, new Locale("tr")); + checkCapitalize("test and ietest", "Test And Ietest", SPACE_PERIOD, Locale.ENGLISH); + checkCapitalize("Test&Retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); + checkCapitalize("Test&retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); + checkCapitalize("test&Retest", "Test&Retest", SENTENCE_SEPARATORS, Locale.ENGLISH); checkCapitalize("rest\nrecreation! And in the end...", - "Rest\nRecreation! And In The End...", " \n.!?*,();&", Locale.ENGLISH); + "Rest\nRecreation! And In The End...", WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("lorem ipsum dolor sit amet", "Lorem Ipsum Dolor Sit Amet", - " \n.,!?*()&;", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("Lorem!Ipsum (Dolor) Sit * Amet", "Lorem!Ipsum (Dolor) Sit * Amet", - " \n,.;!?*()&", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); checkCapitalize("Lorem!Ipsum (dolor) Sit * Amet", "Lorem!Ipsum (Dolor) Sit * Amet", - " \n,.;!?*()&", Locale.ENGLISH); + WORD_SEPARATORS, Locale.ENGLISH); } public void testLooksLikeURL() { @@ -271,13 +285,91 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(bytesStr.equals(bytesStr2)); } - public void testJsonStringUtils() { + public void testContainsOnlyWhitespace() { + assertTrue(StringUtils.containsOnlyWhitespace(" ")); + assertTrue(StringUtils.containsOnlyWhitespace("")); + assertTrue(StringUtils.containsOnlyWhitespace(" \n\t\t")); + // U+2002 : EN SPACE + // U+2003 : EM SPACE + // U+3000 : IDEOGRAPHIC SPACE (commonly "double-width space") + assertTrue(StringUtils.containsOnlyWhitespace("\u2002\u2003\u3000")); + assertFalse(StringUtils.containsOnlyWhitespace(" a ")); + assertFalse(StringUtils.containsOnlyWhitespace(". ")); + assertFalse(StringUtils.containsOnlyWhitespace(".")); + assertTrue(StringUtils.containsOnlyWhitespace("")); + } + + public void testJsonUtils() { final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 }; final List<Object> objArray = Arrays.asList(objs); - final String str = StringUtils.listToJsonStr(objArray); - final List<Object> newObjArray = StringUtils.jsonStrToList(str); + final String str = JsonUtils.listToJsonStr(objArray); + final List<Object> newObjArray = JsonUtils.jsonStrToList(str); for (int i = 0; i < objs.length; ++i) { assertEquals(objs[i], newObjArray.get(i)); } } + + public void testToCodePointArray() { + final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh\u0000\u2002\u2003\u3000xx"; + final int[] EXPECTED_RESULT = new int[] { 'a', 'b', 'c', 'd', 'e', 0x286D7, 'f', 'g', 'h', + 0, 0x2002, 0x2003, 0x3000, 'x', 'x'}; + final int[] codePointArray = StringUtils.toCodePointArray(STR_WITH_SUPPLEMENTARY_CHAR, 0, + STR_WITH_SUPPLEMENTARY_CHAR.length()); + assertEquals("toCodePointArray, size matches", codePointArray.length, + EXPECTED_RESULT.length); + for (int i = 0; i < EXPECTED_RESULT.length; ++i) { + assertEquals("toCodePointArray position " + i, codePointArray[i], EXPECTED_RESULT[i]); + } + } + + public void testCopyCodePointsAndReturnCodePointCount() { + final String STR_WITH_SUPPLEMENTARY_CHAR = "AbcDE\uD861\uDED7fGh\u0000\u2002\u3000あx"; + final int[] EXPECTED_RESULT = new int[] { 'A', 'b', 'c', 'D', 'E', 0x286D7, + 'f', 'G', 'h', 0, 0x2002, 0x3000, 'あ', 'x'}; + final int[] EXPECTED_RESULT_DOWNCASE = new int[] { 'a', 'b', 'c', 'd', 'e', 0x286D7, + 'f', 'g', 'h', 0, 0x2002, 0x3000, 'あ', 'x'}; + + int[] codePointArray = new int[50]; + int codePointCount = StringUtils.copyCodePointsAndReturnCodePointCount(codePointArray, + STR_WITH_SUPPLEMENTARY_CHAR, 0, + STR_WITH_SUPPLEMENTARY_CHAR.length(), false /* downCase */); + assertEquals("copyCodePointsAndReturnCodePointCount, size matches", codePointCount, + EXPECTED_RESULT.length); + for (int i = 0; i < codePointCount; ++i) { + assertEquals("copyCodePointsAndReturnCodePointCount position " + i, codePointArray[i], + EXPECTED_RESULT[i]); + } + + codePointCount = StringUtils.copyCodePointsAndReturnCodePointCount(codePointArray, + STR_WITH_SUPPLEMENTARY_CHAR, 0, + STR_WITH_SUPPLEMENTARY_CHAR.length(), true /* downCase */); + assertEquals("copyCodePointsAndReturnCodePointCount downcase, size matches", codePointCount, + EXPECTED_RESULT_DOWNCASE.length); + for (int i = 0; i < codePointCount; ++i) { + assertEquals("copyCodePointsAndReturnCodePointCount position " + i, codePointArray[i], + EXPECTED_RESULT_DOWNCASE[i]); + } + + final int JAVA_CHAR_COUNT = 8; + final int CODEPOINT_COUNT = 7; + codePointCount = StringUtils.copyCodePointsAndReturnCodePointCount(codePointArray, + STR_WITH_SUPPLEMENTARY_CHAR, 0, JAVA_CHAR_COUNT, false /* downCase */); + assertEquals("copyCodePointsAndReturnCodePointCount, size matches", codePointCount, + CODEPOINT_COUNT); + for (int i = 0; i < codePointCount; ++i) { + assertEquals("copyCodePointsAndReturnCodePointCount position " + i, codePointArray[i], + EXPECTED_RESULT[i]); + } + + boolean exceptionHappened = false; + codePointArray = new int[5]; + try { + codePointCount = StringUtils.copyCodePointsAndReturnCodePointCount(codePointArray, + STR_WITH_SUPPLEMENTARY_CHAR, 0, JAVA_CHAR_COUNT, false /* downCase */); + } catch (ArrayIndexOutOfBoundsException e) { + exceptionHappened = true; + } + assertTrue("copyCodePointsAndReturnCodePointCount throws when array is too small", + exceptionHappened); + } } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index 856b2dbda..ee345905c 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -20,9 +20,9 @@ import android.content.Context; import android.content.res.Resources; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import java.util.ArrayList; @@ -30,7 +30,7 @@ import java.util.Locale; @SmallTest public class SubtypeLocaleUtilsTests extends AndroidTestCase { - // Locale to subtypes list. + // All input method subtypes of LatinIME. private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList(); private RichInputMethodManager mRichImm; @@ -41,7 +41,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype ES_US; InputMethodSubtype FR; InputMethodSubtype FR_CA; + InputMethodSubtype FR_CH; InputMethodSubtype DE; + InputMethodSubtype DE_CH; InputMethodSubtype ZZ; InputMethodSubtype DE_QWERTY; InputMethodSubtype FR_QWERTZ; @@ -60,6 +62,13 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { mRes = context.getResources(); SubtypeLocaleUtils.init(context); + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); + final int subtypeCount = imi.getSubtypeCount(); + for (int index = 0; index < subtypeCount; index++) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + mSubtypesList.add(subtype); + } + EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.US.toString(), "qwerty"); EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( @@ -70,8 +79,12 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { Locale.FRENCH.toString(), "azerty"); FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.CANADA_FRENCH.toString(), "qwerty"); + FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "fr_CH", "swiss"); DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.GERMAN.toString(), "qwertz"); + DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "de_CH", "swiss"); ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype( @@ -88,19 +101,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "azerty", null); ZZ_PC = AdditionalSubtypeUtils.createAdditionalSubtype( SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty", null); - } public void testAllFullDisplayName() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - final String noLanguage = mRes.getString(R.string.subtype_no_language); - assertTrue(subtypeName, subtypeName.contains(noLanguage)); + final String layoutName = SubtypeLocaleUtils + .getKeyboardLayoutSetDisplayName(subtype); + assertTrue(subtypeName, subtypeName.contains(layoutName)); } else { - final String languageName = - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale()); assertTrue(subtypeName, subtypeName.contains(languageName)); } } @@ -110,10 +123,23 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("en_US", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US)); assertEquals("en_GB", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_GB)); assertEquals("es_US", "spanish", SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US)); - assertEquals("fr ", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR)); + assertEquals("fr", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR)); assertEquals("fr_CA", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CA)); - assertEquals("de ", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); - assertEquals("zz ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); + assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); + assertEquals("de", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); + assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); + assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); + + assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY)); + assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ)); + assertEquals("en_US azerty", "azerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_US_AZERTY)); + assertEquals("en_UK dvorak", "dvorak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(EN_UK_DVORAK)); + assertEquals("es_US colemak", "colemak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US_COLEMAK)); + assertEquals("zz azerty", "azerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ_AZERTY)); } // InputMethodSubtype's display name in system locale (en_US). @@ -125,7 +151,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // es_US spanish F Spanish (US) exception // fr azerty F French // fr_CA qwerty F French (Canada) + // fr_CH swiss F French (Switzerland) // de qwertz F German + // de_CH swiss F German (Switzerland) // zz qwerty F Alphabet (QWERTY) // fr qwertz T French (QWERTZ) // de qwerty T German (QWERTY) @@ -144,13 +172,17 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB)); assertEquals("es_US", "Spanish (US)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US)); - assertEquals("fr ", "French", + assertEquals("fr", "French", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "French (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); - assertEquals("de ", "German", + assertEquals("fr_CH", "French (Switzerland)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); + assertEquals("de", "German", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); - assertEquals("zz ", "Alphabet (QWERTY)", + assertEquals("de_CH", "German (Switzerland)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("zz", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; } @@ -162,17 +194,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { final RunInLocale<Void> tests = new RunInLocale<Void>() { @Override protected Void job(final Resources res) { - assertEquals("fr qwertz", "French (QWERTZ)", + assertEquals("fr qwertz", "French (QWERTZ)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ)); - assertEquals("de qwerty", "German (QWERTY)", + assertEquals("de qwerty", "German (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY)); assertEquals("en_US azerty", "English (US) (AZERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY)); - assertEquals("en_UK dvorak", "English (UK) (Dvorak)", + assertEquals("en_UK dvorak","English (UK) (Dvorak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK)); - assertEquals("es_US colemak","Spanish (US) (Colemak)", + assertEquals("es_US colemak", "Spanish (US) (Colemak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK)); - assertEquals("zz pc", "Alphabet (PC)", + assertEquals("zz azerty", "Alphabet (AZERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); + assertEquals("zz pc", "Alphabet (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); return null; } @@ -189,14 +223,16 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // es_US spanish F Espagnol (États-Unis) exception // fr azerty F Français // fr_CA qwerty F Français (Canada) + // fr_CH swiss F Français (Suisse) // de qwertz F Allemand - // zz qwerty F Aucune langue (QWERTY) + // de_CH swiss F Allemand (Suisse) + // zz qwerty F Alphabet latin (QWERTY) // fr qwertz T Français (QWERTZ) // de qwerty T Allemand (QWERTY) // en_US azerty T Anglais (États-Unis) (AZERTY) exception // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception // es_US colemak T Espagnol (États-Unis) (Colemak) exception - // zz pc T Alphabet (PC) + // zz pc T Alphabet latin (PC) public void testPredefinedSubtypesInFrenchSystemLocale() { final RunInLocale<Void> tests = new RunInLocale<Void>() { @@ -208,13 +244,17 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_GB)); assertEquals("es_US", "Espagnol (États-Unis)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US)); - assertEquals("fr ", "Français", + assertEquals("fr", "Français", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR)); assertEquals("fr_CA", "Français (Canada)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA)); - assertEquals("de ", "Allemand", + assertEquals("fr_CH", "Français (Suisse)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH)); + assertEquals("de", "Allemand", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); - assertEquals("zz ", "Alphabet latin (QWERTY)", + assertEquals("de_CH", "Allemand (Suisse)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("zz", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); return null; } @@ -226,17 +266,19 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { final RunInLocale<Void> tests = new RunInLocale<Void>() { @Override protected Void job(final Resources res) { - assertEquals("fr qwertz", "Français (QWERTZ)", + assertEquals("fr qwertz", "Français (QWERTZ)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_QWERTZ)); - assertEquals("de qwerty", "Allemand (QWERTY)", + assertEquals("de qwerty", "Allemand (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_QWERTY)); assertEquals("en_US azerty", "Anglais (États-Unis) (AZERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_US_AZERTY)); assertEquals("en_UK dvorak", "Anglais (Royaume-Uni) (Dvorak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK)); - assertEquals("es_US colemak","Espagnol (États-Unis) (Colemak)", + assertEquals("es_US colemak", "Espagnol (États-Unis) (Colemak)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK)); - assertEquals("zz pc", "Alphabet latin (PC)", + assertEquals("zz azerty", "Alphabet latin (AZERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); + assertEquals("zz pc", "Alphabet latin (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); return null; } @@ -244,144 +286,26 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { tests.runInLocale(mRes, Locale.FRENCH); } - public void testAllFullDisplayNameForSpacebar() { - for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); - final String spacebarText = SubtypeLocaleUtils.getFullDisplayName(subtype); - final String languageName = - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - assertFalse(subtypeName, spacebarText.contains(languageName)); - } else { - assertTrue(subtypeName, spacebarText.contains(languageName)); - } - } - } - - public void testAllMiddleDisplayNameForSpacebar() { - for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); - final String spacebarText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - assertEquals(subtypeName, - SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype), spacebarText); - } else { - assertEquals(subtypeName, - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()), - spacebarText); - } - } - } + public void testIsRtlLanguage() { + // Known Right-to-Left language subtypes. + final InputMethodSubtype ARABIC = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("ar", "arabic"); + assertNotNull("Arabic", ARABIC); + final InputMethodSubtype FARSI = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("fa", "farsi"); + assertNotNull("Farsi", FARSI); + final InputMethodSubtype HEBREW = mRichImm + .findSubtypeByLocaleAndKeyboardLayoutSet("iw", "hebrew"); + assertNotNull("Hebrew", HEBREW); - public void testAllShortDisplayNameForSpacebar() { for (final InputMethodSubtype subtype : mSubtypesList) { - final String subtypeName = - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype); - final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); - final String spacebarText = SubtypeLocaleUtils.getShortDisplayName(subtype); - final String languageCode = StringUtils.capitalizeFirstCodePoint( - locale.getLanguage(), locale); - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - assertEquals(subtypeName, "", spacebarText); + final String subtypeName = SubtypeLocaleUtils + .getSubtypeDisplayNameInSystemLocale(subtype); + if (subtype.equals(ARABIC) || subtype.equals(FARSI) || subtype.equals(HEBREW)) { + assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); } else { - assertEquals(subtypeName, languageCode, spacebarText); + assertFalse(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); } } } - - // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Short Middle Full - // ------ ------- - ---- --------- ---------------------- - // en_US qwerty F En English English (US) exception - // en_GB qwerty F En English English (UK) exception - // es_US spanish F Es Español Español (EE.UU.) exception - // fr azerty F Fr Français Français - // fr_CA qwerty F Fr Français Français (Canada) - // de qwertz F De Deutsch Deutsch - // zz qwerty F QWERTY QWERTY - // fr qwertz T Fr Français Français - // de qwerty T De Deutsch Deutsch - // en_US azerty T En English English (US) - // zz azerty T AZERTY AZERTY - - private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - assertEquals("en_US", "English (US)", SubtypeLocaleUtils.getFullDisplayName(EN_US)); - assertEquals("en_GB", "English (UK)", SubtypeLocaleUtils.getFullDisplayName(EN_GB)); - assertEquals("es_US", "Español (EE.UU.)", - SubtypeLocaleUtils.getFullDisplayName(ES_US)); - assertEquals("fr ", "Français", SubtypeLocaleUtils.getFullDisplayName(FR)); - assertEquals("fr_CA", "Français (Canada)", - SubtypeLocaleUtils.getFullDisplayName(FR_CA)); - assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getFullDisplayName(DE)); - assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getFullDisplayName(ZZ)); - - assertEquals("en_US", "English", SubtypeLocaleUtils.getMiddleDisplayName(EN_US)); - assertEquals("en_GB", "English", SubtypeLocaleUtils.getMiddleDisplayName(EN_GB)); - assertEquals("es_US", "Español", SubtypeLocaleUtils.getMiddleDisplayName(ES_US)); - assertEquals("fr ", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR)); - assertEquals("fr_CA", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CA)); - assertEquals("de ", "Deutsch", SubtypeLocaleUtils.getMiddleDisplayName(DE)); - assertEquals("zz ", "QWERTY", SubtypeLocaleUtils.getMiddleDisplayName(ZZ)); - - assertEquals("en_US", "En", SubtypeLocaleUtils.getShortDisplayName(EN_US)); - assertEquals("en_GB", "En", SubtypeLocaleUtils.getShortDisplayName(EN_GB)); - assertEquals("es_US", "Es", SubtypeLocaleUtils.getShortDisplayName(ES_US)); - assertEquals("fr ", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR)); - assertEquals("fr_CA", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_CA)); - assertEquals("de ", "De", SubtypeLocaleUtils.getShortDisplayName(DE)); - assertEquals("zz ", "", SubtypeLocaleUtils.getShortDisplayName(ZZ)); - return null; - } - }; - - private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() { - @Override - protected Void job(final Resources res) { - assertEquals("fr qwertz", "Français", - SubtypeLocaleUtils.getFullDisplayName(FR_QWERTZ)); - assertEquals("de qwerty", "Deutsch", - SubtypeLocaleUtils.getFullDisplayName(DE_QWERTY)); - assertEquals("en_US azerty", "English (US)", - SubtypeLocaleUtils.getFullDisplayName(EN_US_AZERTY)); - assertEquals("zz azerty", "AZERTY", - SubtypeLocaleUtils.getFullDisplayName(ZZ_AZERTY)); - - assertEquals("fr qwertz", "Français", - SubtypeLocaleUtils.getMiddleDisplayName(FR_QWERTZ)); - assertEquals("de qwerty", "Deutsch", - SubtypeLocaleUtils.getMiddleDisplayName(DE_QWERTY)); - assertEquals("en_US azerty", "English", - SubtypeLocaleUtils.getMiddleDisplayName(EN_US_AZERTY)); - assertEquals("zz azerty", "AZERTY", - SubtypeLocaleUtils.getMiddleDisplayName(ZZ_AZERTY)); - - assertEquals("fr qwertz", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_QWERTZ)); - assertEquals("de qwerty", "De", SubtypeLocaleUtils.getShortDisplayName(DE_QWERTY)); - assertEquals("en_US azerty", "En", - SubtypeLocaleUtils.getShortDisplayName(EN_US_AZERTY)); - assertEquals("zz azerty", "", SubtypeLocaleUtils.getShortDisplayName(ZZ_AZERTY)); - return null; - } - }; - - public void testPredefinedSubtypesForSpacebarInEnglish() { - testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); - } - - public void testAdditionalSubtypeForSpacebarInEnglish() { - testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.ENGLISH); - } - - public void testPredefinedSubtypesForSpacebarInFrench() { - testsPredefinedSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); - } - - public void testAdditionalSubtypeForSpacebarInFrench() { - testsAdditionalSubtypesForSpacebar.runInLocale(mRes, Locale.FRENCH); - } } diff --git a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java deleted file mode 100644 index 1944fd332..000000000 --- a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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.utils; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.inputmethod.latin.makedict.DictDecoder; -import com.android.inputmethod.latin.makedict.DictEncoder; -import com.android.inputmethod.latin.makedict.FormatSpec; -import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.Ver3DictDecoder; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; -import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; -import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; - -/** - * Unit tests for UserHistoryDictIOUtils - */ -@LargeTest -public class UserHistoryDictIOUtilsTests extends AndroidTestCase - implements BigramDictionaryInterface { - - private static final String TAG = UserHistoryDictIOUtilsTests.class.getSimpleName(); - private static final int UNIGRAM_FREQUENCY = 50; - private static final int BIGRAM_FREQUENCY = 100; - private static final ArrayList<String> NOT_HAVE_BIGRAM = new ArrayList<String>(); - private static final FormatSpec.FormatOptions FORMAT_OPTIONS = new FormatSpec.FormatOptions(2); - private static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - - /** - * Return same frequency for all words and bigrams - */ - @Override - public int getFrequency(String word1, String word2) { - if (word1 == null) return UNIGRAM_FREQUENCY; - return BIGRAM_FREQUENCY; - } - - // Utilities for Testing - - private void addWord(final String word, - final HashMap<String, ArrayList<String> > addedWords) { - if (!addedWords.containsKey(word)) { - addedWords.put(word, new ArrayList<String>()); - } - } - - private void addBigram(final String word1, final String word2, - final HashMap<String, ArrayList<String> > addedWords) { - addWord(word1, addedWords); - addWord(word2, addedWords); - addedWords.get(word1).add(word2); - } - - private void addBigramToBigramList(final String word1, final String word2, - final HashMap<String, ArrayList<String> > addedWords, - final UserHistoryDictionaryBigramList bigramList) { - bigramList.addBigram(null, word1); - bigramList.addBigram(word1, word2); - - addBigram(word1, word2, addedWords); - } - - private void checkWordInFusionDict(final FusionDictionary dict, final String word, - final ArrayList<String> expectedBigrams) { - final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word); - assertNotNull(ptNode); - assertTrue(ptNode.isTerminal()); - - for (final String bigram : expectedBigrams) { - assertNotNull(ptNode.getBigram(bigram)); - } - } - - private void checkWordsInFusionDict(final FusionDictionary dict, - final HashMap<String, ArrayList<String> > bigrams) { - for (final String word : bigrams.keySet()) { - if (bigrams.containsKey(word)) { - checkWordInFusionDict(dict, word, bigrams.get(word)); - } else { - checkWordInFusionDict(dict, word, NOT_HAVE_BIGRAM); - } - } - } - - private void checkWordInBigramList( - final UserHistoryDictionaryBigramList bigramList, final String word, - final ArrayList<String> expectedBigrams) { - // check unigram - final HashMap<String,Byte> unigramMap = bigramList.getBigrams(null); - assertTrue(unigramMap.containsKey(word)); - - // check bigrams - final ArrayList<String> actualBigrams = new ArrayList<String>( - bigramList.getBigrams(word).keySet()); - - Collections.sort(expectedBigrams); - Collections.sort(actualBigrams); - assertEquals(expectedBigrams, actualBigrams); - } - - private void checkWordsInBigramList(final UserHistoryDictionaryBigramList bigramList, - final HashMap<String, ArrayList<String> > addedWords) { - for (final String word : addedWords.keySet()) { - if (addedWords.containsKey(word)) { - checkWordInBigramList(bigramList, word, addedWords.get(word)); - } else { - checkWordInBigramList(bigramList, word, NOT_HAVE_BIGRAM); - } - } - } - - private void writeDictToFile(final File file, - final UserHistoryDictionaryBigramList bigramList) { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); - UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, bigramList, FORMAT_OPTIONS); - } - - private void readDictFromFile(final File file, final OnAddWordListener listener) { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, DictDecoder.USE_BYTEARRAY); - try { - dictDecoder.openDictBuffer(); - } catch (FileNotFoundException e) { - Log.e(TAG, "file not found", e); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - } - UserHistoryDictIOUtils.readDictionaryBinary(dictDecoder, listener); - } - - public void testGenerateFusionDictionary() { - final UserHistoryDictionaryBigramList originalList = new UserHistoryDictionaryBigramList(); - - final HashMap<String, ArrayList<String> > addedWords = - new HashMap<String, ArrayList<String>>(); - addBigramToBigramList("this", "is", addedWords, originalList); - addBigramToBigramList("this", "was", addedWords, originalList); - addBigramToBigramList("hello", "world", addedWords, originalList); - - final FusionDictionary fusionDict = - UserHistoryDictIOUtils.constructFusionDictionary(this, originalList); - - checkWordsInFusionDict(fusionDict, addedWords); - } - - public void testReadAndWrite() { - final Context context = getContext(); - - File file = null; - try { - file = File.createTempFile("testReadAndWrite", TEST_DICT_FILE_EXTENSION, - getContext().getCacheDir()); - } catch (IOException e) { - Log.d(TAG, "IOException while creating a temporary file", e); - } - assertNotNull(file); - - // make original dictionary - final UserHistoryDictionaryBigramList originalList = new UserHistoryDictionaryBigramList(); - final HashMap<String, ArrayList<String>> addedWords = CollectionUtils.newHashMap(); - addBigramToBigramList("this" , "is" , addedWords, originalList); - addBigramToBigramList("this" , "was" , addedWords, originalList); - addBigramToBigramList("is" , "not" , addedWords, originalList); - addBigramToBigramList("hello", "world", addedWords, originalList); - - // write to file - writeDictToFile(file, originalList); - - // make result dict. - final UserHistoryDictionaryBigramList resultList = new UserHistoryDictionaryBigramList(); - final OnAddWordListener listener = new OnAddWordListener() { - @Override - public void setUnigram(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq) { - Log.d(TAG, "in: setUnigram: " + word + "," + frequency); - resultList.addBigram(null, word, (byte)frequency); - } - @Override - public void setBigram(final String word1, final String word2, final int frequency) { - Log.d(TAG, "in: setBigram: " + word1 + "," + word2 + "," + frequency); - resultList.addBigram(word1, word2, (byte)frequency); - } - }; - - // load from file - readDictFromFile(file, listener); - checkWordsInBigramList(resultList, addedWords); - - // add new bigram - addBigramToBigramList("hello", "java", addedWords, resultList); - - // rewrite - writeDictToFile(file, resultList); - final UserHistoryDictionaryBigramList resultList2 = new UserHistoryDictionaryBigramList(); - final OnAddWordListener listener2 = new OnAddWordListener() { - @Override - public void setUnigram(final String word, final String shortcutTarget, - final int frequency, final int shortcutFreq) { - Log.d(TAG, "in: setUnigram: " + word + "," + frequency); - resultList2.addBigram(null, word, (byte)frequency); - } - @Override - public void setBigram(final String word1, final String word2, final int frequency) { - Log.d(TAG, "in: setBigram: " + word1 + "," + word2 + "," + frequency); - resultList2.addBigram(word1, word2, (byte)frequency); - } - }; - - // load from file - readDictFromFile(file, listener2); - checkWordsInBigramList(resultList2, addedWords); - } -} diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 3d09c0508..e12d7e0b5 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# HACK: Temporarily disable host tool build on Mac until the build system is ready for C++11. +LATINIME_HOST_OSNAME := $(shell uname -s) +ifneq ($(LATINIME_HOST_OSNAME), Darwin) # TODO: Remove this + LATINIME_DICTTOOL_AOSP_LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(LATINIME_DICTTOOL_AOSP_LOCAL_PATH) LATINIME_HOST_NATIVE_LIBNAME := liblatinime-aosp-dicttool-host @@ -25,12 +29,40 @@ include $(CLEAR_VARS) LATINIME_LOCAL_DIR := ../.. LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/java/src/com/android/inputmethod LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations -LATINIME_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin -MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_CORE_SOURCE_DIRECTORY)/makedict -USED_TARGETTED_UTILS := \ - $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \ - $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \ - $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java +MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/makedict +LATINIME_TESTS_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin + +# Dependencies for Dicttool. Most of these files are needed by BinaryDictionary.java. Note that +# a significant part of the dependencies are mocked in the compat/ directory, with empty or +# nearly-empty implementations, for parts that we don't use in Dicttool. +LATINIME_SRC_FILES_FOR_DICTTOOL := \ + event/Combiner.java \ + event/Event.java \ + latin/BinaryDictionary.java \ + latin/DicTraverseSession.java \ + latin/Dictionary.java \ + latin/InputPointers.java \ + latin/LastComposedWord.java \ + latin/LatinImeLogger.java \ + latin/SuggestedWords.java \ + latin/WordComposer.java \ + latin/settings/NativeSuggestOptions.java \ + latin/utils/BinaryDictionaryUtils.java \ + latin/utils/CollectionUtils.java \ + latin/utils/CombinedFormatUtils.java \ + latin/utils/CoordinateUtils.java \ + latin/utils/FileUtils.java \ + latin/utils/JniUtils.java \ + latin/utils/LocaleUtils.java \ + latin/utils/ResizableIntArray.java \ + latin/utils/StringUtils.java + +LATINIME_TEST_SRC_FILES_FOR_DICTTOOL := \ + utils/ByteArrayDictBuffer.java + +USED_TARGETED_SRCS := \ + $(addprefix $(LATINIME_BASE_SOURCE_DIRECTORY)/, $(LATINIME_SRC_FILES_FOR_DICTTOOL)) \ + $(addprefix $(LATINIME_TESTS_SOURCE_DIRECTORY)/, $(LATINIME_TEST_SRC_FILES_FOR_DICTTOOL)) DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \ $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin/makedict/ @@ -43,12 +75,11 @@ LOCAL_ANNOTATIONS_SRC_FILES := \ LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \ $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \ - $(LOCAL_ANNOTATIONS_SRC_FILES) \ - $(LATINIME_CORE_SOURCE_DIRECTORY)/Constants.java \ - $(call all-java-files-under, tests) \ - $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY)) \ $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIRECTORY)) \ - $(USED_TARGETTED_UTILS) + $(LOCAL_ANNOTATIONS_SRC_FILES) $(USED_TARGETED_SRCS) \ + $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/Constants.java \ + $(call all-java-files-under, tests) \ + $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY)) LOCAL_JAVA_LIBRARIES := junit LOCAL_ADDITIONAL_DEPENDENCIES := $(LATINIME_HOST_NATIVE_LIBNAME) @@ -58,6 +89,9 @@ LOCAL_MODULE := dicttool_aosp include $(BUILD_HOST_JAVA_LIBRARY) include $(LOCAL_PATH)/etc/Android.mk +endif # Darwin - TODO: Remove this + # Clear our private variables LATINIME_DICTTOOL_AOSP_LOCAL_PATH := LATINIME_LOCAL_DIR := +LATINIME_HOST_OSNAME := diff --git a/tools/dicttool/NativeLib.mk b/tools/dicttool/NativeLib.mk index a3d3c0295..74034482b 100644 --- a/tools/dicttool/NativeLib.mk +++ b/tools/dicttool/NativeLib.mk @@ -13,6 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +# HACK: Temporarily disable host tool build on Mac until the build system is ready for C++11. +LATINIME_HOST_OSNAME := $(shell uname -s) +ifneq ($(LATINIME_HOST_OSNAME), Darwin) # TODO: Remove this + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -20,24 +24,22 @@ include $(CLEAR_VARS) LATINIME_DIR_RELATIVE_TO_DICTTOOL := ../.. -ifneq ($(strip $(HOST_JDK_IS_64BIT_VERSION)),) -LOCAL_CFLAGS += -m64 -LOCAL_LDFLAGS += -m64 -endif #HOST_JDK_IS_64BIT_VERSION +ifeq ($(FLAG_DBG), true) + $(warning Making debug version of native library) + LOCAL_CFLAGS += -DFLAG_DBG -funwind-tables -fno-inline +endif #FLAG_DBG + +LOCAL_CFLAGS += -DHOST_TOOL -fPIC -Wno-deprecated -Wno-unused-parameter -Wno-unused-function -LOCAL_CFLAGS += -DHOST_TOOL -fPIC -LOCAL_NO_DEFAULT_COMPILER_FLAGS := true +LOCAL_CLANG := true +# For C++11 +LOCAL_CFLAGS += -std=c++11 LATINIME_NATIVE_JNI_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni LATINIME_NATIVE_SRC_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni/src LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(LATINIME_NATIVE_SRC_DIR) -# Used in jni_common.cpp to avoid registering useless methods. -LATIN_IME_JNI_SRC_FILES := \ - com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \ - jni_common.cpp - -LATIN_IME_CORE_SRC_FILES := +include $(LOCAL_PATH)/$(LATINIME_NATIVE_JNI_DIR)/NativeFileList.mk LOCAL_SRC_FILES := \ $(addprefix $(LATINIME_NATIVE_JNI_DIR)/, $(LATIN_IME_JNI_SRC_FILES)) \ @@ -47,5 +49,9 @@ LOCAL_MODULE := $(LATINIME_HOST_NATIVE_LIBNAME) include $(BUILD_HOST_SHARED_LIBRARY) +endif # Darwin - TODO: Remove this + # Clear our private variables +include $(LOCAL_PATH)/$(LATINIME_NATIVE_JNI_DIR)/CleanupNativeFileList.mk LATINIME_DIR_RELATIVE_TO_DICTTOOL := ../.. +LATINIME_HOST_OSNAME := diff --git a/java/src/com/android/inputmethod/event/EventDecoderSpec.java b/tools/dicttool/compat/android/content/SharedPreferences.java index 303b4b4c9..cfeb1532d 100644 --- a/java/src/com/android/inputmethod/event/EventDecoderSpec.java +++ b/tools/dicttool/compat/android/content/SharedPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2013 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,13 +14,10 @@ * limitations under the License. */ -package com.android.inputmethod.event; +package android.content; -/** - * Class describing a decoder chain. This will depend on the language and the input medium (soft - * or hard keyboard for example). - */ -public class EventDecoderSpec { - public EventDecoderSpec() { +public class SharedPreferences { + public interface OnSharedPreferenceChangeListener { + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key); } } diff --git a/tools/dicttool/compat/android/graphics/Rect.java b/tools/dicttool/compat/android/graphics/Rect.java new file mode 100644 index 000000000..c7b61d759 --- /dev/null +++ b/tools/dicttool/compat/android/graphics/Rect.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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 android.graphics; + +public class Rect { +} diff --git a/tools/dicttool/compat/android/text/TextUtils.java b/tools/dicttool/compat/android/text/TextUtils.java new file mode 100644 index 000000000..5a94b7d4c --- /dev/null +++ b/tools/dicttool/compat/android/text/TextUtils.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 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 android.text; + +public class TextUtils { + private TextUtils() { /* cannot be instantiated */ } + + /** + * Returns true if the string is null or 0-length. + * @param str the string to be examined + * @return true if str is null or zero length + */ + public static boolean isEmpty(CharSequence str) { + if (str == null || str.length() == 0) + return true; + else + return false; + } + + /** + * Returns true if a and b are equal, including if they are both null. + * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if + * both the arguments were instances of String.</i></p> + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return true if a and b are equal + */ + public static boolean equals(CharSequence a, CharSequence b) { + if (a == b) return true; + int length; + if (a != null && b != null && (length = a.length()) == b.length()) { + if (a instanceof String && b instanceof String) { + return a.equals(b); + } else { + for (int i = 0; i < length; i++) { + if (a.charAt(i) != b.charAt(i)) return false; + } + return true; + } + } + return false; + } + + /** + * Returns list of multiple {@link CharSequence} joined into a single + * {@link CharSequence} separated by localized delimiter such as ", ". + * + * @hide + */ + public static CharSequence join(Iterable<CharSequence> list) { + final CharSequence delimiter = ", "; + return join(delimiter, list); + } + + /** + * Returns a string containing the tokens joined by delimiters. + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + public static String join(CharSequence delimiter, Object[] tokens) { + StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + + /** + * Returns a string containing the tokens joined by delimiters. + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + public static String join(CharSequence delimiter, Iterable tokens) { + StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + +} diff --git a/tools/dicttool/compat/android/util/Log.java b/tools/dicttool/compat/android/util/Log.java index b3b6dd847..9410e74a2 100644 --- a/tools/dicttool/compat/android/util/Log.java +++ b/tools/dicttool/compat/android/util/Log.java @@ -25,13 +25,19 @@ public class Log { public static void d(final String tag, final String message) { System.out.println(tag + " : " + message); } - public static void d(final String tag, final String message, final Throwable e) { - System.out.println(tag + " : " + message + " : " + e); + public static void d(final String tag, final String message, final Throwable t) { + System.out.println(tag + " : " + message + " : " + t); } public static void e(final String tag, final String message) { d(tag, message); } - public static void e(final String tag, final String message, final Throwable e) { - d(tag, message, e); + public static void e(final String tag, final String message, final Throwable t) { + d(tag, message, t); + } + public static void w(final String tag, final String message) { + d(tag, message); + } + public static void w(final String tag, final String message, final Throwable t) { + d(tag, message, t); } } diff --git a/tools/dicttool/compat/android/util/Pair.java b/tools/dicttool/compat/android/util/Pair.java new file mode 100644 index 000000000..5bf34848d --- /dev/null +++ b/tools/dicttool/compat/android/util/Pair.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 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 android.util; + +import java.util.Arrays; + +public class Pair<T1, T2> { + public final T1 mFirst; + public final T2 mSecond; + + public Pair(final T1 first, final T2 second) { + mFirst = first; + mSecond = second; + } + + @Override + public int hashCode() { + return Arrays.hashCode(new Object[] { mFirst, mSecond }); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof Pair)) return false; + Pair<?, ?> p = (Pair<?, ?>)o; + return ((mFirst == null && p.mFirst == null) || mFirst.equals(p.mFirst)) + && ((mSecond == null && p.mSecond == null) || mSecond.equals(p.mSecond)); + } +} diff --git a/tools/dicttool/compat/android/util/SparseIntArray.java b/tools/dicttool/compat/android/util/SparseIntArray.java new file mode 100644 index 000000000..ac8a04ceb --- /dev/null +++ b/tools/dicttool/compat/android/util/SparseIntArray.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 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 android.util; + +public class SparseIntArray { + private final SparseArray<Integer> mArray; + + public SparseIntArray() { + this(10); + } + + public SparseIntArray(final int initialCapacity) { + mArray = new SparseArray<Integer>(initialCapacity); + } + + public int size() { + return mArray.size(); + } + + public void clear() { + mArray.clear(); + } + + public void put(final int key, final int value) { + mArray.put(key, value); + } + + public int get(final int key) { + return get(key, 0); + } + + public int get(final int key, final int valueIfKeyNotFound) { + return mArray.get(key, valueIfKeyNotFound); + } + + public int indexOfKey(final int key) { + return mArray.indexOfKey(key); + } + + public int keyAt(final int index) { + return mArray.keyAt(index); + } +} diff --git a/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java b/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java new file mode 100644 index 000000000..fbce72556 --- /dev/null +++ b/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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 android.view.inputmethod; + +public class CompletionInfo { + public final String getText() { return ""; } +} diff --git a/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java b/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java new file mode 100644 index 000000000..9c7118118 --- /dev/null +++ b/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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 android.view.inputmethod; + +public class EditorInfo { +} diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java new file mode 100644 index 000000000..b68df1ce7 --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 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.event; + +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.util.ArrayList; + +public class CombinerChain { + private StringBuilder mComposingWord = new StringBuilder(); + public CombinerChain(final Combiner... combinerList) {} + + public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { + mComposingWord.append(newEvent.getTextToCommit()); + } + + public CharSequence getComposingWordWithCombiningFeedback() { + return mComposingWord; + } + + public void reset() { + mComposingWord.setLength(0); + } +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java new file mode 100644 index 000000000..1e63bb526 --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 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; + +public class Key { + public final int getX() { return 0; } + public final int getY() { return 0; } + public final int getWidth() { return 0; } + public final int getHeight() { return 0; } +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java new file mode 100644 index 000000000..61b209f4d --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013 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; + +public class Keyboard { + private final Key KEY = new Key(); + public final Key getKey(final int i) { return KEY; } +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java new file mode 100644 index 000000000..561b6637c --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 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; + +public class ProximityInfo { + public long getNativeProximityInfo() { return 0l; } + private static native long setProximityInfoNative(String locale, + int displayWidth, int displayHeight, int gridWidth, int gridHeight, + int mostCommonKeyWidth, int mostCommonKeyHeight, int[] proximityCharsArray, + int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths, + int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs, + float[] sweetSpotCenterYs, float[] sweetSpotRadii); + private static native void releaseProximityInfoNative(long nativeProximityInfo); +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java b/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java new file mode 100644 index 000000000..e7aa340fb --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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; + +public class LatinIME { +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java b/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java index c68bdaabf..d6d5e2d61 100644 --- a/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java +++ b/tools/dicttool/compat/com/android/inputmethod/latin/define/JniLibName.java @@ -21,5 +21,5 @@ public final class JniLibName { // This class is not publicly instantiable. } - public static final String JNI_LIB_NAME = "latinime-dicttool-host"; + public static final String JNI_LIB_NAME = "latinime-aosp-dicttool-host"; } diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java b/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java new file mode 100644 index 000000000..6a430d57d --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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.settings; + +public class AdditionalFeaturesSettingUtils { + public static final int ADDITIONAL_FEATURES_SETTINGS_SIZE = 0; +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/utils/LanguageModelParam.java b/tools/dicttool/compat/com/android/inputmethod/latin/utils/LanguageModelParam.java new file mode 100644 index 000000000..f4ca94a81 --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/utils/LanguageModelParam.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 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.utils; + +public final class LanguageModelParam { +} diff --git a/tools/dicttool/etc/dicttool_aosp b/tools/dicttool/etc/dicttool_aosp index 65a1c3a1c..09d65c691 100755 --- a/tools/dicttool/etc/dicttool_aosp +++ b/tools/dicttool/etc/dicttool_aosp @@ -68,5 +68,14 @@ else libpath="$frameworkdir/$lib" fi +# Check if the host Java executable supports a 32-bit JVM. It needs to do because the JNI +# library is 32-bit. +${DICTTOOL_JAVA-java} -d32 -version > /dev/null 2>&1 +if [[ $? != 0 ]] ; then + echo Please specify a Java executable that supports a 32-bit JVM as DICTTOOL_JAVA. + exit 1 +fi + # might need more memory, e.g. -Xmx128M -exec java -ea -classpath "$libpath":"$jarpath" -Djava.library.path="$libdir" "$classname" "$@" +exec ${DICTTOOL_JAVA-java} -d32 -ea -classpath "$libpath":"$jarpath" \ + -Djava.library.path="$libdir" "$classname" "$@" diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java index e571bc21d..f9771c8dd 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.DictDecoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; @@ -191,14 +192,15 @@ public final class BinaryDictOffdeviceUtils { return CombinedInputOutput.readDictionaryCombined( new BufferedInputStream(new FileInputStream(decodedSpec.mFile))); } else { - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodedSpec.mFile, + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder( + decodedSpec.mFile, 0, decodedSpec.mFile.length(), DictDecoder.USE_BYTEARRAY); if (report) { System.out.println("Format : Binary dictionary format"); System.out.println("Packaging : " + decodedSpec.describeChain()); System.out.println("Uncompressed size : " + decodedSpec.mFile.length()); } - return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */); + return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); } } } catch (IOException e) { diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java index 4b6716936..391328fda 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java @@ -17,11 +17,13 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.makedict.Word; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; +import com.android.inputmethod.latin.utils.CombinedFormatUtils; import java.io.BufferedReader; import java.io.File; @@ -41,18 +43,10 @@ import java.util.TreeSet; * All functions in this class are static. */ public class CombinedInputOutput { - - private static final String DICTIONARY_TAG = "dictionary"; - private static final String BIGRAM_TAG = "bigram"; - private static final String SHORTCUT_TAG = "shortcut"; - private static final String FREQUENCY_TAG = "f"; - private static final String WORD_TAG = "word"; - private static final String NOT_A_WORD_TAG = "not_a_word"; private static final String WHITELIST_TAG = "whitelist"; private static final String OPTIONS_TAG = "options"; - private static final String GERMAN_UMLAUT_PROCESSING_OPTION = "german_umlaut_processing"; - private static final String FRENCH_LIGATURE_PROCESSING_OPTION = "french_ligature_processing"; private static final String COMMENT_LINE_STARTER = "#"; + private static final int HISTORICAL_INFO_ELEMENT_COUNT = 3; /** * Basic test to find out whether the file is in the combined format or not. @@ -70,7 +64,8 @@ public class CombinedInputOutput { while (firstLine.startsWith(COMMENT_LINE_STARTER)) { firstLine = reader.readLine(); } - return firstLine.matches("^" + DICTIONARY_TAG + "=[^:]+(:[^=]+=[^:]+)*"); + return firstLine.matches( + "^" + CombinedFormatUtils.DICTIONARY_TAG + "=[^:]+(:[^=]+=[^:]+)*"); } catch (FileNotFoundException e) { return false; } catch (IOException e) { @@ -112,28 +107,25 @@ public class CombinedInputOutput { attributes.put(keyValue[0], keyValue[1]); } - final boolean processUmlauts = - GERMAN_UMLAUT_PROCESSING_OPTION.equals(attributes.get(OPTIONS_TAG)); - final boolean processLigatures = - FRENCH_LIGATURE_PROCESSING_OPTION.equals(attributes.get(OPTIONS_TAG)); attributes.remove(OPTIONS_TAG); - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), new DictionaryOptions( - attributes, processUmlauts, processLigatures)); + final FusionDictionary dict = + new FusionDictionary(new PtNodeArray(), new DictionaryOptions(attributes)); String line; String word = null; - int freq = 0; + ProbabilityInfo probabilityInfo = new ProbabilityInfo(0); boolean isNotAWord = false; ArrayList<WeightedString> bigrams = new ArrayList<WeightedString>(); ArrayList<WeightedString> shortcuts = new ArrayList<WeightedString>(); while (null != (line = reader.readLine())) { if (line.startsWith(COMMENT_LINE_STARTER)) continue; final String args[] = line.trim().split(","); - if (args[0].matches(WORD_TAG + "=.*")) { + if (args[0].matches(CombinedFormatUtils.WORD_TAG + "=.*")) { if (null != word) { - dict.add(word, freq, shortcuts.isEmpty() ? null : shortcuts, isNotAWord); + dict.add(word, probabilityInfo, shortcuts.isEmpty() ? null : shortcuts, + isNotAWord); for (WeightedString s : bigrams) { - dict.setBigram(word, s.mWord, s.mFrequency); + dict.setBigram(word, s.mWord, s.mProbabilityInfo); } } if (!shortcuts.isEmpty()) shortcuts = new ArrayList<WeightedString>(); @@ -142,23 +134,35 @@ public class CombinedInputOutput { for (String param : args) { final String params[] = param.split("=", 2); if (2 != params.length) throw new RuntimeException("Wrong format : " + line); - if (WORD_TAG.equals(params[0])) { + if (CombinedFormatUtils.WORD_TAG.equals(params[0])) { word = params[1]; - } else if (FREQUENCY_TAG.equals(params[0])) { - freq = Integer.parseInt(params[1]); - } else if (NOT_A_WORD_TAG.equals(params[0])) { + } else if (CombinedFormatUtils.PROBABILITY_TAG.equals(params[0])) { + probabilityInfo = new ProbabilityInfo(Integer.parseInt(params[1]), + probabilityInfo.mTimestamp, probabilityInfo.mLevel, + probabilityInfo.mCount); + } else if (CombinedFormatUtils.HISTORICAL_INFO_TAG.equals(params[0])) { + final String[] historicalInfoParams = + params[1].split(CombinedFormatUtils.HISTORICAL_INFO_SEPARATOR); + if (historicalInfoParams.length != HISTORICAL_INFO_ELEMENT_COUNT) { + throw new RuntimeException("Wrong format (historical info) : " + line); + } + probabilityInfo = new ProbabilityInfo(probabilityInfo.mProbability, + Integer.parseInt(historicalInfoParams[0]), + Integer.parseInt(historicalInfoParams[1]), + Integer.parseInt(historicalInfoParams[2])); + } else if (CombinedFormatUtils.NOT_A_WORD_TAG.equals(params[0])) { isNotAWord = "true".equals(params[1]); } } - } else if (args[0].matches(SHORTCUT_TAG + "=.*")) { + } else if (args[0].matches(CombinedFormatUtils.SHORTCUT_TAG + "=.*")) { String shortcut = null; int shortcutFreq = 0; for (String param : args) { final String params[] = param.split("=", 2); if (2 != params.length) throw new RuntimeException("Wrong format : " + line); - if (SHORTCUT_TAG.equals(params[0])) { + if (CombinedFormatUtils.SHORTCUT_TAG.equals(params[0])) { shortcut = params[1]; - } else if (FREQUENCY_TAG.equals(params[0])) { + } else if (CombinedFormatUtils.PROBABILITY_TAG.equals(params[0])) { shortcutFreq = WHITELIST_TAG.equals(params[1]) ? FormatSpec.SHORTCUT_WHITELIST_FREQUENCY : Integer.parseInt(params[1]); @@ -169,29 +173,42 @@ public class CombinedInputOutput { } else { throw new RuntimeException("Wrong format : " + line); } - } else if (args[0].matches(BIGRAM_TAG + "=.*")) { + } else if (args[0].matches(CombinedFormatUtils.BIGRAM_TAG + "=.*")) { String secondWordOfBigram = null; - int bigramFreq = 0; + ProbabilityInfo bigramProbabilityInfo = new ProbabilityInfo(0); for (String param : args) { final String params[] = param.split("=", 2); if (2 != params.length) throw new RuntimeException("Wrong format : " + line); - if (BIGRAM_TAG.equals(params[0])) { + if (CombinedFormatUtils.BIGRAM_TAG.equals(params[0])) { secondWordOfBigram = params[1]; - } else if (FREQUENCY_TAG.equals(params[0])) { - bigramFreq = Integer.parseInt(params[1]); + } else if (CombinedFormatUtils.PROBABILITY_TAG.equals(params[0])) { + bigramProbabilityInfo = new ProbabilityInfo(Integer.parseInt(params[1]), + bigramProbabilityInfo.mTimestamp, bigramProbabilityInfo.mLevel, + bigramProbabilityInfo.mCount); + } else if (CombinedFormatUtils.HISTORICAL_INFO_TAG.equals(params[0])) { + final String[] historicalInfoParams = + params[1].split(CombinedFormatUtils.HISTORICAL_INFO_SEPARATOR); + if (historicalInfoParams.length != HISTORICAL_INFO_ELEMENT_COUNT) { + throw new RuntimeException("Wrong format (historical info) : " + line); + } + bigramProbabilityInfo = new ProbabilityInfo( + bigramProbabilityInfo.mProbability, + Integer.parseInt(historicalInfoParams[0]), + Integer.parseInt(historicalInfoParams[1]), + Integer.parseInt(historicalInfoParams[2])); } } if (null != secondWordOfBigram) { - bigrams.add(new WeightedString(secondWordOfBigram, bigramFreq)); + bigrams.add(new WeightedString(secondWordOfBigram, bigramProbabilityInfo)); } else { throw new RuntimeException("Wrong format : " + line); } } } if (null != word) { - dict.add(word, freq, shortcuts.isEmpty() ? null : shortcuts, isNotAWord); + dict.add(word, probabilityInfo, shortcuts.isEmpty() ? null : shortcuts, isNotAWord); for (WeightedString s : bigrams) { - dict.setBigram(word, s.mWord, s.mFrequency); + dict.setBigram(word, s.mWord, s.mProbabilityInfo); } } @@ -204,44 +221,16 @@ public class CombinedInputOutput { * @param destination a destination stream to write to. * @param dict the dictionary to write. */ - public static void writeDictionaryCombined(Writer destination, FusionDictionary dict) - throws IOException { - final TreeSet<Word> set = new TreeSet<Word>(); - for (Word word : dict) { - set.add(word); // This for ordering by frequency, then by asciibetic order - } - final HashMap<String, String> options = dict.mOptions.mAttributes; - destination.write(DICTIONARY_TAG + "="); - if (options.containsKey(DICTIONARY_TAG)) { - destination.write(options.get(DICTIONARY_TAG)); - options.remove(DICTIONARY_TAG); - } - if (dict.mOptions.mGermanUmlautProcessing) { - destination.write("," + OPTIONS_TAG + "=" + GERMAN_UMLAUT_PROCESSING_OPTION); - } else if (dict.mOptions.mFrenchLigatureProcessing) { - destination.write("," + OPTIONS_TAG + "=" + FRENCH_LIGATURE_PROCESSING_OPTION); - } - for (final String key : dict.mOptions.mAttributes.keySet()) { - final String value = dict.mOptions.mAttributes.get(key); - destination.write("," + key + "=" + value); + public static void writeDictionaryCombined( + final Writer destination, final FusionDictionary dict) throws IOException { + final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<WordProperty>(); + for (final WordProperty wordProperty : dict) { + // This for ordering by frequency, then by asciibetic order + wordPropertiesInDict.add(wordProperty); } - destination.write("\n"); - for (Word word : set) { - destination.write(" " + WORD_TAG + "=" + word.mWord + "," - + FREQUENCY_TAG + "=" + word.mFrequency - + (word.mIsNotAWord ? "," + NOT_A_WORD_TAG + "=true\n" : "\n")); - if (null != word.mShortcutTargets) { - for (WeightedString target : word.mShortcutTargets) { - destination.write(" " + SHORTCUT_TAG + "=" + target.mWord + "," - + FREQUENCY_TAG + "=" + target.mFrequency + "\n"); - } - } - if (null != word.mBigrams) { - for (WeightedString bigram : word.mBigrams) { - destination.write(" " + BIGRAM_TAG + "=" + bigram.mWord + "," - + FREQUENCY_TAG + "=" + bigram.mFrequency + "\n"); - } - } + destination.write(CombinedFormatUtils.formatAttributeMap(dict.mOptions.mAttributes)); + for (final WordProperty wordProperty : wordPropertiesInDict) { + destination.write(CombinedFormatUtils.formatWordProperty(wordProperty)); } destination.close(); } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java index 5c7e8b4f2..8e8ab19e0 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -17,13 +17,14 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.DictDecoder; import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.MakedictLog; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import com.android.inputmethod.latin.makedict.Ver4DictEncoder; import java.io.BufferedWriter; @@ -46,7 +47,6 @@ public class DictionaryMaker { static class Arguments { private static final String OPTION_VERSION_2 = "-2"; - private static final String OPTION_VERSION_3 = "-3"; private static final String OPTION_VERSION_4 = "-4"; private static final String OPTION_INPUT_SOURCE = "-s"; private static final String OPTION_INPUT_BIGRAM_XML = "-b"; @@ -158,10 +158,8 @@ public class DictionaryMaker { if (arg.charAt(0) == '-') { if (OPTION_VERSION_2.equals(arg)) { // Do nothing, this is the default - } else if (OPTION_VERSION_3.equals(arg)) { - outputBinaryFormatVersion = 3; } else if (OPTION_VERSION_4.equals(arg)) { - outputBinaryFormatVersion = 4; + outputBinaryFormatVersion = FormatSpec.VERSION4; } else if (OPTION_HELP.equals(arg)) { displayHelp(); } else { @@ -267,8 +265,8 @@ public class DictionaryMaker { private static FusionDictionary readBinaryFile(final String binaryFilename) throws FileNotFoundException, IOException, UnsupportedFormatException { final File file = new File(binaryFilename); - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file); - return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */); + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(file, 0, file.length()); + return dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); } /** @@ -358,10 +356,10 @@ public class DictionaryMaker { final File outputFile = new File(outputFilename); final FormatSpec.FormatOptions formatOptions = new FormatSpec.FormatOptions(version); final DictEncoder dictEncoder; - if (version == 4) { + if (version == FormatSpec.VERSION4) { dictEncoder = new Ver4DictEncoder(outputFile); } else { - dictEncoder = new Ver3DictEncoder(outputFile); + dictEncoder = new Ver2DictEncoder(outputFile); } dictEncoder.writeDictionary(dict, formatOptions); } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java index 66fd084cd..cd3d4d393 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java @@ -18,8 +18,8 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.makedict.Word; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; import java.util.Arrays; import java.util.ArrayList; @@ -85,18 +85,6 @@ public class Diff extends Dicttool.Command { private static void diffHeaders(final FusionDictionary dict0, final FusionDictionary dict1) { boolean hasDifferences = false; - if (dict0.mOptions.mFrenchLigatureProcessing != dict1.mOptions.mFrenchLigatureProcessing) { - System.out.println(" French ligature processing : " - + dict0.mOptions.mFrenchLigatureProcessing + " <=> " - + dict1.mOptions.mFrenchLigatureProcessing); - hasDifferences = true; - } - else if (dict0.mOptions.mGermanUmlautProcessing != dict1.mOptions.mGermanUmlautProcessing) { - System.out.println(" German umlaut processing : " - + dict0.mOptions.mGermanUmlautProcessing + " <=> " - + dict1.mOptions.mGermanUmlautProcessing); - hasDifferences = true; - } final HashMap<String, String> options1 = new HashMap<String, String>(dict1.mOptions.mAttributes); for (final String optionKey : dict0.mOptions.mAttributes.keySet()) { @@ -120,42 +108,47 @@ public class Diff extends Dicttool.Command { private static void diffWords(final FusionDictionary dict0, final FusionDictionary dict1) { boolean hasDifferences = false; - for (final Word word0 : dict0) { - final PtNode word1 = FusionDictionary.findWordInTree(dict1.mRootNodeArray, - word0.mWord); - if (null == word1) { + for (final WordProperty word0Property : dict0) { + final PtNode word1PtNode = FusionDictionary.findWordInTree(dict1.mRootNodeArray, + word0Property.mWord); + if (null == word1PtNode) { // This word is not in dict1 - System.out.println("Deleted: " + word0.mWord + " " + word0.mFrequency); + System.out.println("Deleted: " + word0Property.mWord + " " + + word0Property.getProbability()); hasDifferences = true; } else { // We found the word. Compare frequencies, shortcuts, bigrams - if (word0.mFrequency != word1.getFrequency()) { - System.out.println("Freq changed: " + word0.mWord + " " + word0.mFrequency - + " -> " + word1.getFrequency()); + if (word0Property.getProbability() != word1PtNode.getProbability()) { + System.out.println("Probability changed: " + word0Property.mWord + " " + + word0Property.getProbability() + " -> " + + word1PtNode.getProbability()); hasDifferences = true; } - if (word0.mIsNotAWord != word1.getIsNotAWord()) { - System.out.println("Not a word: " + word0.mWord + " " + word0.mIsNotAWord - + " -> " + word1.getIsNotAWord()); + if (word0Property.mIsNotAWord != word1PtNode.getIsNotAWord()) { + System.out.println("Not a word: " + word0Property.mWord + " " + + word0Property.mIsNotAWord + " -> " + word1PtNode.getIsNotAWord()); hasDifferences = true; } - if (word0.mIsBlacklistEntry != word1.getIsBlacklistEntry()) { - System.out.println("Blacklist: " + word0.mWord + " " + word0.mIsBlacklistEntry - + " -> " + word1.getIsBlacklistEntry()); + if (word0Property.mIsBlacklistEntry != word1PtNode.getIsBlacklistEntry()) { + System.out.println("Blacklist: " + word0Property.mWord + " " + + word0Property.mIsBlacklistEntry + " -> " + + word1PtNode.getIsBlacklistEntry()); hasDifferences = true; } - hasDifferences |= hasAttributesDifferencesAndPrintThemIfAny(word0.mWord, - "Bigram", word0.mBigrams, word1.getBigrams()); - hasDifferences |= hasAttributesDifferencesAndPrintThemIfAny(word0.mWord, - "Shortcut", word0.mShortcutTargets, word1.getShortcutTargets()); + hasDifferences |= hasAttributesDifferencesAndPrintThemIfAny(word0Property.mWord, + "Bigram", word0Property.mBigrams, word1PtNode.getBigrams()); + hasDifferences |= hasAttributesDifferencesAndPrintThemIfAny(word0Property.mWord, + "Shortcut", word0Property.mShortcutTargets, + word1PtNode.getShortcutTargets()); } } - for (final Word word1 : dict1) { - final PtNode word0 = FusionDictionary.findWordInTree(dict0.mRootNodeArray, - word1.mWord); - if (null == word0) { + for (final WordProperty word1Property : dict1) { + final PtNode word0PtNode = FusionDictionary.findWordInTree(dict0.mRootNodeArray, + word1Property.mWord); + if (null == word0PtNode) { // This word is not in dict0 - System.out.println("Added: " + word1.mWord + " " + word1.mFrequency); + System.out.println("Added: " + word1Property.mWord + " " + + word1Property.getProbability()); hasDifferences = true; } } @@ -171,7 +164,7 @@ public class Diff extends Dicttool.Command { if (null == list0) return false; for (final WeightedString attribute0 : list0) { System.out.println(type + " removed: " + word + " " + attribute0.mWord + " " - + attribute0.mFrequency); + + attribute0.getProbability()); } return true; } @@ -187,8 +180,8 @@ public class Diff extends Dicttool.Command { for (final WeightedString attribute1 : list1) { if (attribute0.mWord.equals(attribute1.mWord)) { System.out.println(type + " freq changed: " + word + " " - + attribute0.mWord + " " + attribute0.mFrequency + " -> " - + attribute1.mFrequency); + + attribute0.mWord + " " + attribute0.getProbability() + " -> " + + attribute1.getProbability()); list1.remove(attribute1); foundString = true; break; @@ -197,7 +190,7 @@ public class Diff extends Dicttool.Command { if (!foundString) { // We come here if we haven't found any matching string. System.out.println(type + " removed: " + word + " " + attribute0.mWord + " " - + attribute0.mFrequency); + + attribute0.getProbability()); } } else { list1.remove(attribute0); @@ -209,7 +202,7 @@ public class Diff extends Dicttool.Command { for (final WeightedString attribute1 : list1) { hasDifferences = true; System.out.println(type + " added: " + word + " " + attribute1.mWord + " " - + attribute1.mFrequency); + + attribute1.getProbability()); } return hasDifferences; } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java index 350f42772..9b2567fd3 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java @@ -19,8 +19,8 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.makedict.Word; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; import java.util.Arrays; import java.util.ArrayList; @@ -43,15 +43,16 @@ public class Info extends Dicttool.Command { int bigramCount = 0; int shortcutCount = 0; int whitelistCount = 0; - for (final Word w : dict) { + for (final WordProperty wordProperty : dict) { ++wordCount; - if (null != w.mBigrams) { - bigramCount += w.mBigrams.size(); + if (null != wordProperty.mBigrams) { + bigramCount += wordProperty.mBigrams.size(); } - if (null != w.mShortcutTargets) { - shortcutCount += w.mShortcutTargets.size(); - for (WeightedString shortcutTarget : w.mShortcutTargets) { - if (FormatSpec.SHORTCUT_WHITELIST_FREQUENCY == shortcutTarget.mFrequency) { + if (null != wordProperty.mShortcutTargets) { + shortcutCount += wordProperty.mShortcutTargets.size(); + for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + if (FormatSpec.SHORTCUT_WHITELIST_FREQUENCY + == shortcutTarget.getProbability()) { ++whitelistCount; } } @@ -71,7 +72,7 @@ public class Info extends Dicttool.Command { return; } System.out.println("Word: " + word); - System.out.println(" Freq: " + ptNode.getFrequency()); + System.out.println(" Freq: " + ptNode.getProbability()); if (ptNode.getIsNotAWord()) { System.out.println(" Is not a word"); } @@ -84,8 +85,9 @@ public class Info extends Dicttool.Command { } else { for (final WeightedString shortcutTarget : shortcutTargets) { System.out.println(" Shortcut target: " + shortcutTarget.mWord + " (" - + (FormatSpec.SHORTCUT_WHITELIST_FREQUENCY == shortcutTarget.mFrequency - ? "whitelist" : shortcutTarget.mFrequency) + ")"); + + (FormatSpec.SHORTCUT_WHITELIST_FREQUENCY + == shortcutTarget.getProbability() ? + "whitelist" : shortcutTarget.getProbability()) + ")"); } } final ArrayList<WeightedString> bigrams = ptNode.getBigrams(); @@ -93,7 +95,8 @@ public class Info extends Dicttool.Command { System.out.println(" No bigrams"); } else { for (final WeightedString bigram : bigrams) { - System.out.println(" Bigram: " + bigram.mWord + " (" + bigram.mFrequency + ")"); + System.out.println( + " Bigram: " + bigram.mWord + " (" + bigram.getProbability() + ")"); } } } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java index 9174238da..48817b1b1 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java @@ -18,7 +18,6 @@ package com.android.inputmethod.latin.dicttool; import com.android.inputmethod.latin.makedict.BinaryDictDecoderEncoderTests; import com.android.inputmethod.latin.makedict.BinaryDictEncoderFlattenTreeTests; -import com.android.inputmethod.latin.makedict.BinaryDictIOUtilsTests; import com.android.inputmethod.latin.makedict.FusionDictionaryTest; import java.lang.reflect.Constructor; @@ -31,15 +30,15 @@ import java.util.ArrayList; */ public class Test extends Dicttool.Command { public static final String COMMAND = "test"; + private static final int DEFAULT_MAX_UNIGRAMS = 1500; private long mSeed = System.currentTimeMillis(); - private int mMaxUnigrams = BinaryDictIOUtilsTests.DEFAULT_MAX_UNIGRAMS; + private int mMaxUnigrams = DEFAULT_MAX_UNIGRAMS; private static final Class<?>[] sClassesToTest = { BinaryDictOffdeviceUtilsTests.class, FusionDictionaryTest.class, BinaryDictDecoderEncoderTests.class, BinaryDictEncoderFlattenTreeTests.class, - BinaryDictIOUtilsTests.class }; private ArrayList<Method> mAllTestMethods = new ArrayList<Method>(); private ArrayList<String> mUsedTestMethods = new ArrayList<String>(); diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java index 4e99bf979..17e77dca1 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java @@ -16,11 +16,12 @@ package com.android.inputmethod.latin.dicttool; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.makedict.Word; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; +import com.android.inputmethod.latin.makedict.WeightedString; +import com.android.inputmethod.latin.makedict.WordProperty; import java.io.BufferedReader; import java.io.File; @@ -52,13 +53,11 @@ 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 PROBABILITY_ATTR = "f"; private static final String WORD_ATTR = "word"; private static final String NOT_A_WORD_ATTR = "not_a_word"; private static final String OPTIONS_KEY = "options"; - private static final String GERMAN_UMLAUT_PROCESSING_OPTION = "german_umlaut_processing"; - private static final String FRENCH_LIGATURE_PROCESSING_OPTION = "french_ligature_processing"; /** * SAX handler for a unigram XML file. @@ -68,6 +67,7 @@ public class XmlDictInputOutput { private static final int START = 1; private static final int WORD = 2; private static final int UNKNOWN = 3; + private static final int SHORTCUT_ONLY_WORD_PROBABILITY = 1; FusionDictionary mDictionary; int mState; // the state of the parser @@ -92,7 +92,8 @@ public class XmlDictInputOutput { final FusionDictionary dict = mDictionary; for (final String shortcutOnly : mShortcutsMap.keySet()) { if (dict.hasWord(shortcutOnly)) continue; - dict.add(shortcutOnly, 1, mShortcutsMap.get(shortcutOnly), true /* isNotAWord */); + dict.add(shortcutOnly, new ProbabilityInfo(SHORTCUT_ONLY_WORD_PROBABILITY), + mShortcutsMap.get(shortcutOnly), true /* isNotAWord */); } mDictionary = null; mShortcutsMap.clear(); @@ -109,7 +110,7 @@ public class XmlDictInputOutput { mWord = ""; for (int attrIndex = 0; attrIndex < attrs.getLength(); ++attrIndex) { final String attrName = attrs.getLocalName(attrIndex); - if (FREQUENCY_ATTR.equals(attrName)) { + if (PROBABILITY_ATTR.equals(attrName)) { mFreq = Integer.parseInt(attrs.getValue(attrIndex)); } } @@ -120,12 +121,8 @@ public class XmlDictInputOutput { attributes.put(attrName, attrs.getValue(attrIndex)); } final String optionsString = attributes.get(OPTIONS_KEY); - final boolean processUmlauts = - GERMAN_UMLAUT_PROCESSING_OPTION.equals(optionsString); - final boolean processLigatures = - FRENCH_LIGATURE_PROCESSING_OPTION.equals(optionsString); mDictionary = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(attributes, processUmlauts, processLigatures)); + new DictionaryOptions(attributes)); } else { mState = UNKNOWN; } @@ -144,7 +141,8 @@ public class XmlDictInputOutput { @Override public void endElement(String uri, String localName, String qName) { if (WORD == mState) { - mDictionary.add(mWord, mFreq, mShortcutsMap.get(mWord), false /* isNotAWord */); + mDictionary.add(mWord, new ProbabilityInfo(mFreq), mShortcutsMap.get(mWord), + false /* isNotAWord */); mState = START; } } @@ -325,7 +323,7 @@ public class XmlDictInputOutput { final ArrayList<WeightedString> bigramList = bigramMap.get(firstWord); for (final WeightedString bigram : bigramList) { if (!dict.hasWord(bigram.mWord)) continue; - dict.setBigram(firstWord, bigram.mWord, bigram.mFrequency); + dict.setBigram(firstWord, bigram.mWord, bigram.mProbabilityInfo); } } return dict; @@ -354,42 +352,38 @@ public class XmlDictInputOutput { */ public static void writeDictionaryXml(Writer destination, FusionDictionary dict) throws IOException { - final TreeSet<Word> set = new TreeSet<Word>(); - for (Word word : dict) { - set.add(word); + final TreeSet<WordProperty> wordPropertiesInDict = new TreeSet<WordProperty>(); + for (WordProperty wordProperty : dict) { + wordPropertiesInDict.add(wordProperty); } // TODO: use an XMLSerializer if this gets big destination.write("<wordlist format=\"2\""); - final HashMap<String, String> options = dict.mOptions.mAttributes; - if (dict.mOptions.mGermanUmlautProcessing) { - destination.write(" " + OPTIONS_KEY + "=\"" + GERMAN_UMLAUT_PROCESSING_OPTION + "\""); - } else if (dict.mOptions.mFrenchLigatureProcessing) { - destination.write(" " + OPTIONS_KEY + "=\"" + FRENCH_LIGATURE_PROCESSING_OPTION + "\""); - } for (final String key : dict.mOptions.mAttributes.keySet()) { final String value = dict.mOptions.mAttributes.get(key); destination.write(" " + key + "=\"" + value + "\""); } destination.write(">\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 - + (word.mIsNotAWord ? "\" " + NOT_A_WORD_ATTR + "=\"true" : "") + "\">"); - if (null != word.mShortcutTargets) { + for (WordProperty wordProperty : wordPropertiesInDict) { + destination.write(" <" + WORD_TAG + " " + WORD_ATTR + "=\"" + wordProperty.mWord + + "\" " + PROBABILITY_ATTR + "=\"" + wordProperty.getProbability() + + (wordProperty.mIsNotAWord ? "\" " + NOT_A_WORD_ATTR + "=\"true" : "") + + "\">"); + if (null != wordProperty.mShortcutTargets) { destination.write("\n"); - for (WeightedString target : word.mShortcutTargets) { - destination.write(" <" + SHORTCUT_TAG + " " + FREQUENCY_ATTR + "=\"" - + target.mFrequency + "\">" + target.mWord + "</" + SHORTCUT_TAG + for (WeightedString target : wordProperty.mShortcutTargets) { + destination.write(" <" + SHORTCUT_TAG + " " + PROBABILITY_ATTR + "=\"" + + target.getProbability() + "\">" + target.mWord + "</" + SHORTCUT_TAG + ">\n"); } destination.write(" "); } - if (null != word.mBigrams) { + if (null != wordProperty.mBigrams) { destination.write("\n"); - for (WeightedString bigram : word.mBigrams) { - destination.write(" <" + BIGRAM_TAG + " " + FREQUENCY_ATTR + "=\"" - + bigram.mFrequency + "\">" + bigram.mWord + "</" + BIGRAM_TAG + ">\n"); + for (WeightedString bigram : wordProperty.mBigrams) { + destination.write(" <" + BIGRAM_TAG + " " + PROBABILITY_ATTR + "=\"" + + bigram.getProbability() + "\">" + bigram.mWord + + "</" + BIGRAM_TAG + ">\n"); } destination.write(" "); } diff --git a/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java b/tools/dicttool/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index de91567c7..a4ad6b514 100644 --- a/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 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,14 +14,9 @@ * limitations under the License. */ -package com.android.inputmethod.event; +package com.android.inputmethod.latin.personalization; -/** - * A decoder for events from software keyboard, like the ones displayed by Latin IME. - */ -public class SoftwareKeyboardEventDecoder implements SoftwareEventDecoder { - @Override - public Event decodeSoftwareEvent() { - return null; +public class PersonalizationHelper { + public static void currentTimeChangedForTesting(final int currentTimestamp) { } } diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java index 1baeb7a47..4f1273bdc 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java @@ -16,15 +16,19 @@ package com.android.inputmethod.latin.dicttool; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.DictDecoder; import com.android.inputmethod.latin.makedict.DictEncoder; +import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; +import com.android.inputmethod.latin.makedict.ProbabilityInfo; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import junit.framework.TestCase; @@ -42,15 +46,21 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { private static final int TEST_FREQ = 37; // Some arbitrary value unlikely to happen by chance public void testGetRawDictWorks() throws IOException, UnsupportedFormatException { + final String VERSION = "1"; + final String LOCALE = "test"; + final String ID = "main:test"; + // Create a thrice-compressed dictionary file. - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); - dict.add("foo", TEST_FREQ, null, false /* isNotAWord */); - dict.add("fta", 1, null, false /* isNotAWord */); - dict.add("ftb", 1, null, false /* isNotAWord */); - dict.add("bar", 1, null, false /* isNotAWord */); - dict.add("fool", 1, null, false /* isNotAWord */); + final DictionaryOptions testOptions = new DictionaryOptions(new HashMap<String, String>()); + testOptions.mAttributes.put(DictionaryHeader.DICTIONARY_VERSION_KEY, VERSION); + testOptions.mAttributes.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, LOCALE); + testOptions.mAttributes.put(DictionaryHeader.DICTIONARY_ID_KEY, ID); + final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), testOptions); + dict.add("foo", new ProbabilityInfo(TEST_FREQ), null, false /* isNotAWord */); + dict.add("fta", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("ftb", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("bar", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("fool", new ProbabilityInfo(1), null, false /* isNotAWord */); final File dst = File.createTempFile("testGetRawDict", ".tmp"); dst.deleteOnExit(); @@ -59,7 +69,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { Compress.getCompressedStream( Compress.getCompressedStream( new BufferedOutputStream(new FileOutputStream(dst))))); - final DictEncoder dictEncoder = new Ver3DictEncoder(out); + final DictEncoder dictEncoder = new Ver2DictEncoder(out); dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); // Test for an actually compressed dictionary and its contents @@ -69,12 +79,18 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { assertEquals("Wrong decode spec", BinaryDictOffdeviceUtils.COMPRESSION, step); } assertEquals("Wrong decode spec", 3, decodeSpec.mDecoderSpec.size()); - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodeSpec.mFile); - final FusionDictionary resultDict = dictDecoder.readDictionaryBinary( - null /* dict : an optional dictionary to add words to, or null */, - false /* deleteDictIfBroken */); + final DictDecoder dictDecoder = BinaryDictIOUtils.getDictDecoder(decodeSpec.mFile, 0, + decodeSpec.mFile.length()); + final FusionDictionary resultDict = + dictDecoder.readDictionaryBinary(false /* deleteDictIfBroken */); + assertEquals("Wrong version attribute", VERSION, resultDict.mOptions.mAttributes.get( + DictionaryHeader.DICTIONARY_VERSION_KEY)); + assertEquals("Wrong locale attribute", LOCALE, resultDict.mOptions.mAttributes.get( + DictionaryHeader.DICTIONARY_LOCALE_KEY)); + assertEquals("Wrong id attribute", ID, resultDict.mOptions.mAttributes.get( + DictionaryHeader.DICTIONARY_ID_KEY)); assertEquals("Dictionary can't be read back correctly", - FusionDictionary.findWordInTree(resultDict.mRootNodeArray, "foo").getFrequency(), + FusionDictionary.findWordInTree(resultDict.mRootNodeArray, "foo").getProbability(), TEST_FREQ); } diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java index 55058238c..aa228e72c 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java @@ -16,7 +16,7 @@ package com.android.inputmethod.latin.makedict; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import junit.framework.TestCase; @@ -32,13 +32,12 @@ public class BinaryDictEncoderFlattenTreeTests extends TestCase { // that it does not contain any duplicates. public void testFlattenNodes() { final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); - dict.add("foo", 1, null, false /* isNotAWord */); - dict.add("fta", 1, null, false /* isNotAWord */); - dict.add("ftb", 1, null, false /* isNotAWord */); - dict.add("bar", 1, null, false /* isNotAWord */); - dict.add("fool", 1, null, false /* isNotAWord */); + new DictionaryOptions(new HashMap<String, String>())); + dict.add("foo", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("fta", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("ftb", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("bar", new ProbabilityInfo(1), null, false /* isNotAWord */); + dict.add("fool", new ProbabilityInfo(1), null, false /* isNotAWord */); final ArrayList<PtNodeArray> result = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray); assertEquals(4, result.size()); diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java index 659650a05..6e81c3f3a 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java @@ -16,11 +16,11 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; -import com.android.inputmethod.latin.makedict.Word; +import com.android.inputmethod.latin.makedict.WordProperty; import junit.framework.TestCase; @@ -87,8 +87,8 @@ public class FusionDictionaryTest extends TestCase { } private void dumpDict(final FusionDictionary dict) { - for (Word w : dict) { - System.out.println("Word " + dumpWord(w.mWord)); + for (WordProperty wordProperty : dict) { + System.out.println("Word " + dumpWord(wordProperty.mWord)); } } @@ -96,13 +96,12 @@ public class FusionDictionaryTest extends TestCase { // that it does not contain any duplicates. public void testFusion() { final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); + new DictionaryOptions(new HashMap<String, String>())); final long time = System.currentTimeMillis(); prepare(time); for (int i = 0; i < sWords.size(); ++i) { System.out.println("Adding in pos " + i + " : " + dumpWord(sWords.get(i))); - dict.add(sWords.get(i), 180, null, false); + dict.add(sWords.get(i), new ProbabilityInfo(180), null, false); dumpDict(dict); checkDictionary(dict, sWords, i); } diff --git a/tools/dicttool/tests/etc/test-dicttool.sh b/tools/dicttool/tests/etc/test-dicttool.sh index 5eb44fc85..f96db6816 100755 --- a/tools/dicttool/tests/etc/test-dicttool.sh +++ b/tools/dicttool/tests/etc/test-dicttool.sh @@ -18,7 +18,7 @@ echo "Usage:" 1>&2 echo " source $0" 1>&2 echo " or" 1>&2 echo " . $0" 1>&2 -exit 1 +if [[ ${BASH_SOURCE[0]} != $0 ]]; then return; else exit 1; fi fi find out -name "dicttool_aosp*" -exec rm -rf {} \; > /dev/null 2>&1 diff --git a/tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl b/tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl deleted file mode 100644 index 4cd9c236b..000000000 --- a/tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.content.Context; -import android.content.res.Resources; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.util.HashMap; - -/** - * !!!!! DO NOT EDIT THIS FILE !!!!! - * - * This file is generated by tools/make-keyboard-text. The base template file is - * tools/make-keyboard-text/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl - * - * This file must be updated when any text resources in keyboard layout files have been changed. - * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, - * and should be defined in - * tools/make-keyboard-text/res/values-<locale>/donottranslate-more-keys.xml - * - * To update this file, please run the following commands. - * $ cd $ANDROID_BUILD_TOP - * $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text - * $ make-keyboard-text -java packages/inputmethods/LatinIME/java/src - * - * The updated source file will be generated to the following path (this file). - * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ - * KeyboardTextsSet.java - */ -public final class KeyboardTextsSet { - // Language to texts map. - private static final HashMap<String, String[]> sLocaleToTextsMap = CollectionUtils.newHashMap(); - private static final HashMap<String, Integer> sNameToIdsMap = CollectionUtils.newHashMap(); - - private String[] mTexts; - // Resource name to text map. - private HashMap<String, String> mResourceNameToTextsMap = CollectionUtils.newHashMap(); - - public void setLanguage(final String language) { - mTexts = sLocaleToTextsMap.get(language); - if (mTexts == null) { - mTexts = LANGUAGE_DEFAULT; - } - } - - public void loadStringResources(final Context context) { - final int referenceId = context.getApplicationInfo().labelRes; - loadStringResourcesInternal(context, RESOURCE_NAMES, referenceId); - } - - @UsedForTesting - void loadStringResourcesInternal(final Context context, final String[] resourceNames, - final int referenceId) { - final Resources res = context.getResources(); - final String packageName = res.getResourcePackageName(referenceId); - for (final String resName : resourceNames) { - final int resId = res.getIdentifier(resName, "string", packageName); - mResourceNameToTextsMap.put(resName, res.getString(resId)); - } - } - - public String getText(final String name) { - String text = mResourceNameToTextsMap.get(name); - if (text != null) { - return text; - } - final Integer id = sNameToIdsMap.get(name); - if (id == null) throw new RuntimeException("Unknown label: " + name); - text = (id < mTexts.length) ? mTexts[id] : null; - return (text == null) ? LANGUAGE_DEFAULT[id] : text; - } - - private static final String[] RESOURCE_NAMES = { - // These texts' name should be aligned with the @string/<name> in values/strings.xml. - // Labels for action. - "label_go_key", - // "label_search_key", - "label_send_key", - "label_next_key", - "label_done_key", - "label_previous_key", - // Other labels. - "label_pause_key", - "label_wait_key", - }; - - private static final String[] NAMES = { - /* @NAMES@ */ - }; - - private static final String EMPTY = ""; - - /* Default texts */ - private static final String[] LANGUAGE_DEFAULT = { - /* @DEFAULT_TEXTS@ */ - }; - - /* @TEXTS@ */ - private static final Object[] LANGUAGES_AND_TEXTS = { - /* @LANGUAGES_AND_TEXTS@ */ - }; - - static { - int id = 0; - for (final String name : NAMES) { - sNameToIdsMap.put(name, id++); - } - - for (int i = 0; i < LANGUAGES_AND_TEXTS.length; i += 2) { - final String language = (String)LANGUAGES_AND_TEXTS[i]; - final String[] texts = (String[])LANGUAGES_AND_TEXTS[i + 1]; - sLocaleToTextsMap.put(language, texts); - } - } -} diff --git a/tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl b/tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl new file mode 100644 index 000000000..2b5494fa5 --- /dev/null +++ b/tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.tmpl @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014 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.latin.utils.CollectionUtils; + +import java.util.HashMap; +import java.util.Locale; + +/** + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file is generated by tools/make-keyboard-text. The base template file is + * tools/make-keyboard-text/res/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsTable.tmpl + * + * This file must be updated when any text resources in keyboard layout files have been changed. + * These text resources are referred as "!text/<resource_name>" in keyboard XML definitions, + * and should be defined in + * tools/make-keyboard-text/res/values-<locale>/donottranslate-more-keys.xml + * + * To update this file, please run the following commands. + * $ cd $ANDROID_BUILD_TOP + * $ mmm packages/inputmethods/LatinIME/tools/make-keyboard-text + * $ make-keyboard-text -java packages/inputmethods/LatinIME/java + * + * The updated source file will be generated to the following path (this file). + * packages/inputmethods/LatinIME/java/src/com/android/inputmethod/keyboard/internal/ + * KeyboardTextsTable.java + */ +public final class KeyboardTextsTable { + // Name to index map. + private static final HashMap<String, Integer> sNameToIndexesMap = CollectionUtils.newHashMap(); + // Locale to texts table map. + private static final HashMap<String, String[]> sLocaleToTextsTableMap = + CollectionUtils.newHashMap(); + // TODO: Remove this variable after debugging. + // Texts table to locale maps. + private static final HashMap<String[], String> sTextsTableToLocaleMap = + CollectionUtils.newHashMap(); + + public static String getText(final String name, final String[] textsTable) { + final Integer indexObj = sNameToIndexesMap.get(name); + if (indexObj == null) { + throw new RuntimeException("Unknown text name=" + name + " locale=" + + sTextsTableToLocaleMap.get(textsTable)); + } + final int index = indexObj; + final String text = (index < textsTable.length) ? textsTable[index] : null; + if (text != null) { + return text; + } + // Sanity check. + if (index >= 0 && index < TEXTS_DEFAULT.length) { + return TEXTS_DEFAULT[index]; + } + // Throw exception for debugging purpose. + throw new RuntimeException("Illegal index=" + index + " for name=" + name + + " locale=" + sTextsTableToLocaleMap.get(textsTable)); + } + + public static String[] getTextsTable(final Locale locale) { + final String localeKey = locale.toString(); + if (sLocaleToTextsTableMap.containsKey(localeKey)) { + return sLocaleToTextsTableMap.get(localeKey); + } + final String languageKey = locale.getLanguage(); + if (sLocaleToTextsTableMap.containsKey(languageKey)) { + return sLocaleToTextsTableMap.get(languageKey); + } + return TEXTS_DEFAULT; + } + + private static final String[] NAMES = { + // /* index:histogram */ "name", + /* @NAMES@ */ + }; + + private static final String EMPTY = ""; + + /* Default texts */ + private static final String[] TEXTS_DEFAULT = { + /* @DEFAULT_TEXTS@ */ + }; + + /* @TEXTS@ */ + private static final Object[] LOCALES_AND_TEXTS = { + // "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */ + /* @LOCALES_AND_TEXTS@ */ + }; + + static { + for (int index = 0; index < NAMES.length; index++) { + sNameToIndexesMap.put(NAMES[index], index); + } + + for (int i = 0; i < LOCALES_AND_TEXTS.length; i += 2) { + final String locale = (String)LOCALES_AND_TEXTS[i]; + final String[] textsTable = (String[])LOCALES_AND_TEXTS[i + 1]; + sLocaleToTextsTableMap.put(locale, textsTable); + sTextsTableToLocaleMap.put(textsTable, locale); + } + } +} diff --git a/tools/make-keyboard-text/res/values-af/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-af/donottranslate-more-keys.xml index ee96f442d..45acb7e57 100644 --- a/tools/make-keyboard-text/res/values-af/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-af/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,â,ä,à,æ,ã,å,ā</string> + <string name="morekeys_a">á,â,ä,à,æ,ã,å,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -35,7 +35,7 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">é,è,ê,ë,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS @@ -43,7 +43,7 @@ U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_i">í,ì,ï,î,į,ī,ij</string> + <string name="morekeys_i">í,ì,ï,î,į,ī,ij</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -52,18 +52,17 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ô,ö,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ô,ö,ò,õ,œ,ø,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,û,ü,ù,ū</string> + <string name="morekeys_u">ú,û,ü,ù,ū</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> - <string name="more_keys_for_y">ý,ŷ,ÿ,ij</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_y">ý,ij</string> + <string name="morekeys_y">ý,ij</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ar/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ar/donottranslate-more-keys.xml index 8b86b1ba2..4ecb10533 100644 --- a/tools/make-keyboard-text/res/values-ar/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ar/donottranslate-more-keys.xml @@ -19,91 +19,99 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Label for "switch to alphabetic" key. - U+0623: "ا" ARABIC LETTER ALEF + U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE U+200C: ZERO WIDTH NON-JOINER U+0628: "ب" ARABIC LETTER BEH - U+062C: "پ" ARABIC LETTER PEH --> - <string name="label_to_alpha_key">أ‌ب‌ج</string> + U+062C: "ج" ARABIC LETTER JEEM --> + <string name="keylabel_to_alpha">أ‌ب‌ج</string> <!-- U+0661: "١" ARABIC-INDIC DIGIT ONE --> - <string name="keylabel_for_symbols_1">١</string> + <string name="keyspec_symbols_1">١</string> <!-- U+0662: "٢" ARABIC-INDIC DIGIT TWO --> - <string name="keylabel_for_symbols_2">٢</string> + <string name="keyspec_symbols_2">٢</string> <!-- U+0663: "٣" ARABIC-INDIC DIGIT THREE --> - <string name="keylabel_for_symbols_3">٣</string> + <string name="keyspec_symbols_3">٣</string> <!-- U+0664: "٤" ARABIC-INDIC DIGIT FOUR --> - <string name="keylabel_for_symbols_4">٤</string> + <string name="keyspec_symbols_4">٤</string> <!-- U+0665: "٥" ARABIC-INDIC DIGIT FIVE --> - <string name="keylabel_for_symbols_5">٥</string> + <string name="keyspec_symbols_5">٥</string> <!-- U+0666: "٦" ARABIC-INDIC DIGIT SIX --> - <string name="keylabel_for_symbols_6">٦</string> + <string name="keyspec_symbols_6">٦</string> <!-- U+0667: "٧" ARABIC-INDIC DIGIT SEVEN --> - <string name="keylabel_for_symbols_7">٧</string> + <string name="keyspec_symbols_7">٧</string> <!-- U+0668: "٨" ARABIC-INDIC DIGIT EIGHT --> - <string name="keylabel_for_symbols_8">٨</string> + <string name="keyspec_symbols_8">٨</string> <!-- U+0669: "٩" ARABIC-INDIC DIGIT NINE --> - <string name="keylabel_for_symbols_9">٩</string> + <string name="keyspec_symbols_9">٩</string> <!-- U+0660: "٠" ARABIC-INDIC DIGIT ZERO --> - <string name="keylabel_for_symbols_0">٠</string> + <string name="keyspec_symbols_0">٠</string> <!-- Label for "switch to symbols" key. U+061F: "؟" ARABIC QUESTION MARK --> - <string name="label_to_symbol_key">٣٢١؟</string> - <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - part because it'll be appended by the code. --> - <string name="label_to_symbol_with_microphone_key">٣٢١</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> + <string name="keylabel_to_symbol">٣٢١؟</string> + <string name="additional_morekeys_symbols_1">1</string> + <string name="additional_morekeys_symbols_2">2</string> + <string name="additional_morekeys_symbols_3">3</string> + <string name="additional_morekeys_symbols_4">4</string> + <string name="additional_morekeys_symbols_5">5</string> + <string name="additional_morekeys_symbols_6">6</string> + <string name="additional_morekeys_symbols_7">7</string> + <string name="additional_morekeys_symbols_8">8</string> + <string name="additional_morekeys_symbols_9">9</string> <!-- U+066B: "٫" ARABIC DECIMAL SEPARATOR U+066C: "٬" ARABIC THOUSANDS SEPARATOR --> - <string name="additional_more_keys_for_symbols_0">0,٫,٬</string> + <string name="additional_morekeys_symbols_0">0,٫,٬</string> <!-- U+060C: "،" ARABIC COMMA --> - <string name="keylabel_for_comma">،</string> - <string name="more_keys_for_comma">"\\,"</string> - <string name="keylabel_for_symbols_question">؟</string> - <string name="keylabel_for_symbols_semicolon">؛</string> + <string name="keyspec_comma">،</string> + <!-- U+0651: "ّ" ARABIC SHADDA --> + <string name="keyhintlabel_period">ّ</string> + <string name="morekeys_period">!text/morekeys_arabic_diacritics</string> + <string name="keyhintlabel_tablet_period">ّ</string> + <string name="morekeys_tablet_period">!text/morekeys_arabic_diacritics</string> + <string name="keyspec_symbols_question">؟</string> + <string name="keyspec_symbols_semicolon">؛</string> <!-- U+066A: "٪" ARABIC PERCENT SIGN --> - <string name="keylabel_for_symbols_percent">٪</string> - <string name="more_keys_for_symbols_question">\?</string> - <string name="more_keys_for_symbols_semicolon">;</string> + <string name="keyspec_symbols_percent">٪</string> + <!-- U+00BF: "¿" INVERTED QUESTION MARK --> + <string name="morekeys_question">?,¿</string> + <string name="morekeys_symbols_semicolon">;</string> <!-- U+2030: "‰" PER MILLE SIGN --> - <string name="more_keys_for_symbols_percent">\\%,‰</string> - <!-- U+060C: "،" ARABIC COMMA - U+061B: "؛" ARABIC SEMICOLON - U+061F: "؟" ARABIC QUESTION MARK --> - <string name="keylabel_for_apostrophe">،</string> - <string name="keyhintlabel_for_apostrophe">؟</string> + <string name="morekeys_symbols_percent">\\%,‰</string> <!-- U+061F: "؟" ARABIC QUESTION MARK U+060C: "،" ARABIC COMMA U+061B: "؛" ARABIC SEMICOLON --> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,،,؟,\@,&,\\%,+,؛,/,(|),)|("</string> - <string name="more_keys_for_apostrophe">"؟,؛,!,:,-,/,\',\""</string> + <string name="keyspec_tablet_comma">"،"</string> + <string name="keyhintlabel_tablet_comma">"؟"</string> + <string name="morekeys_tablet_comma">"!fixedColumnOrder!4,:,!,؟,؛,-,/,\",\'"</string> <!-- U+266A: "♪" EIGHTH NOTE --> - <string name="more_keys_for_bullet">♪</string> + <string name="morekeys_bullet">♪</string> <!-- U+2605: "★" BLACK STAR U+066D: "٭" ARABIC FIVE POINTED STAR --> - <string name="more_keys_for_star">★,٭</string> + <string name="morekeys_star">★,٭</string> <!-- The all letters need to be mirrored are found at http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> <!-- U+FD3E: "﴾" ORNATE LEFT PARENTHESIS U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS --> - <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!4,﴾|﴿,<|>,{|},[|]</string> - <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!4,﴿|﴾,>|<,}|{,]|[</string> + <string name="morekeys_left_parenthesis">!fixedColumnOrder!4,﴾|﴿,!text/keyspecs_left_parenthesis_more_keys</string> + <string name="morekeys_right_parenthesis">!fixedColumnOrder!4,﴿|﴾,!text/keyspecs_right_parenthesis_more_keys</string> <!-- U+2264: "≤" LESS-THAN OR EQUAL TO U+2265: "≥" GREATER-THAN EQUAL TO U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK --> - <string name="more_keys_for_less_than">!fixedColumnOrder!3,‹|›,≤|≥,«|»</string> - <string name="more_keys_for_greater_than">!fixedColumnOrder!3,›|‹,≥|≤,»|«</string> - <string name="single_angle_quotes">!text/single_laqm_raqm_rtl</string> - <string name="double_angle_quotes">!text/double_laqm_raqm_rtl</string> + <string name="keyspec_left_parenthesis">(|)</string> + <string name="keyspec_right_parenthesis">)|(</string> + <string name="keyspec_left_square_bracket">[|]</string> + <string name="keyspec_right_square_bracket">]|[</string> + <string name="keyspec_left_curly_bracket">{|}</string> + <string name="keyspec_right_curly_bracket">}|{</string> + <string name="keyspec_less_than"><|></string> + <string name="keyspec_greater_than">>|<</string> + <string name="keyspec_less_than_equal">≤|≥</string> + <string name="keyspec_greater_than_equal">≥|≤</string> + <string name="keyspec_left_double_angle_quote">«|»</string> + <string name="keyspec_right_double_angle_quote">»|«</string> + <string name="keyspec_left_single_angle_quote">‹|›</string> + <string name="keyspec_right_single_angle_quote">›|‹</string> <!-- U+0655: "ٕ" ARABIC HAMZA BELOW U+0654: "ٔ" ARABIC HAMZA ABOVE U+0652: "ْ" ARABIC SUKUN @@ -120,6 +128,5 @@ U+0640: "ـ" ARABIC TATWEEL --> <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. --> <!-- Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. --> - <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7, ٕ|ٕ, ٔ|ٔ, ْ|ْ, ٍ|ٍ, ٌ|ٌ, ً|ً, ّ|ّ, ٖ|ٖ, ٰ|ٰ, ٓ|ٓ, ِ|ِ, ُ|ُ, َ|َ,ـــ|ـ"</string> - <string name="keyhintlabel_for_arabic_diacritics">ّ</string> + <string name="morekeys_arabic_diacritics">"!fixedColumnOrder!7, ٕ|ٕ, ٔ|ٔ, ْ|ْ, ٍ|ٍ, ٌ|ٌ, ً|ً, ّ|ّ, ٖ|ٖ, ٰ|ٰ, ٓ|ٓ, ِ|ِ, ُ|ُ, َ|َ,ـــ|ـ"</string> </resources> diff --git a/tools/make-keyboard-text/res/values-az/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-az-rAZ/donottranslate-more-keys.xml index db1784c17..54aa570b6 100644 --- a/tools/make-keyboard-text/res/values-az/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-az-rAZ/donottranslate-more-keys.xml @@ -19,9 +19,9 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX --> - <string name="more_keys_for_a">â</string> + <string name="morekeys_a">â</string> <!-- U+0259: "ə" LATIN SMALL LETTER SCHWA --> - <string name="more_keys_for_e">ə</string> + <string name="morekeys_e">ə</string> <!-- U+0131: "ı" LATIN SMALL LETTER DOTLESS I U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS @@ -29,7 +29,7 @@ U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">ı,î,ï,ì,í,į,ī</string> + <string name="morekeys_i">ı,î,ï,ì,í,į,ī</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+0153: "œ" LATIN SMALL LIGATURE OE @@ -38,22 +38,22 @@ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ö,ô,œ,ò,ó,õ,ø,ō</string> + <string name="morekeys_o">ö,ô,œ,ò,ó,õ,ø,ō</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ü,û,ù,ú,ū</string> + <string name="morekeys_u">ü,û,ù,ú,ū</string> <!-- U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ş,ß,ś,š</string> + <string name="morekeys_s">ş,ß,ś,š</string> <!-- U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ğ</string> + <string name="morekeys_g">ğ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,ć,č</string> </resources> diff --git a/tools/make-keyboard-text/res/values-be/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-be-rBY/donottranslate-more-keys.xml index 4723503f1..52ada29d9 100644 --- a/tools/make-keyboard-text/res/values-be/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-be-rBY/donottranslate-more-keys.xml @@ -19,24 +19,22 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+045E: "ў" CYRILLIC SMALL LETTER SHORT U --> - <string name="keylabel_for_east_slavic_row1_9">ў</string> - <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="keylabel_for_east_slavic_row1_12">ё</string> + <string name="keyspec_east_slavic_row1_9">ў</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> - <string name="keylabel_for_east_slavic_row2_1">ы</string> + <string name="keyspec_east_slavic_row2_2">ы</string> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> - <string name="keylabel_for_east_slavic_row2_11">э</string> + <string name="keyspec_east_slavic_row2_11">э</string> <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I --> - <string name="keylabel_for_east_slavic_row3_5">і</string> + <string name="keyspec_east_slavic_row3_5">і</string> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="more_keys_for_cyrillic_ie">ё</string> + <string name="morekeys_cyrillic_ie">ё</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> + <string name="morekeys_cyrillic_soft_sign">ъ</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-bg/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-bg/donottranslate-more-keys.xml index 5262133de..8a98b1227 100644 --- a/tools/make-keyboard-text/res/values-bg/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-bg/donottranslate-more-keys.xml @@ -22,7 +22,7 @@ U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <!-- single_quotes of Bulgarian is default single_quotes_right_left. --> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml index 66393732c..125f08f26 100644 --- a/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml @@ -28,7 +28,7 @@ U+00E6: "æ" LATIN SMALL LETTER AE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">à,á,ä,â,ã,å,ą,æ,ā,ª</string> + <string name="morekeys_a">à,á,ä,â,ã,å,ą,æ,ā,ª</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS @@ -36,14 +36,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">è,é,ë,ê,ę,ė,ē</string> + <string name="morekeys_e">è,é,ë,ê,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="morekeys_i">í,ï,ì,î,į,ī</string> <!-- U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -53,26 +53,26 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ò,ó,ö,ô,õ,ø,œ,ō,º</string> + <string name="morekeys_o">ò,ó,ö,ô,õ,ø,œ,ō,º</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,ù,û,ū</string> + <string name="morekeys_u">ú,ü,ù,û,ū</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,ć,č</string> <!-- U+00B7: "·" MIDDLE DOT U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">l·l,ł</string> + <string name="morekeys_l">l·l,ł</string> <!-- U+00B7: "·" MIDDLE DOT --> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!9,;,/,(,),#,·,!,\\,,\?,&,\\%,+,\",-,:,',\@"</string> - <string name="more_keys_for_period">\?,·</string> + <string name="morekeys_punctuation">"!autoColumnOrder!9,\\,,?,!,·,#,),(,/,;,',@,:,-,\",+,\\%,&"</string> + <string name="morekeys_tablet_punctuation">"!autoColumnOrder!8,\\,,',·,#,),(,/,;,@,:,-,\",+,\\%,&"</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> - <string name="keylabel_for_spanish_row2_10">ç</string> + <string name="keyspec_spanish_row2_10">ç</string> </resources> diff --git a/tools/make-keyboard-text/res/values-cs/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-cs/donottranslate-more-keys.xml index 5ce1d3bc8..1a27783e9 100644 --- a/tools/make-keyboard-text/res/values-cs/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-cs/donottranslate-more-keys.xml @@ -26,7 +26,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,à,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">á,à,â,ä,æ,ã,å,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+011B: "ě" LATIN SMALL LETTER E WITH CARON U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE @@ -35,14 +35,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,ě,è,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">é,ě,è,ê,ë,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,î,ï,ì,į,ī</string> + <string name="morekeys_i">í,î,ï,ì,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -51,39 +51,39 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ö,ô,ò,õ,œ,ø,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ů,û,ü,ù,ū</string> + <string name="morekeys_u">ú,ů,û,ü,ù,ū</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE --> - <string name="more_keys_for_s">š,ß,ś</string> + <string name="morekeys_s">š,ß,ś</string> <!-- U+0148: "ň" LATIN SMALL LETTER N WITH CARON U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ň,ñ,ń</string> + <string name="morekeys_n">ň,ñ,ń</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> <!-- U+0159: "ř" LATIN SMALL LETTER R WITH CARON --> - <string name="more_keys_for_r">ř</string> + <string name="morekeys_r">ř</string> <!-- U+0165: "ť" LATIN SMALL LETTER T WITH CARON --> - <string name="more_keys_for_t">ť</string> + <string name="morekeys_t">ť</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE --> - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="morekeys_z">ž,ź,ż</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml index cbaf9f497..c22e26275 100644 --- a/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml @@ -24,50 +24,50 @@ U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,ä,à,â,ã,ā</string> + <string name="morekeys_a">á,ä,à,â,ã,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS --> - <string name="more_keys_for_e">é,ë</string> + <string name="morekeys_e">é,ë</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS --> - <string name="more_keys_for_i">í,ï</string> + <string name="morekeys_i">í,ï</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ô,ò,õ,œ,ō</string> + <string name="morekeys_o">ó,ô,ò,õ,œ,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,û,ù,ū</string> + <string name="morekeys_u">ú,ü,û,ù,ū</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ß,ś,š</string> + <string name="morekeys_s">ß,ś,š</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+00F0: "ð" LATIN SMALL LETTER ETH --> - <string name="more_keys_for_d">ð</string> + <string name="morekeys_d">ð</string> <!-- U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ł</string> + <string name="morekeys_l">ł</string> <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE --> - <string name="keylabel_for_nordic_row1_11">å</string> + <string name="keyspec_nordic_row1_11">å</string> <!-- U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="keylabel_for_nordic_row2_10">æ</string> + <string name="keyspec_nordic_row2_10">æ</string> <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="keylabel_for_nordic_row2_11">ø</string> + <string name="keyspec_nordic_row2_11">ø</string> <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> - <string name="more_keys_for_nordic_row2_10">ä</string> + <string name="morekeys_nordic_row2_10">ä</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> - <string name="more_keys_for_nordic_row2_11">ö</string> + <string name="morekeys_nordic_row2_11">ö</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml index 9dc8717ec..0c6d3ad2b 100644 --- a/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml @@ -26,13 +26,13 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">ä,â,à,á,æ,ã,å,ā</string> + <string name="morekeys_a">ä,%,â,à,á,æ,ã,å,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE --> - <string name="more_keys_for_e">é,è,ê,ë,ė</string> + <string name="morekeys_e">é,è,ê,ë,ė</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -41,20 +41,32 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ö,ô,ò,ó,õ,œ,ø,ō</string> + <string name="morekeys_o">ö,%,ô,ò,ó,õ,œ,ø,ō</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ü,û,ù,ú,ū</string> + <string name="morekeys_u">ü,%,û,ù,ú,ū</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ß,ś,š</string> + <string name="morekeys_s">ß,ś,š</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> + <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> + <string name="keyspec_swiss_row1_11">ü</string> + <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE --> + <string name="morekeys_swiss_row1_11">è</string> + <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> + <string name="keyspec_swiss_row2_10">ö</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE --> + <string name="morekeys_swiss_row2_10">é</string> + <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> + <string name="keyspec_swiss_row2_11">ä</string> + <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE --> + <string name="morekeys_swiss_row2_11">à</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-el/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-el/donottranslate-more-keys.xml index 964dba081..77950c3b3 100644 --- a/tools/make-keyboard-text/res/values-el/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-el/donottranslate-more-keys.xml @@ -22,5 +22,5 @@ U+0391: "Α" GREEK CAPITAL LETTER ALPHA U+0392: "Β" GREEK CAPITAL LETTER BETA U+0393: "Γ" GREEK CAPITAL LETTER GAMMA --> - <string name="label_to_alpha_key">ΑΒΓ</string> + <string name="keylabel_to_alpha">ΑΒΓ</string> </resources> diff --git a/tools/make-keyboard-text/res/values-en/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-en/donottranslate-more-keys.xml index 969a5041b..7998bf161 100644 --- a/tools/make-keyboard-text/res/values-en/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-en/donottranslate-more-keys.xml @@ -26,19 +26,19 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">à,á,â,ä,æ,ã,å,ā</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">è,é,ê,ë,ē</string> + <string name="morekeys_e">è,é,ê,ë,ē</string> <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE --> - <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <string name="morekeys_i">î,ï,í,ī,ì</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -47,17 +47,17 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> - <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> + <string name="morekeys_o">ô,ö,ò,ó,œ,ø,ō,õ</string> <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">û,ü,ù,ú,ū</string> + <string name="morekeys_u">û,ü,ù,ú,ū</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S --> - <string name="more_keys_for_s">ß</string> + <string name="morekeys_s">ß</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="more_keys_for_n">ñ</string> + <string name="morekeys_n">ñ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> - <string name="more_keys_for_c">ç</string> + <string name="morekeys_c">ç</string> </resources> diff --git a/tools/make-keyboard-text/res/values-eo/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-eo/donottranslate-more-keys.xml index e929869e2..7ef3101f5 100644 --- a/tools/make-keyboard-text/res/values-eo/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-eo/donottranslate-more-keys.xml @@ -29,7 +29,7 @@ U+0103: "ă" LATIN SMALL LETTER A WITH BREVE U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">á,à,â,ä,æ,ã,å,ā,ă,ą,ª</string> + <string name="morekeys_a">á,à,â,ä,æ,ã,å,ā,ă,ą,ª</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+011B: "ě" LATIN SMALL LETTER E WITH CARON U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE @@ -38,7 +38,7 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,ě,è,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">é,ě,è,ê,ë,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS @@ -48,7 +48,7 @@ U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+0131: "ı" LATIN SMALL LETTER DOTLESS I U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_i">í,î,ï,ĩ,ì,į,ī,ı,ij</string> + <string name="morekeys_i">í,î,ï,ĩ,ì,į,ī,ı,ij</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -59,7 +59,7 @@ U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō,ő,º</string> + <string name="morekeys_o">ó,ö,ô,ò,õ,œ,ø,ō,ő,º</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX @@ -70,77 +70,77 @@ U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK U+00B5: "µ" MICRO SIGN --> - <string name="more_keys_for_u">ú,ů,û,ü,ù,ū,ũ,ű,ų,µ</string> + <string name="morekeys_u">ú,ů,û,ü,ù,ū,ũ,ű,ų,µ</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S U+0161: "š" LATIN SMALL LETTER S WITH CARON U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA --> - <string name="more_keys_for_s">ß,š,ś,ș,ş</string> + <string name="morekeys_s">ß,š,ś,ș,ş</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+0148: "ň" LATIN SMALL LETTER N WITH CARON U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE U+014B: "ŋ" LATIN SMALL LETTER ENG --> - <string name="more_keys_for_n">ñ,ń,ņ,ň,ʼn,ŋ</string> + <string name="morekeys_n">ñ,ń,ņ,ň,ʼn,ŋ</string> <!-- U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE --> - <string name="more_keys_for_c">ć,č,ç,ċ</string> + <string name="morekeys_c">ć,č,ç,ċ</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS U+00FE: "þ" LATIN SMALL LETTER THORN --> - <string name="more_keys_for_y">y,ý,ŷ,ÿ,þ</string> + <string name="morekeys_y">y,ý,ŷ,ÿ,þ</string> <!-- U+00F0: "ð" LATIN SMALL LETTER ETH U+010F: "ď" LATIN SMALL LETTER D WITH CARON U+0111: "đ" LATIN SMALL LETTER D WITH STROKE --> - <string name="more_keys_for_d">ð,ď,đ</string> + <string name="morekeys_d">ð,ď,đ</string> <!-- U+0159: "ř" LATIN SMALL LETTER R WITH CARON U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA --> - <string name="more_keys_for_r">ř,ŕ,ŗ</string> + <string name="morekeys_r">ř,ŕ,ŗ</string> <!-- U+0165: "ť" LATIN SMALL LETTER T WITH CARON U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE --> - <string name="more_keys_for_t">ť,ț,ţ,ŧ</string> + <string name="morekeys_t">ť,ț,ţ,ŧ</string> <!-- U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017E: "ž" LATIN SMALL LETTER Z WITH CARON --> - <string name="more_keys_for_z">ź,ż,ž</string> + <string name="morekeys_z">ź,ż,ž</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA U+0138: "ĸ" LATIN SMALL LETTER KRA --> - <string name="more_keys_for_k">ķ,ĸ</string> + <string name="morekeys_k">ķ,ĸ</string> <!-- U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+013E: "ľ" LATIN SMALL LETTER L WITH CARON U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ĺ,ļ,ľ,ŀ,ł</string> + <string name="morekeys_l">ĺ,ļ,ľ,ŀ,ł</string> <!-- U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA --> - <string name="more_keys_for_g">ğ,ġ,ģ</string> + <string name="morekeys_g">ğ,ġ,ģ</string> <!-- U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX --> - <string name="more_keys_for_v">w,ŵ</string> + <string name="morekeys_v">w,ŵ</string> <!-- U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE --> - <string name="more_keys_for_h">ĥ,ħ</string> + <string name="morekeys_h">ĥ,ħ</string> <!-- U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX --> - <string name="more_keys_for_w">w,ŵ</string> - <string name="more_keys_for_q">q</string> - <string name="more_keys_for_x">x</string> + <string name="morekeys_w">w,ŵ</string> + <string name="morekeys_q">q</string> + <string name="morekeys_x">x</string> <!-- U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX --> - <string name="keylabel_for_q">ŝ</string> + <string name="keyspec_q">ŝ</string> <!-- U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX --> - <string name="keylabel_for_w">ĝ</string> + <string name="keyspec_w">ĝ</string> <!-- U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE --> - <string name="keylabel_for_y">ŭ</string> + <string name="keyspec_y">ŭ</string> <!-- U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX --> - <string name="keylabel_for_x">ĉ</string> + <string name="keyspec_x">ĉ</string> <!-- U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX --> - <string name="keylabel_for_spanish_row2_10">ĵ</string> + <string name="keyspec_spanish_row2_10">ĵ</string> </resources> diff --git a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml index 8e6b4ee06..22e537069 100644 --- a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml @@ -28,7 +28,7 @@ U+00E6: "æ" LATIN SMALL LETTER AE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> + <string name="morekeys_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS @@ -36,14 +36,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ë,ê,ę,ė,ē</string> + <string name="morekeys_e">é,è,ë,ê,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="morekeys_i">í,ï,ì,î,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -53,30 +53,21 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <string name="morekeys_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,ù,û,ū</string> + <string name="morekeys_u">ú,ü,ù,û,ū</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> - <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="keylabel_for_spanish_row2_10">ñ</string> + <string name="morekeys_c">ç,ć,č</string> <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK U+00BF: "¿" INVERTED QUESTION MARK --> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!4,;,!,\\,,\?,:,¡,\@,¿"</string> - <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK --> - <string name="more_keys_for_tablet_comma">"!,¡"</string> - <!-- U+00BF: "¿" INVERTED QUESTION MARK --> - <string name="more_keys_for_period">"\?,¿"</string> - <string name="keylabel_for_apostrophe">\"</string> - <string name="keyhintlabel_for_apostrophe">\'</string> - <string name="more_keys_for_apostrophe">\'</string> + <string name="morekeys_punctuation">"!autoColumnOrder!9,\\,,?,!,#,),(,/,;,¡,',@,:,-,\",+,\\%,&,¿"</string> </resources> diff --git a/tools/make-keyboard-text/res/values-et/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml index d037044bd..9a8fa3c59 100644 --- a/tools/make-keyboard-text/res/values-et/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+00E6: "æ" LATIN SMALL LETTER AE U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK --> - <string name="more_keys_for_a">ä,ā,à,á,â,ã,å,æ,ą</string> + <string name="morekeys_a">ä,ā,à,á,â,ã,å,æ,ą</string> <!-- U+0113: "ē" LATIN SMALL LETTER E WITH MACRON U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE @@ -36,7 +36,7 @@ U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+011B: "ě" LATIN SMALL LETTER E WITH CARON --> - <string name="more_keys_for_e">ē,è,ė,é,ê,ë,ę,ě</string> + <string name="morekeys_e">ē,è,ė,é,ê,ë,ę,ě</string> <!-- U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK @@ -44,7 +44,7 @@ U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+0131: "ı" LATIN SMALL LETTER DOTLESS I --> - <string name="more_keys_for_i">ī,ì,į,í,î,ï,ı</string> + <string name="morekeys_i">ī,ì,į,í,î,ï,ı</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -53,7 +53,7 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_o">ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="morekeys_o">ö,õ,ò,ó,ô,œ,ő,ø</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+016B: "ū" LATIN SMALL LETTER U WITH MACRON U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK @@ -62,55 +62,55 @@ U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE --> - <string name="more_keys_for_u">ü,ū,ų,ù,ú,û,ů,ű</string> + <string name="morekeys_u">ü,ū,ų,ù,ú,û,ů,ű</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA --> - <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="morekeys_s">š,ß,ś,ş</string> <!-- U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ņ,ñ,ń,ń</string> + <string name="morekeys_n">ņ,ñ,ń</string> + <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> <!-- U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA U+0159: "ř" LATIN SMALL LETTER R WITH CARON U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE --> - <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="morekeys_r">ŗ,ř,ŕ</string> <!-- U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA U+0165: "ť" LATIN SMALL LETTER T WITH CARON --> - <string name="more_keys_for_t">ţ,ť</string> + <string name="morekeys_t">ţ,ť</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE --> - <string name="more_keys_for_z">ž,ż,ź</string> + <string name="morekeys_z">ž,ż,ź</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA --> - <string name="more_keys_for_k">ķ</string> + <string name="morekeys_k">ķ</string> <!-- U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+0142: "ł" LATIN SMALL LETTER L WITH STROKE U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013E: "ľ" LATIN SMALL LETTER L WITH CARON --> - <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="morekeys_l">ļ,ł,ĺ,ľ</string> <!-- U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ģ,ğ</string> + <string name="morekeys_g">ģ,ğ</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> - <string name="keylabel_for_nordic_row1_11">ü</string> + <string name="keyspec_nordic_row1_11">ü</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_10">ö</string> + <string name="keyspec_nordic_row2_10">ö</string> <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_11">ä</string> + <string name="keyspec_nordic_row2_11">ä</string> <!-- U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> - <string name="more_keys_for_nordic_row2_10">õ</string> + <string name="morekeys_nordic_row2_10">õ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-eu-rES/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-eu-rES/donottranslate-more-keys.xml new file mode 100644 index 000000000..95f632a52 --- /dev/null +++ b/tools/make-keyboard-text/res/values-eu-rES/donottranslate-more-keys.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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"> + <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + U+00E6: "æ" LATIN SMALL LETTER AE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + U+00AA: "ª" FEMININE ORDINAL INDICATOR --> + <string name="morekeys_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="morekeys_e">é,è,ë,ê,ę,ė,ē</string> + <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> + <string name="morekeys_i">í,ï,ì,î,į,ī</string> + <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + U+00BA: "º" MASCULINE ORDINAL INDICATOR --> + <string name="morekeys_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="morekeys_u">ú,ü,ù,û,ū</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> + <string name="morekeys_n">ñ,ń</string> + <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + U+010D: "č" LATIN SMALL LETTER C WITH CARON --> + <string name="morekeys_c">ç,ć,č</string> +</resources> diff --git a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml index ab4fbda44..bdbc92afa 100644 --- a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml @@ -23,96 +23,101 @@ U+200C: ZERO WIDTH NON-JOINER U+0628: "ب" ARABIC LETTER BEH U+067E: "پ" ARABIC LETTER PEH --> - <string name="label_to_alpha_key">ا‌ب‌پ</string> + <string name="keylabel_to_alpha">ا‌ب‌پ</string> <!-- U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE --> - <string name="keylabel_for_symbols_1">۱</string> + <string name="keyspec_symbols_1">۱</string> <!-- U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO --> - <string name="keylabel_for_symbols_2">۲</string> + <string name="keyspec_symbols_2">۲</string> <!-- U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE --> - <string name="keylabel_for_symbols_3">۳</string> + <string name="keyspec_symbols_3">۳</string> <!-- U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR --> - <string name="keylabel_for_symbols_4">۴</string> + <string name="keyspec_symbols_4">۴</string> <!-- U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE --> - <string name="keylabel_for_symbols_5">۵</string> + <string name="keyspec_symbols_5">۵</string> <!-- U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX --> - <string name="keylabel_for_symbols_6">۶</string> + <string name="keyspec_symbols_6">۶</string> <!-- U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN --> - <string name="keylabel_for_symbols_7">۷</string> + <string name="keyspec_symbols_7">۷</string> <!-- U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT --> - <string name="keylabel_for_symbols_8">۸</string> + <string name="keyspec_symbols_8">۸</string> <!-- U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE --> - <string name="keylabel_for_symbols_9">۹</string> + <string name="keyspec_symbols_9">۹</string> <!-- U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO --> - <string name="keylabel_for_symbols_0">۰</string> + <string name="keyspec_symbols_0">۰</string> <!-- Label for "switch to symbols" key. U+061F: "؟" ARABIC QUESTION MARK --> - <string name="label_to_symbol_key">۳۲۱؟</string> - <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - part because it'll be appended by the code. --> - <string name="label_to_symbol_with_microphone_key">۳۲۱</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> + <string name="keylabel_to_symbol">۳۲۱؟</string> + <string name="additional_morekeys_symbols_1">1</string> + <string name="additional_morekeys_symbols_2">2</string> + <string name="additional_morekeys_symbols_3">3</string> + <string name="additional_morekeys_symbols_4">4</string> + <string name="additional_morekeys_symbols_5">5</string> + <string name="additional_morekeys_symbols_6">6</string> + <string name="additional_morekeys_symbols_7">7</string> + <string name="additional_morekeys_symbols_8">8</string> + <string name="additional_morekeys_symbols_9">9</string> <!-- U+066B: "٫" ARABIC DECIMAL SEPARATOR U+066C: "٬" ARABIC THOUSANDS SEPARATOR --> - <string name="additional_more_keys_for_symbols_0">0,٫,٬</string> + <string name="additional_morekeys_symbols_0">0,٫,٬</string> <!-- U+060C: "،" ARABIC COMMA --> - <string name="keylabel_for_comma">،</string> - <string name="more_keys_for_comma">"\\,"</string> - <string name="keylabel_for_symbols_question">؟</string> - <string name="keylabel_for_symbols_semicolon">؛</string> + <string name="keyspec_comma">،</string> + <!-- U+064B: "ً" ARABIC FATHATAN --> + <string name="keyhintlabel_period">ً</string> + <string name="morekeys_period">!text/morekeys_arabic_diacritics</string> + <string name="keyhintlabel_tablet_period">ً</string> + <string name="morekeys_tablet_period">!text/morekeys_arabic_diacritics</string> + <string name="keyspec_symbols_question">؟</string> + <string name="keyspec_symbols_semicolon">؛</string> <!-- U+066A: "٪" ARABIC PERCENT SIGN --> - <string name="keylabel_for_symbols_percent">٪</string> - <string name="more_keys_for_symbols_question">\?</string> - <string name="more_keys_for_symbols_semicolon">;</string> + <string name="keyspec_symbols_percent">٪</string> + <!-- U+00BF: "¿" INVERTED QUESTION MARK --> + <string name="morekeys_question">?,¿</string> + <string name="morekeys_symbols_semicolon">;</string> <!-- U+2030: "‰" PER MILLE SIGN --> - <string name="more_keys_for_symbols_percent">\\%,‰</string> + <string name="morekeys_symbols_percent">\\%,‰</string> <!-- U+060C: "،" ARABIC COMMA U+061B: "؛" ARABIC SEMICOLON U+061F: "؟" ARABIC QUESTION MARK U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> - <string name="keylabel_for_tablet_comma">"،"</string> - <string name="keyhintlabel_for_tablet_comma">"!"</string> - <string name="more_keys_for_tablet_comma">"!,\\,"</string> - <string name="keyhintlabel_for_period">"؟"</string> - <string name="more_keys_for_period">"؟,\?"</string> - <string name="keylabel_for_apostrophe">،</string> - <string name="keyhintlabel_for_apostrophe">؟</string> - <string name="more_keys_for_apostrophe">"!fixedColumnOrder!4,:,!,؟,؛,-,/,«|»,»|«"</string> + <string name="keyspec_tablet_comma">"،"</string> + <string name="keyhintlabel_tablet_comma">"؟"</string> + <string name="morekeys_tablet_comma">"!fixedColumnOrder!4,:,!,؟,؛,-,/,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote"</string> <!-- U+FDFC: "﷼" RIAL SIGN --> - <string name="keylabel_for_currency">﷼</string> - <!-- U+061F: "؟" ARABIC QUESTION MARK - U+060C: "،" ARABIC COMMA - U+061B: "؛" ARABIC SEMICOLON --> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,،,؟,\@,&,\\%,+,؛,/,(|),)|("</string> + <string name="keyspec_currency">﷼</string> <!-- U+266A: "♪" EIGHTH NOTE --> - <string name="more_keys_for_bullet">♪</string> + <string name="morekeys_bullet">♪</string> <!-- U+2605: "★" BLACK STAR U+066D: "٭" ARABIC FIVE POINTED STAR --> - <string name="more_keys_for_star">★,٭</string> + <string name="morekeys_star">★,٭</string> <!-- The all letters need to be mirrored are found at http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> <!-- U+FD3E: "﴾" ORNATE LEFT PARENTHESIS U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS --> - <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!4,﴾|﴿,<|>,{|},[|]</string> - <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!4,﴿|﴾,>|<,}|{,]|[</string> + <string name="morekeys_left_parenthesis">!fixedColumnOrder!4,﴾|﴿,!text/keyspecs_left_parenthesis_more_keys</string> + <string name="morekeys_right_parenthesis">!fixedColumnOrder!4,﴿|﴾,!text/keyspecs_right_parenthesis_more_keys</string> <!-- U+2264: "≤" LESS-THAN OR EQUAL TO U+2265: "≥" GREATER-THAN EQUAL TO U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK --> - <string name="more_keys_for_less_than">!fixedColumnOrder!3,‹|›,≤|≥,<|></string> - <string name="more_keys_for_greater_than">!fixedColumnOrder!3,›|‹,≥|≤,>|<</string> - <string name="single_angle_quotes">!text/single_laqm_raqm_rtl</string> - <string name="double_angle_quotes">!text/double_laqm_raqm_rtl</string> + <string name="morekeys_less_than">!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote,!text/keyspec_less_than_equal,!text/keyspec_less_than</string> + <string name="morekeys_greater_than">!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_greater_than</string> + <string name="keyspec_left_parenthesis">(|)</string> + <string name="keyspec_right_parenthesis">)|(</string> + <string name="keyspec_left_square_bracket">[|]</string> + <string name="keyspec_right_square_bracket">]|[</string> + <string name="keyspec_left_curly_bracket">{|}</string> + <string name="keyspec_right_curly_bracket">}|{</string> + <string name="keyspec_less_than"><|></string> + <string name="keyspec_greater_than">>|<</string> + <string name="keyspec_less_than_equal">≤|≥</string> + <string name="keyspec_greater_than_equal">≥|≤</string> + <string name="keyspec_left_double_angle_quote">«|»</string> + <string name="keyspec_right_double_angle_quote">»|«</string> + <string name="keyspec_left_single_angle_quote">‹|›</string> + <string name="keyspec_right_single_angle_quote">›|‹</string> <!-- U+0655: "ٕ" ARABIC HAMZA BELOW U+0652: "ْ" ARABIC SUKUN U+0651: "ّ" ARABIC SHADDA @@ -129,6 +134,5 @@ U+0640: "ـ" ARABIC TATWEEL --> <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. --> <!-- Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly. --> - <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7, ٕ|ٕ, ْ|ْ, ّ|ّ, ٌ|ٌ, ٍ|ٍ, ً|ً, ٔ|ٔ, ٖ|ٖ, ٰ|ٰ, ٓ|ٓ, ُ|ُ, ِ|ِ, َ|َ,ـــ|ـ"</string> - <string name="keyhintlabel_for_arabic_diacritics">ً</string> + <string name="morekeys_arabic_diacritics">"!fixedColumnOrder!7, ٕ|ٕ, ْ|ْ, ّ|ّ, ٌ|ٌ, ٍ|ٍ, ً|ً, ٔ|ٔ, ٖ|ٖ, ٰ|ٰ, ٓ|ٓ, ُ|ُ, ِ|ِ, َ|َ,ـــ|ـ"</string> </resources> diff --git a/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml index 25b785845..82b847262 100644 --- a/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml @@ -24,7 +24,7 @@ U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">æ,à,á,â,ã,ā</string> + <string name="morekeys_a">æ,à,á,â,ã,ā</string> <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -32,25 +32,25 @@ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ø,ô,ò,ó,õ,œ,ō</string> + <string name="morekeys_o">ø,ô,ò,ó,õ,œ,ō</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> - <string name="more_keys_for_u">ü</string> + <string name="morekeys_u">ü</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE --> - <string name="more_keys_for_s">š,ß,ś</string> + <string name="morekeys_s">š,ß,ś</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE --> - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="morekeys_z">ž,ź,ż</string> <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE --> - <string name="keylabel_for_nordic_row1_11">å</string> + <string name="keyspec_nordic_row1_11">å</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_10">ö</string> + <string name="keyspec_nordic_row2_10">ö</string> <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_11">ä</string> + <string name="keyspec_nordic_row2_11">ä</string> <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_nordic_row2_10">ø</string> + <string name="morekeys_nordic_row2_10">ø</string> <!-- U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="more_keys_for_nordic_row2_11">æ</string> + <string name="morekeys_nordic_row2_11">æ</string> </resources> diff --git a/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml index 7b11a183d..dded5d251 100644 --- a/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">à,â,%,æ,á,ä,ã,å,ā,ª</string> + <string name="morekeys_a">à,â,%,æ,á,ä,ã,å,ā,ª</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -35,14 +35,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ê,ë,%,ę,ė,ē</string> + <string name="morekeys_e">é,è,ê,ë,%,ę,ė,ē</string> <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">î,%,ï,ì,í,į,ī</string> + <string name="morekeys_i">î,%,ï,ì,í,į,ī</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+0153: "œ" LATIN SMALL LIGATURE OE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -52,17 +52,29 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ô,œ,%,ö,ò,ó,õ,ø,ō,º</string> + <string name="morekeys_o">ô,œ,%,ö,ò,ó,õ,ø,ō,º</string> <!-- U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ù,û,%,ü,ú,ū</string> + <string name="morekeys_u">ù,û,%,ü,ú,ū</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,%,ć,č</string> <!-- U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">%,ÿ</string> + <string name="morekeys_y">%,ÿ</string> + <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE --> + <string name="keyspec_swiss_row1_11">è</string> + <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> + <string name="morekeys_swiss_row1_11">ü</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE --> + <string name="keyspec_swiss_row2_10">é</string> + <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> + <string name="morekeys_swiss_row2_10">ö</string> + <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE --> + <string name="keyspec_swiss_row2_11">à</string> + <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> + <string name="morekeys_swiss_row2_11">ä</string> </resources> diff --git a/tools/make-keyboard-text/res/values-gl-rES/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-gl-rES/donottranslate-more-keys.xml new file mode 100644 index 000000000..95f632a52 --- /dev/null +++ b/tools/make-keyboard-text/res/values-gl-rES/donottranslate-more-keys.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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"> + <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE + U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE + U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS + U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX + U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE + U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE + U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK + U+00E6: "æ" LATIN SMALL LETTER AE + U+0101: "ā" LATIN SMALL LETTER A WITH MACRON + U+00AA: "ª" FEMININE ORDINAL INDICATOR --> + <string name="morekeys_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE + U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE + U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS + U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX + U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK + U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE + U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> + <string name="morekeys_e">é,è,ë,ê,ę,ė,ē</string> + <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE + U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS + U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE + U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX + U+012F: "į" LATIN SMALL LETTER I WITH OGONEK + U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> + <string name="morekeys_i">í,ï,ì,î,į,ī</string> + <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE + U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE + U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS + U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX + U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE + U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE + U+0153: "œ" LATIN SMALL LIGATURE OE + U+014D: "ō" LATIN SMALL LETTER O WITH MACRON + U+00BA: "º" MASCULINE ORDINAL INDICATOR --> + <string name="morekeys_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE + U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS + U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE + U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX + U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> + <string name="morekeys_u">ú,ü,ù,û,ū</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE + U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> + <string name="morekeys_n">ñ,ń</string> + <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA + U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE + U+010D: "č" LATIN SMALL LETTER C WITH CARON --> + <string name="morekeys_c">ç,ć,č</string> +</resources> diff --git a/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml index b0d010f81..55723cdd1 100644 --- a/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml @@ -22,42 +22,39 @@ U+0915: "क" DEVANAGARI LETTER KA U+0916: "ख" DEVANAGARI LETTER KHA U+0917: "ग" DEVANAGARI LETTER GA --> - <string name="label_to_alpha_key">कखग</string> + <string name="keylabel_to_alpha">कखग</string> <!-- U+0967: "१" DEVANAGARI DIGIT ONE --> - <string name="keylabel_for_symbols_1">१</string> + <string name="keyspec_symbols_1">१</string> <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> - <string name="keylabel_for_symbols_2">२</string> + <string name="keyspec_symbols_2">२</string> <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> - <string name="keylabel_for_symbols_3">३</string> + <string name="keyspec_symbols_3">३</string> <!-- U+096A: "४" DEVANAGARI DIGIT FOUR --> - <string name="keylabel_for_symbols_4">४</string> + <string name="keyspec_symbols_4">४</string> <!-- U+096B: "५" DEVANAGARI DIGIT FIVE --> - <string name="keylabel_for_symbols_5">५</string> + <string name="keyspec_symbols_5">५</string> <!-- U+096C: "६" DEVANAGARI DIGIT SIX --> - <string name="keylabel_for_symbols_6">६</string> + <string name="keyspec_symbols_6">६</string> <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN --> - <string name="keylabel_for_symbols_7">७</string> + <string name="keyspec_symbols_7">७</string> <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT --> - <string name="keylabel_for_symbols_8">८</string> + <string name="keyspec_symbols_8">८</string> <!-- U+096F: "९" DEVANAGARI DIGIT NINE --> - <string name="keylabel_for_symbols_9">९</string> + <string name="keyspec_symbols_9">९</string> <!-- U+0966: "०" DEVANAGARI DIGIT ZERO --> - <string name="keylabel_for_symbols_0">०</string> + <string name="keyspec_symbols_0">०</string> <!-- Label for "switch to symbols" key. --> - <string name="label_to_symbol_key">\?१२३</string> - <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - part because it'll be appended by the code. --> - <string name="label_to_symbol_with_microphone_key">१२३</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> - <string name="additional_more_keys_for_symbols_0">0</string> + <string name="keylabel_to_symbol">?१२३</string> + <string name="additional_morekeys_symbols_1">1</string> + <string name="additional_morekeys_symbols_2">2</string> + <string name="additional_morekeys_symbols_3">3</string> + <string name="additional_morekeys_symbols_4">4</string> + <string name="additional_morekeys_symbols_5">5</string> + <string name="additional_morekeys_symbols_6">6</string> + <string name="additional_morekeys_symbols_7">7</string> + <string name="additional_morekeys_symbols_8">8</string> + <string name="additional_morekeys_symbols_9">9</string> + <string name="additional_morekeys_symbols_0">0</string> <!-- U+20B9: "₹" INDIAN RUPEE SIGN --> - <string name="keylabel_for_currency">₹</string> + <string name="keyspec_currency">₹</string> </resources> diff --git a/tools/make-keyboard-text/res/values-hr/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hr/donottranslate-more-keys.xml index 022bd2a87..73e51db4f 100644 --- a/tools/make-keyboard-text/res/values-hr/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-hr/donottranslate-more-keys.xml @@ -21,20 +21,20 @@ <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+00DF: "ß" LATIN SMALL LETTER SHARP S --> - <string name="more_keys_for_s">š,ś,ß</string> + <string name="morekeys_s">š,ś,ß</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE --> - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="morekeys_z">ž,ź,ż</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> - <string name="more_keys_for_c">č,ć,ç</string> + <string name="morekeys_c">č,ć,ç</string> <!-- U+0111: "đ" LATIN SMALL LETTER D WITH STROKE --> - <string name="more_keys_for_d">đ</string> + <string name="morekeys_d">đ</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-hu/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hu/donottranslate-more-keys.xml index ce2f5d057..a394a9722 100644 --- a/tools/make-keyboard-text/res/values-hu/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-hu/donottranslate-more-keys.xml @@ -26,7 +26,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,à,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">á,à,â,ä,æ,ã,å,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -34,14 +34,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">é,è,ê,ë,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,î,ï,ì,į,ī</string> + <string name="morekeys_i">í,î,ï,ì,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE @@ -51,14 +51,14 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ö,ő,ô,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ö,ő,ô,ò,õ,œ,ø,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,ű,û,ù,ū</string> + <string name="morekeys_u">ú,ü,ű,û,ù,ū</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-hy-rAM/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hy-rAM/donottranslate-more-keys.xml new file mode 100644 index 000000000..1e051190c --- /dev/null +++ b/tools/make-keyboard-text/res/values-hy-rAM/donottranslate-more-keys.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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"> + <!-- Label for "switch to alphabetic" key. + U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB + U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN + U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM --> + <string name="keylabel_to_alpha">ԱԲԳ</string> + <!-- U+055E: "՞" ARMENIAN QUESTION MARK + U+055C: "՜" ARMENIAN EXCLAMATION MARK + U+055A: "՚" ARMENIAN APOSTROPHE + U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING + U+055D: "՝" ARMENIAN COMMA + U+055B: "՛" ARMENIAN EMPHASIS MARK + U+058A: "֊" ARMENIAN HYPHEN + U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + U+055F: "՟" ARMENIAN ABBREVIATION MARK --> + <string name="morekeys_punctuation">"!autoColumnOrder!8,\\,,՞,՜,.,՚,ՙ,?,!,՝,՛,֊,»,«,՟,;,:"</string> + <!-- U+055E: "՞" ARMENIAN QUESTION MARK + U+00BF: "¿" INVERTED QUESTION MARK --> + <string name="morekeys_question">՞,¿</string> + <!-- U+055C: "՜" ARMENIAN EXCLAMATION MARK + U+00A1: "¡" INVERTED EXCLAMATION MARK --> + <string name="morekeys_exclamation">՜,¡</string> + <!-- U+058F: "֏" ARMENIAN DRAM SIGN --> + <!-- TODO: Enable this when we have glyph for the following letter + <string name="keyspec_currency">֏</string> + --> + <!-- U+055D: "՝" ARMENIAN COMMA --> + <string name="keyspec_tablet_comma">՝</string> + <!-- U+0589: "։" ARMENIAN FULL STOP --> + <string name="keyspec_period">։</string> + <string name="keyspec_tablet_period">։</string> + <string name="morekeys_tablet_period">!text/morekeys_punctuation</string> +</resources> diff --git a/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml deleted file mode 100644 index 2f34128bd..000000000 --- a/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, 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"> - <!-- U+058A: "֊" ARMENIAN HYPHEN --> - <!-- U+055C: "՜" ARMENIAN EXCLAMATION MARK --> - <!-- U+055D: "՝" ARMENIAN COMMA --> - <!-- U+055E: "՞" ARMENIAN QUESTION MARK --> - <!-- U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING --> - <!-- U+055A: "՚" ARMENIAN APOSTROPHE --> - <!-- U+055B: "՛" ARMENIAN EMPHASIS MARK --> - <!-- U+055F: "՟" ARMENIAN ABBREVIATION MARK --> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,!,?,\\,,.,֊,՜,՝,՞,:,;,\@,ՙ,՚,՛,՟"</string> - <!-- U+055E: "՞" ARMENIAN QUESTION MARK --> - <!-- U+00BF: "¿" INVERTED QUESTION MARK --> - <string name="more_keys_for_symbols_question">՞,¿</string> - <!-- U+055C: "՜" ARMENIAN EXCLAMATION MARK --> - <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK --> - <string name="more_keys_for_symbols_exclamation">՜,¡</string> - <!-- U+058F: "֏" ARMENIAN DRAM SIGN --> - <!-- TODO: Enable this when we have glyph for the following letter - <string name="keylabel_for_currency">֏</string> - --> -</resources> diff --git a/tools/make-keyboard-text/res/values-is/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-is/donottranslate-more-keys.xml index 4b4d986b8..ea7f86f1f 100644 --- a/tools/make-keyboard-text/res/values-is/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-is/donottranslate-more-keys.xml @@ -26,7 +26,7 @@ U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,ä,æ,å,à,â,ã,ā</string> + <string name="morekeys_a">á,ä,æ,å,à,â,ã,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE @@ -34,14 +34,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,ë,è,ê,ę,ė,ē</string> + <string name="morekeys_e">é,ë,è,ê,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,ï,î,ì,į,ī</string> + <string name="morekeys_i">í,ï,î,ì,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -50,26 +50,20 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ö,ô,ò,õ,œ,ø,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,û,ù,ū</string> + <string name="morekeys_u">ú,ü,û,ù,ū</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+00F0: "ð" LATIN SMALL LETTER ETH --> - <string name="more_keys_for_d">ð</string> + <string name="morekeys_d">ð</string> <!-- U+00FE: "þ" LATIN SMALL LETTER THORN --> - <string name="more_keys_for_t">þ</string> - <!-- U+00F0: "ð" LATIN SMALL LETTER ETH --> - <string name="keylabel_for_nordic_row1_11">ð</string> - <!-- U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="keylabel_for_nordic_row2_10">æ</string> - <!-- U+00FE: "þ" LATIN SMALL LETTER THORN --> - <string name="keylabel_for_nordic_row2_11">þ</string> + <string name="morekeys_t">þ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-it/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-it/donottranslate-more-keys.xml index 17dd03108..e809f4835 100644 --- a/tools/make-keyboard-text/res/values-it/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-it/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā,ª</string> + <string name="morekeys_a">à,á,â,ä,æ,ã,å,ā,ª</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -35,14 +35,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">è,é,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">è,é,ê,ë,ę,ė,ē</string> <!-- U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">ì,í,î,ï,į,ī</string> + <string name="morekeys_i">ì,í,î,ï,į,ī</string> <!-- U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -52,11 +52,23 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ò,ó,ô,ö,õ,œ,ø,ō,º</string> + <string name="morekeys_o">ò,ó,ô,ö,õ,œ,ø,ō,º</string> <!-- U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ù,ú,û,ü,ū</string> + <string name="morekeys_u">ù,ú,û,ü,ū</string> + <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> + <string name="keyspec_swiss_row1_11">ü</string> + <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE --> + <string name="morekeys_swiss_row1_11">è</string> + <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> + <string name="keyspec_swiss_row2_10">ö</string> + <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE --> + <string name="morekeys_swiss_row2_10">é</string> + <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> + <string name="keyspec_swiss_row2_11">ä</string> + <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE --> + <string name="morekeys_swiss_row2_11">à</string> </resources> diff --git a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml index 994e35ae9..0decb8fa2 100644 --- a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml @@ -22,40 +22,36 @@ U+05D0: "א" HEBREW LETTER ALEF U+05D1: "ב" HEBREW LETTER BET U+05D2: "ג" HEBREW LETTER GIMEL --> - <string name="label_to_alpha_key">אבג</string> + <string name="keylabel_to_alpha">אבג</string> <!-- U+2605: "★" BLACK STAR --> - <string name="more_keys_for_star">★</string> + <string name="morekeys_star">★</string> <!-- U+00B1: "±" PLUS-MINUS SIGN U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN --> - <string name="more_keys_for_plus">±,﬩</string> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,;,/,(|),)|(,#,!,\\,,\?,&,\\%,+,\",-,:,',\@"</string> + <string name="morekeys_plus">±,﬩</string> <!-- The all letters need to be mirrored are found at http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> - <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!3,<|>,{|},[|]</string> - <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!3,>|<,}|{,]|[</string> <!-- U+2264: "≤" LESS-THAN OR EQUAL TO U+2265: "≥" GREATER-THAN EQUAL TO U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK --> - <string name="more_keys_for_less_than">!fixedColumnOrder!3,‹|›,≤|≥,«|»</string> - <string name="more_keys_for_greater_than">!fixedColumnOrder!3,›|‹,≥|≤,»|«</string> - <!-- The following characters don't need BIDI mirroring. - U+2018: "‘" LEFT SINGLE QUOTATION MARK - U+2019: "’" RIGHT SINGLE QUOTATION MARK - U+201A: "‚" SINGLE LOW-9 QUOTATION MARK - U+201C: "“" LEFT DOUBLE QUOTATION MARK - U+201D: "”" RIGHT DOUBLE QUOTATION MARK - U+201E: "„" DOUBLE LOW-9 QUOTATION MARK --> - <string name="single_quotes">‘,’,‚</string> - <string name="double_quotes">“,”,„</string> - <string name="single_angle_quotes">!text/single_laqm_raqm_rtl</string> - <string name="double_angle_quotes">!text/double_laqm_raqm_rtl</string> + <string name="keyspec_left_parenthesis">(|)</string> + <string name="keyspec_right_parenthesis">)|(</string> + <string name="keyspec_left_square_bracket">[|]</string> + <string name="keyspec_right_square_bracket">]|[</string> + <string name="keyspec_left_curly_bracket">{|}</string> + <string name="keyspec_right_curly_bracket">}|{</string> + <string name="keyspec_less_than"><|></string> + <string name="keyspec_greater_than">>|<</string> + <string name="keyspec_less_than_equal">≤|≥</string> + <string name="keyspec_greater_than_equal">≥|≤</string> + <string name="keyspec_left_double_angle_quote">«|»</string> + <string name="keyspec_right_double_angle_quote">»|«</string> + <string name="keyspec_left_single_angle_quote">‹|›</string> + <string name="keyspec_right_single_angle_quote">›|‹</string> + <string name="single_quotes">!text/single_rqm_9qm</string> + <string name="double_quotes">!text/double_rqm_9qm</string> <!-- U+20AA: "₪" NEW SHEQEL SIGN --> - <string name="keylabel_for_currency">₪</string> - <string name="keyhintlabel_for_tablet_comma">!</string> - <string name="more_keys_for_tablet_comma">!</string> - <string name="keyhintlabel_for_period">\?</string> - <string name="more_keys_for_period">\?</string> + <string name="keyspec_currency">₪</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ka/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ka-rGE/donottranslate-more-keys.xml index 8c2add44c..f458c02e3 100644 --- a/tools/make-keyboard-text/res/values-ka/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ka-rGE/donottranslate-more-keys.xml @@ -22,7 +22,7 @@ U+10D0: "ა" GEORGIAN LETTER AN U+10D1: "ბ" GEORGIAN LETTER BAN U+10D2: "გ" GEORGIAN LETTER GAN --> - <string name="label_to_alpha_key">აბგ</string> + <string name="keylabel_to_alpha">აბგ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-kk/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-kk/donottranslate-more-keys.xml index 0e953ff21..5e18128da 100644 --- a/tools/make-keyboard-text/res/values-kk/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-kk/donottranslate-more-keys.xml @@ -19,39 +19,37 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> - <string name="keylabel_for_east_slavic_row1_9">щ</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="keylabel_for_east_slavic_row1_12">ъ</string> + <string name="keyspec_east_slavic_row1_9">щ</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> - <string name="keylabel_for_east_slavic_row2_1">ы</string> + <string name="keyspec_east_slavic_row2_2">ы</string> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> - <string name="keylabel_for_east_slavic_row2_11">э</string> + <string name="keyspec_east_slavic_row2_11">э</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> - <string name="keylabel_for_east_slavic_row3_5">и</string> + <string name="keyspec_east_slavic_row3_5">и</string> <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE --> - <string name="more_keys_for_cyrillic_u">ү,ұ</string> + <string name="morekeys_cyrillic_u">ү,ұ</string> <!-- U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER --> - <string name="more_keys_for_cyrillic_ka">қ</string> + <string name="morekeys_cyrillic_ka">қ</string> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="more_keys_for_cyrillic_ie">ё</string> + <string name="morekeys_cyrillic_ie">ё</string> <!-- U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER --> - <string name="more_keys_for_cyrillic_en">ң</string> + <string name="morekeys_cyrillic_en">ң</string> <!-- U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE --> - <string name="more_keys_for_cyrillic_ghe">ғ</string> + <string name="morekeys_cyrillic_ghe">ғ</string> <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I --> - <string name="more_keys_for_east_slavic_row2_1">і</string> + <string name="morekeys_east_slavic_row2_2">і</string> <!-- U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA --> - <string name="more_keys_for_cyrillic_a">ә</string> + <string name="morekeys_cyrillic_a">ә</string> <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O --> - <string name="more_keys_for_cyrillic_o">ө</string> + <string name="morekeys_cyrillic_o">ө</string> <!-- U+04BB: "һ" CYRILLIC SMALL LETTER SHHA --> - <string name="more_keys_for_east_slavic_row2_11">һ</string> + <string name="morekeys_east_slavic_row2_11">һ</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> + <string name="morekeys_cyrillic_soft_sign">ъ</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> </resources> diff --git a/tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-km-rKH/donottranslate-more-keys.xml index c33831c56..edd3753b7 100644 --- a/tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-km-rKH/donottranslate-more-keys.xml @@ -22,8 +22,7 @@ U+1780: "ក" KHMER LETTER KA U+1781: "ខ" KHMER LETTER KHA U+1782: "គ" KHMER LETTER KO --> - <string name="label_to_alpha_key">កខគ</string> + <string name="keylabel_to_alpha">កខគ</string> <!-- U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL --> - <string name="more_keys_for_currency_dollar">៛,¢,£,€,¥,₱</string> - + <string name="morekeys_currency_dollar">៛,¢,£,€,¥,₱</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ky/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ky/donottranslate-more-keys.xml index 8d8c5fbf2..3d885bf72 100644 --- a/tools/make-keyboard-text/res/values-ky/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ky/donottranslate-more-keys.xml @@ -19,28 +19,26 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> - <string name="keylabel_for_east_slavic_row1_9">щ</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="keylabel_for_east_slavic_row1_12">ъ</string> + <string name="keyspec_east_slavic_row1_9">щ</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> - <string name="keylabel_for_east_slavic_row2_1">ы</string> + <string name="keyspec_east_slavic_row2_2">ы</string> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> - <string name="keylabel_for_east_slavic_row2_11">э</string> + <string name="keyspec_east_slavic_row2_11">э</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> - <string name="keylabel_for_east_slavic_row3_5">и</string> + <string name="keyspec_east_slavic_row3_5">и</string> <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U --> - <string name="more_keys_for_cyrillic_u">ү</string> + <string name="morekeys_cyrillic_u">ү</string> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="more_keys_for_cyrillic_ie">ё</string> + <string name="morekeys_cyrillic_ie">ё</string> <!-- U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER --> - <string name="more_keys_for_cyrillic_en">ң</string> + <string name="morekeys_cyrillic_en">ң</string> <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O --> - <string name="more_keys_for_cyrillic_o">ө</string> + <string name="morekeys_cyrillic_o">ө</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> + <string name="morekeys_cyrillic_soft_sign">ъ</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> </resources> diff --git a/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-lo-rLA/donottranslate-more-keys.xml index 1d8ffa8cf..1059930e4 100644 --- a/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-lo-rLA/donottranslate-more-keys.xml @@ -22,7 +22,7 @@ U+0E81: "ກ" LAO LETTER KO U+0E82: "ຂ" LAO LETTER KHO SUNG U+0E84: "ຄ" LAO LETTER KHO TAM --> - <string name="label_to_alpha_key">ກຂຄ</string> + <string name="keylabel_to_alpha">ກຂຄ</string> <!-- U+20AD: "₭" KIP SIGN --> - <string name="keylabel_for_currency">₭</string> + <string name="keyspec_currency">₭</string> </resources> diff --git a/tools/make-keyboard-text/res/values-lt/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-lt/donottranslate-more-keys.xml index 7e2b8a076..8b6a1b2b6 100644 --- a/tools/make-keyboard-text/res/values-lt/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-lt/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="more_keys_for_a">ą,ä,ā,à,á,â,ã,å,æ</string> + <string name="morekeys_a">ą,ä,ā,à,á,â,ã,å,æ</string> <!-- U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0113: "ē" LATIN SMALL LETTER E WITH MACRON @@ -36,7 +36,7 @@ U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+011B: "ě" LATIN SMALL LETTER E WITH CARON --> - <string name="more_keys_for_e">ė,ę,ē,è,é,ê,ë,ě</string> + <string name="morekeys_e">ė,ę,ē,è,é,ê,ë,ě</string> <!-- U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE @@ -44,7 +44,7 @@ U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+0131: "ı" LATIN SMALL LETTER DOTLESS I --> - <string name="more_keys_for_i">į,ī,ì,í,î,ï,ı</string> + <string name="morekeys_i">į,ī,ì,í,î,ï,ı</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -53,7 +53,7 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_o">ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="morekeys_o">ö,õ,ò,ó,ô,œ,ő,ø</string> <!-- U+016B: "ū" LATIN SMALL LETTER U WITH MACRON U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS @@ -63,47 +63,46 @@ U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE --> - <string name="more_keys_for_u">ū,ų,ü,ū,ù,ú,û,ů,ű</string> + <string name="morekeys_u">ū,ų,ü,ū,ù,ú,û,ů,ű</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA --> - <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="morekeys_s">š,ß,ś,ş</string> <!-- U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ņ,ñ,ń,ń</string> + <string name="morekeys_n">ņ,ñ,ń</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> <!-- U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA U+0159: "ř" LATIN SMALL LETTER R WITH CARON U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE --> - <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="morekeys_r">ŗ,ř,ŕ</string> <!-- U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA U+0165: "ť" LATIN SMALL LETTER T WITH CARON --> - <string name="more_keys_for_t">ţ,ť</string> + <string name="morekeys_t">ţ,ť</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE --> - <string name="more_keys_for_z">ž,ż,ź</string> + <string name="morekeys_z">ž,ż,ź</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA --> - <string name="more_keys_for_k">ķ</string> + <string name="morekeys_k">ķ</string> <!-- U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+0142: "ł" LATIN SMALL LETTER L WITH STROKE U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013E: "ľ" LATIN SMALL LETTER L WITH CARON --> - <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="morekeys_l">ļ,ł,ĺ,ľ</string> <!-- U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ģ,ğ</string> + <string name="morekeys_g">ģ,ğ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-lv/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-lv/donottranslate-more-keys.xml index c64e37bc8..83f83fc99 100644 --- a/tools/make-keyboard-text/res/values-lv/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-lv/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+00E6: "æ" LATIN SMALL LETTER AE U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK --> - <string name="more_keys_for_a">ā,à,á,â,ã,ä,å,æ,ą</string> + <string name="morekeys_a">ā,à,á,â,ã,ä,å,æ,ą</string> <!-- U+0113: "ē" LATIN SMALL LETTER E WITH MACRON U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE @@ -36,7 +36,7 @@ U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+011B: "ě" LATIN SMALL LETTER E WITH CARON --> - <string name="more_keys_for_e">ē,ė,è,é,ê,ë,ę,ě</string> + <string name="morekeys_e">ē,ė,è,é,ê,ë,ę,ě</string> <!-- U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE @@ -44,7 +44,7 @@ U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+0131: "ı" LATIN SMALL LETTER DOTLESS I --> - <string name="more_keys_for_i">ī,į,ì,í,î,ï,ı</string> + <string name="morekeys_i">ī,į,ì,í,î,ï,ı</string> <!-- U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -53,7 +53,7 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_o">ò,ó,ô,õ,ö,œ,ő,ø</string> + <string name="morekeys_o">ò,ó,ô,õ,ö,œ,ő,ø</string> <!-- U+016B: "ū" LATIN SMALL LETTER U WITH MACRON U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE @@ -62,47 +62,46 @@ U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE --> - <string name="more_keys_for_u">ū,ų,ù,ú,û,ü,ů,ű</string> + <string name="morekeys_u">ū,ų,ù,ú,û,ü,ů,ű</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA --> - <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="morekeys_s">š,ß,ś,ş</string> <!-- U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ņ,ñ,ń,ń</string> + <string name="morekeys_n">ņ,ñ,ń</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> <!-- U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA U+0159: "ř" LATIN SMALL LETTER R WITH CARON U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE --> - <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="morekeys_r">ŗ,ř,ŕ</string> <!-- U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA U+0165: "ť" LATIN SMALL LETTER T WITH CARON --> - <string name="more_keys_for_t">ţ,ť</string> + <string name="morekeys_t">ţ,ť</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE --> - <string name="more_keys_for_z">ž,ż,ź</string> + <string name="morekeys_z">ž,ż,ź</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA --> - <string name="more_keys_for_k">ķ</string> + <string name="morekeys_k">ķ</string> <!-- U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+0142: "ł" LATIN SMALL LETTER L WITH STROKE U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013E: "ľ" LATIN SMALL LETTER L WITH CARON --> - <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="morekeys_l">ļ,ł,ĺ,ľ</string> <!-- U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ģ,ğ</string> + <string name="morekeys_g">ģ,ğ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-mk/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-mk/donottranslate-more-keys.xml index 2db75c8f5..1ab1354c8 100644 --- a/tools/make-keyboard-text/res/values-mk/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-mk/donottranslate-more-keys.xml @@ -19,22 +19,22 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE --> - <string name="keylabel_for_south_slavic_row1_6">ѕ</string> + <string name="keyspec_south_slavic_row1_6">ѕ</string> <!-- U+045C: "ќ" CYRILLIC SMALL LETTER KJE --> - <string name="keylabel_for_south_slavic_row2_11">ќ</string> + <string name="keyspec_south_slavic_row2_11">ќ</string> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> - <string name="keylabel_for_south_slavic_row3_1">з</string> + <string name="keyspec_south_slavic_row3_1">з</string> <!-- U+0453: "ѓ" CYRILLIC SMALL LETTER GJE --> - <string name="keylabel_for_south_slavic_row3_8">ѓ</string> + <string name="keyspec_south_slavic_row3_8">ѓ</string> <!-- U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE --> - <string name="more_keys_for_cyrillic_ie">ѐ</string> + <string name="morekeys_cyrillic_ie">ѐ</string> <!-- U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE --> - <string name="more_keys_for_cyrillic_i">ѝ</string> + <string name="morekeys_cyrillic_i">ѝ</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-mn-rMN/donottranslate-more-keys.xml index a7f366685..3fafb397b 100644 --- a/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-mn-rMN/donottranslate-more-keys.xml @@ -22,7 +22,7 @@ U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <!-- U+20AE: "₮" TUGRIK SIGN --> - <string name="keylabel_for_currency">₮</string> + <string name="keyspec_currency">₮</string> </resources> diff --git a/tools/make-keyboard-text/res/values-my-rMM/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-my-rMM/donottranslate-more-keys.xml new file mode 100644 index 000000000..f408f588a --- /dev/null +++ b/tools/make-keyboard-text/res/values-my-rMM/donottranslate-more-keys.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, 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"> + <!-- Label for "switch to alphabetic" key. + U+1000: "က" MYANMAR LETTER KA + U+1001: "ခ" MYANMAR LETTER KHA + U+1002: "ဂ" MYANMAR LETTER GA --> + <string name="keylabel_to_alpha">ကခဂ</string> + <!-- U+104A: "၊" MYANMAR SIGN LITTLE SECTION + U+104B: "။" MYANMAR SIGN SECTION --> + <string name="keyspec_tablet_comma">၊</string> + <string name="morekeys_tablet_comma">"\\,"</string> + <string name="keyspec_tablet_period">။</string> + <string name="keyspec_period">။</string> + <string name="keyhintlabel_period">၊</string> + <string name="morekeys_punctuation">"!autoColumnOrder!9,၊,.,?,!,#,),(,/,;,...,',@,:,-,\",+,\\%,&"</string> + <string name="morekeys_tablet_punctuation">"!autoColumnOrder!8,.,',#,),(,/,;,@,...,:,-,\",+,\\%,&"</string> +</resources> diff --git a/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml index 2cecb5e65..c5307a98d 100644 --- a/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml @@ -24,7 +24,7 @@ U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">à,ä,á,â,ã,ā</string> + <string name="morekeys_a">à,ä,á,â,ã,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -32,7 +32,7 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <string name="morekeys_e">é,è,ê,ë,ę,ė,ē</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE @@ -40,23 +40,23 @@ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ô,ò,ó,ö,õ,œ,ō</string> + <string name="morekeys_o">ô,ò,ó,ö,õ,œ,ō</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ü,û,ù,ú,ū</string> + <string name="morekeys_u">ü,û,ù,ú,ū</string> <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE --> - <string name="keylabel_for_nordic_row1_11">å</string> + <string name="keyspec_nordic_row1_11">å</string> <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="keylabel_for_nordic_row2_10">ø</string> + <string name="keyspec_nordic_row2_10">ø</string> <!-- U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="keylabel_for_nordic_row2_11">æ</string> + <string name="keyspec_nordic_row2_11">æ</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> - <string name="more_keys_for_nordic_row2_10">ö</string> + <string name="morekeys_nordic_row2_10">ö</string> <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> - <string name="more_keys_for_nordic_row2_11">ä</string> + <string name="morekeys_nordic_row2_11">ä</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml new file mode 100644 index 000000000..97c50d1b8 --- /dev/null +++ b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, 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"> + <!-- Label for "switch to alphabetic" key. + U+0915: "क" DEVANAGARI LETTER KA + U+0916: "ख" DEVANAGARI LETTER KHA + U+0917: "ग" DEVANAGARI LETTER GA --> + <string name="keylabel_to_alpha">कखग</string> + <!-- U+0967: "१" DEVANAGARI DIGIT ONE --> + <string name="keyspec_symbols_1">१</string> + <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> + <string name="keyspec_symbols_2">२</string> + <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> + <string name="keyspec_symbols_3">३</string> + <!-- U+096A: "४" DEVANAGARI DIGIT FOUR --> + <string name="keyspec_symbols_4">४</string> + <!-- U+096B: "५" DEVANAGARI DIGIT FIVE --> + <string name="keyspec_symbols_5">५</string> + <!-- U+096C: "६" DEVANAGARI DIGIT SIX --> + <string name="keyspec_symbols_6">६</string> + <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN --> + <string name="keyspec_symbols_7">७</string> + <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT --> + <string name="keyspec_symbols_8">८</string> + <!-- U+096F: "९" DEVANAGARI DIGIT NINE --> + <string name="keyspec_symbols_9">९</string> + <!-- U+0966: "०" DEVANAGARI DIGIT ZERO --> + <string name="keyspec_symbols_0">०</string> + <!-- Label for "switch to symbols" key. --> + <string name="keylabel_to_symbol">?१२३</string> + <string name="additional_morekeys_symbols_1">1</string> + <string name="additional_morekeys_symbols_2">2</string> + <string name="additional_morekeys_symbols_3">3</string> + <string name="additional_morekeys_symbols_4">4</string> + <string name="additional_morekeys_symbols_5">5</string> + <string name="additional_morekeys_symbols_6">6</string> + <string name="additional_morekeys_symbols_7">7</string> + <string name="additional_morekeys_symbols_8">8</string> + <string name="additional_morekeys_symbols_9">9</string> + <string name="additional_morekeys_symbols_0">0</string> + <!-- U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN --> + <string name="keyspec_currency">रु.</string> +</resources> diff --git a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml deleted file mode 100644 index 9205e5309..000000000 --- a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2013, 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"> - <!-- Label for "switch to alphabetic" key. - U+0915: "क" DEVANAGARI LETTER KA - U+0916: "ख" DEVANAGARI LETTER KHA - U+0917: "ग" DEVANAGARI LETTER GA --> - <string name="label_to_alpha_key">कखग</string> - <!-- U+0967: "१" DEVANAGARI DIGIT ONE --> - <string name="keylabel_for_symbols_1">१</string> - <!-- U+0968: "२" DEVANAGARI DIGIT TWO --> - <string name="keylabel_for_symbols_2">२</string> - <!-- U+0969: "३" DEVANAGARI DIGIT THREE --> - <string name="keylabel_for_symbols_3">३</string> - <!-- U+096A: "४" DEVANAGARI DIGIT FOUR --> - <string name="keylabel_for_symbols_4">४</string> - <!-- U+096B: "५" DEVANAGARI DIGIT FIVE --> - <string name="keylabel_for_symbols_5">५</string> - <!-- U+096C: "६" DEVANAGARI DIGIT SIX --> - <string name="keylabel_for_symbols_6">६</string> - <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN --> - <string name="keylabel_for_symbols_7">७</string> - <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT --> - <string name="keylabel_for_symbols_8">८</string> - <!-- U+096F: "९" DEVANAGARI DIGIT NINE --> - <string name="keylabel_for_symbols_9">९</string> - <!-- U+0966: "०" DEVANAGARI DIGIT ZERO --> - <string name="keylabel_for_symbols_0">०</string> - <!-- Label for "switch to symbols" key. --> - <string name="label_to_symbol_key">\?१२३</string> - <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - part because it'll be appended by the code. --> - <string name="label_to_symbol_with_microphone_key">१२३</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> - <string name="additional_more_keys_for_symbols_0">0</string> - <!-- U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN --> - <string name="keylabel_for_currency">रु.</string> -</resources> diff --git a/tools/make-keyboard-text/res/values-nl/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-nl/donottranslate-more-keys.xml index e5d82951a..f9a26c540 100644 --- a/tools/make-keyboard-text/res/values-nl/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-nl/donottranslate-more-keys.xml @@ -26,7 +26,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">á,ä,â,à,æ,ã,å,ā</string> + <string name="morekeys_a">á,ä,â,à,æ,ã,å,ā</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -34,7 +34,7 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,ë,ê,è,ę,ė,ē</string> + <string name="morekeys_e">é,ë,ê,è,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE @@ -42,7 +42,7 @@ U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_i">í,ï,ì,î,į,ī,ij</string> + <string name="morekeys_i">í,ï,ì,î,į,ī,ij</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -51,18 +51,18 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ö,ô,ò,õ,œ,ø,ō</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,û,ù,ū</string> + <string name="morekeys_u">ú,ü,û,ù,ū</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_y">ij</string> + <string name="morekeys_y">ij</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-pl/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-pl/donottranslate-more-keys.xml index b5cf6a0fa..8a87db41e 100644 --- a/tools/make-keyboard-text/res/values-pl/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-pl/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">ą,á,à,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">ą,á,à,â,ä,æ,ã,å,ā</string> <!-- U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE @@ -35,7 +35,7 @@ U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">ę,è,é,ê,ë,ė,ē</string> + <string name="morekeys_e">ę,è,é,ê,ë,ė,ē</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -44,24 +44,24 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="morekeys_o">ó,ö,ô,ò,õ,œ,ø,ō</string> <!-- U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+00DF: "ß" LATIN SMALL LETTER SHARP S U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ś,ß,š</string> + <string name="morekeys_s">ś,ß,š</string> <!-- U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="more_keys_for_n">ń,ñ</string> + <string name="morekeys_n">ń,ñ</string> <!-- U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ć,ç,č</string> + <string name="morekeys_c">ć,ç,č</string> <!-- U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017E: "ž" LATIN SMALL LETTER Z WITH CARON --> - <string name="more_keys_for_z">ż,ź,ž</string> + <string name="morekeys_z">ż,ź,ž</string> <!-- U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ł</string> + <string name="morekeys_l">ł</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-pt/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-pt/donottranslate-more-keys.xml index 0c9065f27..f3f667efc 100644 --- a/tools/make-keyboard-text/res/values-pt/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-pt/donottranslate-more-keys.xml @@ -26,7 +26,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+00E6: "æ" LATIN SMALL LETTER AE U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">á,ã,à,â,ä,å,æ,ª</string> + <string name="morekeys_a">á,ã,à,â,ä,å,æ,ª</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE @@ -34,14 +34,14 @@ U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS --> - <string name="more_keys_for_e">é,ê,è,ę,ė,ē,ë</string> + <string name="morekeys_e">é,ê,è,ę,ė,ē,ë</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,î,ì,ï,į,ī</string> + <string name="morekeys_i">í,î,ì,ï,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -51,15 +51,15 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ó,õ,ô,ò,ö,œ,ø,ō,º</string> + <string name="morekeys_o">ó,õ,ô,ò,ö,œ,ø,ō,º</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,ù,û,ū</string> + <string name="morekeys_u">ú,ü,ù,û,ū</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+010D: "č" LATIN SMALL LETTER C WITH CARON U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">ç,č,ć</string> + <string name="morekeys_c">ç,č,ć</string> </resources> diff --git a/tools/make-keyboard-text/res/values-rm/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-rm/donottranslate-more-keys.xml index aa0d7f817..2df401eb4 100644 --- a/tools/make-keyboard-text/res/values-rm/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-rm/donottranslate-more-keys.xml @@ -25,5 +25,5 @@ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+0153: "œ" LATIN SMALL LIGATURE OE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_o">ò,ó,ö,ô,õ,œ,ø</string> + <string name="morekeys_o">ò,ó,ö,ô,õ,œ,ø</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml index f399eb28e..6286c7bae 100644 --- a/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ro/donottranslate-more-keys.xml @@ -27,21 +27,21 @@ U+00E6: "æ" LATIN SMALL LETTER AE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">â,ã,ă,à,á,ä,æ,å,ā</string> + <string name="morekeys_a">â,ã,ă,à,á,ä,æ,å,ā</string> <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">î,ï,ì,í,į,ī</string> + <string name="morekeys_i">î,ï,ì,í,į,ī</string> <!-- U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ș,ß,ś,š</string> + <string name="morekeys_s">ș,ß,ś,š</string> <!-- U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW --> - <string name="more_keys_for_t">ț</string> + <string name="morekeys_t">ț</string> <string name="single_quotes">!text/single_9qm_rqm</string> <string name="double_quotes">!text/double_9qm_rqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-ru/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ru/donottranslate-more-keys.xml index f62c90ffc..2093ba88b 100644 --- a/tools/make-keyboard-text/res/values-ru/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ru/donottranslate-more-keys.xml @@ -19,24 +19,22 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> - <string name="keylabel_for_east_slavic_row1_9">щ</string> - <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="keylabel_for_east_slavic_row1_12">ъ</string> + <string name="keyspec_east_slavic_row1_9">щ</string> <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU --> - <string name="keylabel_for_east_slavic_row2_1">ы</string> + <string name="keyspec_east_slavic_row2_2">ы</string> <!-- U+044D: "э" CYRILLIC SMALL LETTER E --> - <string name="keylabel_for_east_slavic_row2_11">э</string> + <string name="keyspec_east_slavic_row2_11">э</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> - <string name="keylabel_for_east_slavic_row3_5">и</string> + <string name="keyspec_east_slavic_row3_5">и</string> <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO --> - <string name="more_keys_for_cyrillic_ie">ё</string> + <string name="morekeys_cyrillic_ie">ё</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> + <string name="morekeys_cyrillic_soft_sign">ъ</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-sk/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sk/donottranslate-more-keys.xml index 2ed538e5b..a05b70370 100644 --- a/tools/make-keyboard-text/res/values-sk/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-sk/donottranslate-more-keys.xml @@ -27,7 +27,7 @@ U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+00E6: "æ" LATIN SMALL LETTER AE U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK --> - <string name="more_keys_for_a">á,ä,ā,à,â,ã,å,æ,ą</string> + <string name="morekeys_a">á,ä,ā,à,â,ã,å,æ,ą</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+011B: "ě" LATIN SMALL LETTER E WITH CARON U+0113: "ē" LATIN SMALL LETTER E WITH MACRON @@ -36,7 +36,7 @@ U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK --> - <string name="more_keys_for_e">é,ě,ē,ė,è,ê,ë,ę</string> + <string name="morekeys_e">é,ě,ē,ė,è,ê,ë,ę</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+012F: "į" LATIN SMALL LETTER I WITH OGONEK @@ -44,7 +44,7 @@ U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+0131: "ı" LATIN SMALL LETTER DOTLESS I --> - <string name="more_keys_for_i">í,ī,į,ì,î,ï,ı</string> + <string name="morekeys_i">í,ī,į,ì,î,ï,ı</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -53,7 +53,7 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE --> - <string name="more_keys_for_o">ô,ó,ö,ò,õ,œ,ő,ø</string> + <string name="morekeys_o">ô,ó,ö,ò,õ,œ,ő,ø</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS @@ -62,48 +62,47 @@ U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE --> - <string name="more_keys_for_u">ú,ů,ü,ū,ų,ù,û,ű</string> + <string name="morekeys_u">ú,ů,ü,ū,ų,ù,û,ű</string> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA --> - <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="morekeys_s">š,ß,ś,ş</string> <!-- U+0148: "ň" LATIN SMALL LETTER N WITH CARON U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE - U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ň,ņ,ñ,ń,ń</string> + <string name="morekeys_n">ň,ņ,ñ,ń</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ</string> + <string name="morekeys_y">ý,ÿ</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> <!-- U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE U+0159: "ř" LATIN SMALL LETTER R WITH CARON U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA --> - <string name="more_keys_for_r">ŕ,ř,ŗ</string> + <string name="morekeys_r">ŕ,ř,ŗ</string> <!-- U+0165: "ť" LATIN SMALL LETTER T WITH CARON U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA --> - <string name="more_keys_for_t">ť,ţ</string> + <string name="morekeys_t">ť,ţ</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE --> - <string name="more_keys_for_z">ž,ż,ź</string> + <string name="morekeys_z">ž,ż,ź</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA --> - <string name="more_keys_for_k">ķ</string> + <string name="morekeys_k">ķ</string> <!-- U+013E: "ľ" LATIN SMALL LETTER L WITH CARON U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ľ,ĺ,ļ,ł</string> + <string name="morekeys_l">ľ,ĺ,ļ,ł</string> <!-- U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ģ,ğ</string> + <string name="morekeys_g">ģ,ğ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-sl/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sl/donottranslate-more-keys.xml index 1e5d1d71f..d529589a0 100644 --- a/tools/make-keyboard-text/res/values-sl/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-sl/donottranslate-more-keys.xml @@ -19,14 +19,14 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">š</string> + <string name="morekeys_s">š</string> <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE --> - <string name="more_keys_for_c">č,ć</string> + <string name="morekeys_c">č,ć</string> <!-- U+0111: "đ" LATIN SMALL LETTER D WITH STROKE --> - <string name="more_keys_for_d">đ</string> + <string name="morekeys_d">đ</string> <!-- U+017E: "ž" LATIN SMALL LETTER Z WITH CARON --> - <string name="more_keys_for_z">ž</string> + <string name="morekeys_z">ž</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-sr/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sr/donottranslate-more-keys.xml index c00d2a665..870a71331 100644 --- a/tools/make-keyboard-text/res/values-sr/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-sr/donottranslate-more-keys.xml @@ -23,37 +23,37 @@ U+0161: "š" LATIN SMALL LETTER S WITH CARON U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE - <string name="more_keys_for_s">š,ß,ś</string> + <string name="morekeys_s">š,ß,ś</string> U+010D: "č" LATIN SMALL LETTER C WITH CARON U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE - <string name="more_keys_for_c">č,ç,ć</string> + <string name="morekeys_c">č,ç,ć</string> U+010F: "ď" LATIN SMALL LETTER D WITH CARON - <string name="more_keys_for_d">ď</string> + <string name="morekeys_d">ď</string> U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="morekeys_z">ž,ź,ż</string> END: More keys definitions for Serbian (Latin) --> <!-- BEGIN: More keys definitions for Serbian (Cyrillic) --> <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE --> - <string name="keylabel_for_south_slavic_row1_6">з</string> + <string name="keyspec_south_slavic_row1_6">з</string> <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE --> - <string name="keylabel_for_south_slavic_row2_11">ћ</string> + <string name="keyspec_south_slavic_row2_11">ћ</string> <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE --> - <string name="keylabel_for_south_slavic_row3_1">ѕ</string> + <string name="keyspec_south_slavic_row3_1">ѕ</string> <!-- U+0452: "ђ" CYRILLIC SMALL LETTER DJE --> - <string name="keylabel_for_south_slavic_row3_8">ђ</string> + <string name="keyspec_south_slavic_row3_8">ђ</string> <!-- U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE --> - <string name="more_keys_for_cyrillic_ie">ѐ</string> + <string name="morekeys_cyrillic_ie">ѐ</string> <!-- U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE --> - <string name="more_keys_for_cyrillic_i">ѝ</string> + <string name="morekeys_cyrillic_i">ѝ</string> <!-- END: More keys definitions for Serbian (Cyrillic) --> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> diff --git a/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml index 2472364d0..ead514026 100644 --- a/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml @@ -23,72 +23,71 @@ U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE --> - <string name="more_keys_for_a">á,à,â,ą,ã</string> + <string name="morekeys_a">á,à,â,ą,ã</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,ć,č</string> <!-- U+00F0: "ð" LATIN SMALL LETTER ETH U+010F: "ď" LATIN SMALL LETTER D WITH CARON --> - <string name="more_keys_for_d">ð,ď</string> + <string name="morekeys_d">ð,ď</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK --> - <string name="more_keys_for_e">é,è,ê,ë,ę</string> + <string name="morekeys_e">é,è,ê,ë,ę</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS --> - <string name="more_keys_for_i">í,ì,î,ï</string> + <string name="morekeys_i">í,ì,î,ï</string> <!-- U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ł</string> + <string name="morekeys_l">ł</string> <!-- U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0148: "ň" LATIN SMALL LETTER N WITH CARON --> - <string name="more_keys_for_n">ń,ñ,ň</string> + <string name="morekeys_n">ń,ñ,ň</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ó,ò,ô,õ,ō</string> + <string name="morekeys_o">ó,ò,ô,õ,ō</string> <!-- U+0159: "ř" LATIN SMALL LETTER R WITH CARON --> - <string name="more_keys_for_r">ř</string> + <string name="morekeys_r">ř</string> <!-- U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA U+00DF: "ß" LATIN SMALL LETTER SHARP S --> - <string name="more_keys_for_s">ś,š,ş,ß</string> + <string name="morekeys_s">ś,š,ş,ß</string> <!-- U+0165: "ť" LATIN SMALL LETTER T WITH CARON U+00FE: "þ" LATIN SMALL LETTER THORN --> - <string name="more_keys_for_t">ť,þ</string> + <string name="morekeys_t">ť,þ</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ü,ú,ù,û,ū</string> + <string name="morekeys_u">ü,ú,ù,û,ū</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE - U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS - U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS --> - <string name="more_keys_for_y">ý,ÿ,ü</string> + U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS --> + <string name="morekeys_y">ý,ÿ</string> <!-- U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017E: "ž" LATIN SMALL LETTER Z WITH CARON U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE --> - <string name="more_keys_for_z">ź,ž,ż</string> + <string name="morekeys_z">ź,ž,ż</string> <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE --> - <string name="keylabel_for_nordic_row1_11">å</string> + <string name="keyspec_nordic_row1_11">å</string> <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_11">ä</string> + <string name="keyspec_nordic_row2_11">ä</string> <!-- U+00E6: "æ" LATIN SMALL LETTER AE --> - <string name="more_keys_for_nordic_row2_11">æ</string> + <string name="morekeys_nordic_row2_11">æ</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS --> - <string name="keylabel_for_nordic_row2_10">ö</string> + <string name="keyspec_nordic_row2_10">ö</string> <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+0153: "œ" LATIN SMALL LIGATURE OE --> - <string name="more_keys_for_nordic_row2_10">ø,œ</string> + <string name="morekeys_nordic_row2_10">ø,œ</string> <string name="single_angle_quotes">!text/single_raqm_laqm</string> <string name="double_angle_quotes">!text/double_raqm_laqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-sw/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sw/donottranslate-more-keys.xml index 968a80c1c..e06ae21cd 100644 --- a/tools/make-keyboard-text/res/values-sw/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-sw/donottranslate-more-keys.xml @@ -18,7 +18,7 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- This is the same as English except more_keys_for_g. --> + <!-- This is the same as English except morekeys_g. --> <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX @@ -27,19 +27,19 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">à,á,â,ä,æ,ã,å,ā</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">è,é,ê,ë,ē</string> + <string name="morekeys_e">è,é,ê,ë,ē</string> <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE --> - <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <string name="morekeys_i">î,ï,í,ī,ì</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -48,18 +48,18 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> - <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> + <string name="morekeys_o">ô,ö,ò,ó,œ,ø,ō,õ</string> <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">û,ü,ù,ú,ū</string> + <string name="morekeys_u">û,ü,ù,ú,ū</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S --> - <string name="more_keys_for_s">ß</string> + <string name="morekeys_s">ß</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="more_keys_for_n">ñ</string> + <string name="morekeys_n">ñ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> - <string name="more_keys_for_c">ç</string> - <string name="more_keys_for_g">g\'</string> + <string name="morekeys_c">ç</string> + <string name="morekeys_g">g\'</string> </resources> diff --git a/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml index 070c91526..3329cf241 100644 --- a/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml @@ -22,7 +22,7 @@ U+0E01: "ก" THAI CHARACTER KO KAI U+0E02: "ข" THAI CHARACTER KHO KHAI U+0E04: "ค" THAI CHARACTER KHO KHWAI --> - <string name="label_to_alpha_key">กขค</string> + <string name="keylabel_to_alpha">กขค</string> <!-- U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT --> - <string name="keylabel_for_currency">฿</string> + <string name="keyspec_currency">฿</string> </resources> diff --git a/tools/make-keyboard-text/res/values-tl/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-tl/donottranslate-more-keys.xml index 383d55ccf..cf25b6f43 100644 --- a/tools/make-keyboard-text/res/values-tl/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-tl/donottranslate-more-keys.xml @@ -28,7 +28,7 @@ U+00E6: "æ" LATIN SMALL LETTER AE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> + <string name="morekeys_a">á,à,ä,â,ã,å,ą,æ,ā,ª</string> <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS @@ -36,14 +36,14 @@ U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">é,è,ë,ê,ę,ė,ē</string> + <string name="morekeys_e">é,è,ë,ê,ę,ė,ē</string> <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="morekeys_i">í,ï,ì,î,į,ī</string> <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS @@ -53,18 +53,18 @@ U+0153: "œ" LATIN SMALL LIGATURE OE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <string name="morekeys_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ú,ü,ù,û,ū</string> + <string name="morekeys_u">ú,ü,ù,û,ū</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE --> - <string name="more_keys_for_n">ñ,ń</string> + <string name="morekeys_n">ñ,ń</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,ć,č</string> </resources> diff --git a/tools/make-keyboard-text/res/values-tr/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-tr/donottranslate-more-keys.xml index 1161811d4..db1108ff6 100644 --- a/tools/make-keyboard-text/res/values-tr/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-tr/donottranslate-more-keys.xml @@ -19,7 +19,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX --> - <string name="more_keys_for_a">â</string> + <string name="morekeys_a">â</string> <!-- U+0131: "ı" LATIN SMALL LETTER DOTLESS I U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS @@ -27,7 +27,7 @@ U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+012B: "ī" LATIN SMALL LETTER I WITH MACRON --> - <string name="more_keys_for_i">ı,î,ï,ì,í,į,ī</string> + <string name="morekeys_i">ı,î,ï,ì,í,į,ī</string> <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+0153: "œ" LATIN SMALL LIGATURE OE @@ -36,22 +36,22 @@ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON --> - <string name="more_keys_for_o">ö,ô,œ,ò,ó,õ,ø,ō</string> + <string name="morekeys_o">ö,ô,œ,ò,ó,õ,ø,ō</string> <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">ü,û,ù,ú,ū</string> + <string name="morekeys_u">ü,û,ù,ú,ū</string> <!-- U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+0161: "š" LATIN SMALL LETTER S WITH CARON --> - <string name="more_keys_for_s">ş,ß,ś,š</string> + <string name="morekeys_s">ş,ß,ś,š</string> <!-- U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE --> - <string name="more_keys_for_g">ğ</string> + <string name="morekeys_g">ğ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,č</string> + <string name="morekeys_c">ç,ć,č</string> </resources> diff --git a/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml index 6ee34e305..1f72d068b 100644 --- a/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml @@ -19,28 +19,26 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA --> - <string name="keylabel_for_east_slavic_row1_9">щ</string> - <!-- U+0457: "ї" CYRILLIC SMALL LETTER YI --> - <string name="keylabel_for_east_slavic_row1_12">ї</string> + <string name="keyspec_east_slavic_row1_9">щ</string> <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I --> - <string name="keylabel_for_east_slavic_row2_1">і</string> + <string name="keyspec_east_slavic_row2_2">і</string> <!-- U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE --> - <string name="keylabel_for_east_slavic_row2_11">є</string> + <string name="keyspec_east_slavic_row2_11">є</string> <!-- U+0438: "и" CYRILLIC SMALL LETTER I --> - <string name="keylabel_for_east_slavic_row3_5">и</string> + <string name="keyspec_east_slavic_row3_5">и</string> <!-- U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN --> - <string name="more_keys_for_cyrillic_ghe">ґ</string> + <string name="morekeys_cyrillic_ghe">ґ</string> <!-- U+0457: "ї" CYRILLIC SMALL LETTER YI --> - <string name="more_keys_for_east_slavic_row2_1">ї</string> + <string name="morekeys_east_slavic_row2_2">ї</string> <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN --> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> + <string name="morekeys_cyrillic_soft_sign">ъ</string> <!-- U+20B4: "₴" HRYVNIA SIGN --> - <string name="keylabel_for_currency">₴</string> + <string name="keyspec_currency">₴</string> <!-- Label for "switch to alphabetic" key. U+0410: "А" CYRILLIC CAPITAL LETTER A U+0411: "Б" CYRILLIC CAPITAL LETTER BE U+0412: "В" CYRILLIC CAPITAL LETTER VE --> - <string name="label_to_alpha_key">АБВ</string> + <string name="keylabel_to_alpha">АБВ</string> <string name="single_quotes">!text/single_9qm_lqm</string> <string name="double_quotes">!text/double_9qm_lqm</string> </resources> diff --git a/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml index f01f0687a..aa571700f 100644 --- a/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml @@ -35,7 +35,7 @@ U+1EA9: "ẩ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE U+1EAB: "ẫ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE U+1EAD: "ậ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW --> - <string name="more_keys_for_a">à,á,ả,ã,ạ,ă,ằ,ắ,ẳ,ẵ,ặ,â,ầ,ấ,ẩ,ẫ,ậ</string> + <string name="morekeys_a">à,á,ả,ã,ạ,ă,ằ,ắ,ẳ,ẵ,ặ,â,ầ,ấ,ẩ,ẫ,ậ</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE @@ -47,13 +47,13 @@ U+1EC3: "ể" LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE U+1EC5: "ễ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE U+1EC7: "ệ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW --> - <string name="more_keys_for_e">è,é,ẻ,ẽ,ẹ,ê,ề,ế,ể,ễ,ệ</string> + <string name="morekeys_e">è,é,ẻ,ẽ,ẹ,ê,ề,ế,ể,ễ,ệ</string> <!-- U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+1EC9: "ỉ" LATIN SMALL LETTER I WITH HOOK ABOVE U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW --> - <string name="more_keys_for_i">ì,í,ỉ,ĩ,ị</string> + <string name="morekeys_i">ì,í,ỉ,ĩ,ị</string> <!-- U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+1ECF: "ỏ" LATIN SMALL LETTER O WITH HOOK ABOVE @@ -71,7 +71,7 @@ U+1EDF: "ở" LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE U+1EE1: "ỡ" LATIN SMALL LETTER O WITH HORN AND TILDE U+1EE3: "ợ" LATIN SMALL LETTER O WITH HORN AND DOT BELOW --> - <string name="more_keys_for_o">ò,ó,ỏ,õ,ọ,ô,ồ,ố,ổ,ỗ,ộ,ơ,ờ,ớ,ở,ỡ,ợ</string> + <string name="morekeys_o">ò,ó,ỏ,õ,ọ,ô,ồ,ố,ổ,ỗ,ộ,ơ,ờ,ớ,ở,ỡ,ợ</string> <!-- U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+1EE7: "ủ" LATIN SMALL LETTER U WITH HOOK ABOVE @@ -83,15 +83,15 @@ U+1EED: "ử" LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW --> - <string name="more_keys_for_u">ù,ú,ủ,ũ,ụ,ư,ừ,ứ,ử,ữ,ự</string> + <string name="morekeys_u">ù,ú,ủ,ũ,ụ,ư,ừ,ứ,ử,ữ,ự</string> <!-- U+1EF3: "ỳ" LATIN SMALL LETTER Y WITH GRAVE U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+1EF7: "ỷ" LATIN SMALL LETTER Y WITH HOOK ABOVE U+1EF9: "ỹ" LATIN SMALL LETTER Y WITH TILDE U+1EF5: "ỵ" LATIN SMALL LETTER Y WITH DOT BELOW --> - <string name="more_keys_for_y">ỳ,ý,ỷ,ỹ,ỵ</string> + <string name="morekeys_y">ỳ,ý,ỷ,ỹ,ỵ</string> <!-- U+0111: "đ" LATIN SMALL LETTER D WITH STROKE --> - <string name="more_keys_for_d">đ</string> + <string name="morekeys_d">đ</string> <!-- U+20AB: "₫" DONG SIGN --> - <string name="keylabel_for_currency">₫</string> + <string name="keyspec_currency">₫</string> </resources> diff --git a/tools/make-keyboard-text/res/values-zu/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-zu/donottranslate-more-keys.xml index 191791530..f9150f366 100644 --- a/tools/make-keyboard-text/res/values-zu/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-zu/donottranslate-more-keys.xml @@ -27,19 +27,19 @@ U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE U+0101: "ā" LATIN SMALL LETTER A WITH MACRON --> - <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string> + <string name="morekeys_a">à,á,â,ä,æ,ã,å,ā</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS U+0113: "ē" LATIN SMALL LETTER E WITH MACRON --> - <string name="more_keys_for_e">è,é,ê,ë,ē</string> + <string name="morekeys_e">è,é,ê,ë,ē</string> <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+012B: "ī" LATIN SMALL LETTER I WITH MACRON U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE --> - <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <string name="morekeys_i">î,ï,í,ī,ì</string> <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE @@ -48,17 +48,17 @@ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE U+014D: "ō" LATIN SMALL LETTER O WITH MACRON U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE --> - <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> + <string name="morekeys_o">ô,ö,ò,ó,œ,ø,ō,õ</string> <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+016B: "ū" LATIN SMALL LETTER U WITH MACRON --> - <string name="more_keys_for_u">û,ü,ù,ú,ū</string> + <string name="morekeys_u">û,ü,ù,ú,ū</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S --> - <string name="more_keys_for_s">ß</string> + <string name="morekeys_s">ß</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> - <string name="more_keys_for_n">ñ</string> + <string name="morekeys_n">ñ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA --> - <string name="more_keys_for_c">ç</string> + <string name="morekeys_c">ç</string> </resources> diff --git a/tools/make-keyboard-text/res/values-zz/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-zz/donottranslate-more-keys.xml index eb984a469..f20c7f618 100644 --- a/tools/make-keyboard-text/res/values-zz/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-zz/donottranslate-more-keys.xml @@ -29,7 +29,7 @@ U+0103: "ă" LATIN SMALL LETTER A WITH BREVE U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK U+00AA: "ª" FEMININE ORDINAL INDICATOR --> - <string name="more_keys_for_a">à,á,â,ã,ä,å,æ,ã,å,ā,ă,ą,ª</string> + <string name="morekeys_a">à,á,â,ã,ä,å,æ,ā,ă,ą,ª</string> <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX @@ -39,7 +39,7 @@ U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK U+011B: "ě" LATIN SMALL LETTER E WITH CARON --> - <string name="more_keys_for_e">è,é,ê,ë,ē,ĕ,ė,ę,ě</string> + <string name="morekeys_e">è,é,ê,ë,ē,ĕ,ė,ę,ě</string> <!-- U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX @@ -50,7 +50,7 @@ U+012F: "į" LATIN SMALL LETTER I WITH OGONEK U+0131: "ı" LATIN SMALL LETTER DOTLESS I U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_i">ì,í,î,ï,ĩ,ī,ĭ,į,ı,ij</string> + <string name="morekeys_i">ì,í,î,ï,ĩ,ī,ĭ,į,ı,ij</string> <!-- U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX @@ -62,7 +62,7 @@ U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE U+0153: "œ" LATIN SMALL LIGATURE OE U+00BA: "º" MASCULINE ORDINAL INDICATOR --> - <string name="more_keys_for_o">ò,ó,ô,õ,ö,ø,ō,ŏ,ő,œ,º</string> + <string name="morekeys_o">ò,ó,ô,õ,ö,ø,ō,ŏ,ő,œ,º</string> <!-- U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX @@ -73,67 +73,67 @@ U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK --> - <string name="more_keys_for_u">ù,ú,û,ü,ũ,ū,ŭ,ů,ű,ų</string> + <string name="morekeys_u">ù,ú,û,ü,ũ,ū,ŭ,ů,ű,ų</string> <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA U+0161: "š" LATIN SMALL LETTER S WITH CARON U+017F: "ſ" LATIN SMALL LETTER LONG S --> - <string name="more_keys_for_s">ß,ś,ŝ,ş,š,ſ</string> + <string name="morekeys_s">ß,ś,ŝ,ş,š,ſ</string> <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA U+0148: "ň" LATIN SMALL LETTER N WITH CARON U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE U+014B: "ŋ" LATIN SMALL LETTER ENG --> - <string name="more_keys_for_n">ñ,ń,ņ,ň,ʼn,ŋ</string> + <string name="morekeys_n">ñ,ń,ņ,ň,ʼn,ŋ</string> <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE U+010D: "č" LATIN SMALL LETTER C WITH CARON --> - <string name="more_keys_for_c">ç,ć,ĉ,ċ,č</string> + <string name="morekeys_c">ç,ć,ĉ,ċ,č</string> <!-- U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS U+0133: "ij" LATIN SMALL LIGATURE IJ --> - <string name="more_keys_for_y">ý,ŷ,ÿ,ij</string> + <string name="morekeys_y">ý,ŷ,ÿ,ij</string> <!-- U+010F: "ď" LATIN SMALL LETTER D WITH CARON U+0111: "đ" LATIN SMALL LETTER D WITH STROKE U+00F0: "ð" LATIN SMALL LETTER ETH --> - <string name="more_keys_for_d">ď,đ,ð</string> + <string name="morekeys_d">ď,đ,ð</string> <!-- U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA U+0159: "ř" LATIN SMALL LETTER R WITH CARON --> - <string name="more_keys_for_r">ŕ,ŗ,ř</string> + <string name="morekeys_r">ŕ,ŗ,ř</string> <!-- U+00FE: "þ" LATIN SMALL LETTER THORN U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA U+0165: "ť" LATIN SMALL LETTER T WITH CARON U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE --> - <string name="more_keys_for_t">þ,ţ,ť,ŧ</string> + <string name="morekeys_t">þ,ţ,ť,ŧ</string> <!-- U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE U+017E: "ž" LATIN SMALL LETTER Z WITH CARON --> - <string name="more_keys_for_z">ź,ż,ž</string> + <string name="morekeys_z">ź,ż,ž</string> <!-- U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA U+0138: "ĸ" LATIN SMALL LETTER KRA --> - <string name="more_keys_for_k">ķ,ĸ</string> + <string name="morekeys_k">ķ,ĸ</string> <!-- U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA U+013E: "ľ" LATIN SMALL LETTER L WITH CARON U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT U+0142: "ł" LATIN SMALL LETTER L WITH STROKE --> - <string name="more_keys_for_l">ĺ,ļ,ľ,ŀ,ł</string> + <string name="morekeys_l">ĺ,ļ,ľ,ŀ,ł</string> <!-- U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA --> - <string name="more_keys_for_g">ĝ,ğ,ġ,ģ</string> + <string name="morekeys_g">ĝ,ğ,ġ,ģ</string> <!-- U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX --> - <string name="more_keys_for_h">ĥ</string> + <string name="morekeys_h">ĥ</string> <!-- U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX --> - <string name="more_keys_for_j">ĵ</string> + <string name="morekeys_j">ĵ</string> <!-- U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX --> - <string name="more_keys_for_w">ŵ</string> + <string name="morekeys_w">ŵ</string> </resources> diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml index 3c59b4bd1..4b9ca162e 100644 --- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml @@ -18,53 +18,64 @@ */ --> <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="more_keys_for_v"></string> - <string name="more_keys_for_h"></string> - <string name="more_keys_for_j"></string> - <string name="more_keys_for_w"></string> - <string name="keylabel_for_nordic_row1_11"></string> - <string name="keylabel_for_nordic_row2_10"></string> - <string name="keylabel_for_nordic_row2_11"></string> - <string name="more_keys_for_nordic_row2_10"></string> - <string name="more_keys_for_nordic_row2_11"></string> - <string name="keylabel_for_east_slavic_row1_9"></string> - <string name="keylabel_for_east_slavic_row1_12"></string> - <string name="keylabel_for_east_slavic_row2_1"></string> - <string name="keylabel_for_east_slavic_row2_11"></string> - <string name="keylabel_for_east_slavic_row3_5"></string> - <string name="more_keys_for_cyrillic_u"></string> - <string name="more_keys_for_cyrillic_ka"></string> - <string name="more_keys_for_cyrillic_en"></string> - <string name="more_keys_for_cyrillic_ghe"></string> - <string name="more_keys_for_east_slavic_row2_1"></string> - <string name="more_keys_for_cyrillic_a"></string> - <string name="more_keys_for_cyrillic_o"></string> - <string name="more_keys_for_cyrillic_soft_sign"></string> - <string name="more_keys_for_east_slavic_row2_11"></string> - <string name="keylabel_for_south_slavic_row1_6"></string> - <string name="keylabel_for_south_slavic_row2_11"></string> - <string name="keylabel_for_south_slavic_row3_1"></string> - <string name="keylabel_for_south_slavic_row3_8"></string> - <string name="more_keys_for_cyrillic_ie"></string> - <string name="more_keys_for_cyrillic_i"></string> + <string name="morekeys_a"></string> + <string name="morekeys_e"></string> + <string name="morekeys_i"></string> + <string name="morekeys_o"></string> + <string name="morekeys_u"></string> + <string name="morekeys_s"></string> + <string name="morekeys_n"></string> + <string name="morekeys_c"></string> + <string name="morekeys_y"></string> + <string name="morekeys_d"></string> + <string name="morekeys_r"></string> + <string name="morekeys_t"></string> + <string name="morekeys_z"></string> + <string name="morekeys_k"></string> + <string name="morekeys_l"></string> + <string name="morekeys_g"></string> + <string name="morekeys_v"></string> + <string name="morekeys_h"></string> + <string name="morekeys_j"></string> + <string name="morekeys_w"></string> + <string name="morekeys_q"></string> + <string name="morekeys_x"></string> + <string name="keyspec_q">q</string> + <string name="keyspec_w">w</string> + <string name="keyspec_y">y</string> + <string name="keyspec_x">x</string> + <string name="keyspec_nordic_row1_11"></string> + <string name="keyspec_nordic_row2_10"></string> + <string name="keyspec_nordic_row2_11"></string> + <string name="morekeys_nordic_row2_10"></string> + <string name="morekeys_nordic_row2_11"></string> + <string name="keyspec_east_slavic_row1_9"></string> + <string name="keyspec_east_slavic_row2_2"></string> + <string name="keyspec_east_slavic_row2_11"></string> + <string name="keyspec_east_slavic_row3_5"></string> + <string name="morekeys_east_slavic_row2_2"></string> + <string name="morekeys_east_slavic_row2_11"></string> + <string name="morekeys_cyrillic_u"></string> + <string name="morekeys_cyrillic_ka"></string> + <string name="morekeys_cyrillic_en"></string> + <string name="morekeys_cyrillic_ghe"></string> + <string name="morekeys_cyrillic_a"></string> + <string name="morekeys_cyrillic_o"></string> + <string name="morekeys_cyrillic_i"></string> + <string name="morekeys_cyrillic_ie"></string> + <string name="morekeys_cyrillic_soft_sign"></string> + <string name="keyspec_south_slavic_row1_6"></string> + <string name="keyspec_south_slavic_row2_11"></string> + <string name="keyspec_south_slavic_row3_1"></string> + <string name="keyspec_south_slavic_row3_8"></string> + <string name="keyspec_swiss_row1_11"></string> + <string name="keyspec_swiss_row2_10"></string> + <string name="keyspec_swiss_row2_11"></string> + <string name="morekeys_swiss_row1_11"></string> + <string name="morekeys_swiss_row2_10"></string> + <string name="morekeys_swiss_row2_11"></string> <!-- Label for "switch to alphabetic" key. --> - <string name="label_to_alpha_key">ABC</string> + <string name="keylabel_to_alpha">ABC</string> <string name="single_quotes">!text/single_lqm_rqm</string> <string name="double_quotes">!text/double_lqm_rqm</string> <string name="single_angle_quotes">!text/single_laqm_raqm</string> @@ -74,144 +85,146 @@ U+20AC: "€" EURO SIGN U+00A5: "¥" YEN SIGN U+20B1: "₱" PESO SIGN --> - <string name="more_keys_for_currency_dollar">¢,£,€,¥,₱</string> - <string name="keylabel_for_currency">$</string> - <string name="more_keys_for_currency">$,¢,€,£,¥,₱</string> - <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,;,/,(,),#,!,\\,,\?,&,\\%,+,\",-,:,',\@"</string> + <string name="morekeys_currency_dollar">¢,£,€,¥,₱</string> + <string name="keyspec_currency">$</string> + <string name="morekeys_currency">$,¢,€,£,¥,₱</string> + <string name="morekeys_punctuation">"!autoColumnOrder!8,\\,,?,!,#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,',@,:,-,\",+,\\%,&"</string> + <string name="morekeys_tablet_punctuation">"!autoColumnOrder!7,\\,,',#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,@,:,-,\",+,\\%,&"</string> + <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE --> + <string name="keyspec_spanish_row2_10">ñ</string> <!-- U+2020: "†" DAGGER U+2021: "‡" DOUBLE DAGGER U+2605: "★" BLACK STAR --> - <string name="more_keys_for_star">†,‡,★</string> + <string name="morekeys_star">†,‡,★</string> <!-- U+266A: "♪" EIGHTH NOTE U+2665: "♥" BLACK HEART SUIT U+2660: "♠" BLACK SPADE SUIT U+2666: "♦" BLACK DIAMOND SUIT U+2663: "♣" BLACK CLUB SUIT --> - <string name="more_keys_for_bullet">♪,♥,♠,♦,♣</string> + <string name="morekeys_bullet">♪,♥,♠,♦,♣</string> <!-- U+00B1: "±" PLUS-MINUS SIGN --> - <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 --> - <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!3,<,{,[</string> - <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!3,>,},]</string> - <!-- U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - U+2264: "≤" LESS-THAN OR EQUAL TO - U+2265: "≥" GREATER-THAN EQUAL TO - U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> - <string name="more_keys_for_less_than">!fixedColumnOrder!3,‹,≤,«</string> - <string name="more_keys_for_greater_than">!fixedColumnOrder!3,›,≥,»</string> - <string name="more_keys_for_arabic_diacritics"></string> - <string name="keyhintlabel_for_arabic_diacritics"></string> - <string name="keylabel_for_symbols_1">1</string> - <string name="keylabel_for_symbols_2">2</string> - <string name="keylabel_for_symbols_3">3</string> - <string name="keylabel_for_symbols_4">4</string> - <string name="keylabel_for_symbols_5">5</string> - <string name="keylabel_for_symbols_6">6</string> - <string name="keylabel_for_symbols_7">7</string> - <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="morekeys_plus">±</string> + <string name="morekeys_left_parenthesis">!fixedColumnOrder!3,!text/keyspecs_left_parenthesis_more_keys</string> + <string name="morekeys_right_parenthesis">!fixedColumnOrder!3,!text/keyspecs_right_parenthesis_more_keys</string> + <string name="morekeys_less_than">!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote,!text/keyspec_less_than_equal,!text/keyspec_left_double_angle_quote</string> + <string name="morekeys_greater_than">!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_right_double_angle_quote</string> + <string name="morekeys_arabic_diacritics"></string> + <string name="keyspec_symbols_1">1</string> + <string name="keyspec_symbols_2">2</string> + <string name="keyspec_symbols_3">3</string> + <string name="keyspec_symbols_4">4</string> + <string name="keyspec_symbols_5">5</string> + <string name="keyspec_symbols_6">6</string> + <string name="keyspec_symbols_7">7</string> + <string name="keyspec_symbols_8">8</string> + <string name="keyspec_symbols_9">9</string> + <string name="keyspec_symbols_0">0</string> <!-- Label for "switch to symbols" key. --> - <string name="label_to_symbol_key">\?123</string> - <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic" - part because it'll be appended by the code. --> - <string name="label_to_symbol_with_microphone_key">123</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="keylabel_to_symbol">?123</string> + <string name="additional_morekeys_symbols_1"></string> + <string name="additional_morekeys_symbols_2"></string> + <string name="additional_morekeys_symbols_3"></string> + <string name="additional_morekeys_symbols_4"></string> + <string name="additional_morekeys_symbols_5"></string> + <string name="additional_morekeys_symbols_6"></string> + <string name="additional_morekeys_symbols_7"></string> + <string name="additional_morekeys_symbols_8"></string> + <string name="additional_morekeys_symbols_9"></string> + <string name="additional_morekeys_symbols_0"></string> <!-- U+00B9: "¹" SUPERSCRIPT ONE U+00BD: "½" VULGAR FRACTION ONE HALF U+2153: "⅓" VULGAR FRACTION ONE THIRD U+00BC: "¼" VULGAR FRACTION ONE QUARTER U+215B: "⅛" VULGAR FRACTION ONE EIGHTH --> - <string name="more_keys_for_symbols_1">¹,½,⅓,¼,⅛</string> + <string name="morekeys_symbols_1">¹,½,⅓,¼,⅛</string> <!-- U+00B2: "²" SUPERSCRIPT TWO U+2154: "⅔" VULGAR FRACTION TWO THIRDS --> - <string name="more_keys_for_symbols_2">²,⅔</string> + <string name="morekeys_symbols_2">²,⅔</string> <!-- U+00B3: "³" SUPERSCRIPT THREE U+00BE: "¾" VULGAR FRACTION THREE QUARTERS U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS --> - <string name="more_keys_for_symbols_3">³,¾,⅜</string> + <string name="morekeys_symbols_3">³,¾,⅜</string> <!-- U+2074: "⁴" SUPERSCRIPT FOUR --> - <string name="more_keys_for_symbols_4">⁴</string> + <string name="morekeys_symbols_4">⁴</string> <!-- U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS --> - <string name="more_keys_for_symbols_5">⅝</string> - <string name="more_keys_for_symbols_6"></string> + <string name="morekeys_symbols_5">⅝</string> + <string name="morekeys_symbols_6"></string> <!-- U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS --> - <string name="more_keys_for_symbols_7">⅞</string> - <string name="more_keys_for_symbols_8"></string> - <string name="more_keys_for_symbols_9"></string> + <string name="morekeys_symbols_7">⅞</string> + <string name="morekeys_symbols_8"></string> + <string name="morekeys_symbols_9"></string> <!-- U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N U+2205: "∅" EMPTY SET --> - <string name="more_keys_for_symbols_0">ⁿ,∅</string> - <string name="keylabel_for_comma">,</string> - <string name="more_keys_for_comma"></string> - <string name="keylabel_for_symbols_question">\?</string> - <string name="keylabel_for_symbols_semicolon">;</string> - <string name="keylabel_for_symbols_percent">%</string> + <string name="morekeys_symbols_0">ⁿ,∅</string> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt + U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK + U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + U+2264: "≤" LESS-THAN OR EQUAL TO + U+2265: "≥" GREATER-THAN EQUAL TO + U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK --> + <string name="keyspec_left_parenthesis">(</string> + <string name="keyspec_right_parenthesis">)</string> + <string name="keyspec_left_square_bracket">[</string> + <string name="keyspec_right_square_bracket">]</string> + <string name="keyspec_left_curly_bracket">{</string> + <string name="keyspec_right_curly_bracket">}</string> + <string name="keyspec_less_than"><</string> + <string name="keyspec_greater_than">></string> + <string name="keyspec_less_than_equal">≤</string> + <string name="keyspec_greater_than_equal">≥</string> + <string name="keyspec_left_double_angle_quote">«</string> + <string name="keyspec_right_double_angle_quote">»</string> + <string name="keyspec_left_single_angle_quote">‹</string> + <string name="keyspec_right_single_angle_quote">›</string> + <!-- Comma key --> + <string name="keyspec_comma">,</string> + <string name="keyspec_tablet_comma">,</string> + <string name="keyhintlabel_tablet_comma"></string> + <string name="morekeys_tablet_comma"></string> + <!-- Period key --> + <string name="keyspec_period">.</string> + <string name="keyhintlabel_period"></string> + <string name="morekeys_period">!text/morekeys_punctuation</string> + <string name="keyspec_tablet_period">.</string> + <string name="keyhintlabel_tablet_period"></string> + <string name="morekeys_tablet_period">!text/morekeys_tablet_punctuation</string> + <string name="keyspec_symbols_question">?</string> + <string name="keyspec_symbols_semicolon">;</string> + <string name="keyspec_symbols_percent">%</string> <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK --> - <string name="more_keys_for_symbols_exclamation">¡</string> + <string name="morekeys_exclamation">¡</string> <!-- U+00BF: "¿" INVERTED QUESTION MARK --> - <string name="more_keys_for_symbols_question">¿</string> - <string name="more_keys_for_symbols_semicolon"></string> + <string name="morekeys_question">¿</string> + <string name="morekeys_symbols_semicolon"></string> <!-- U+2030: "‰" PER MILLE SIGN --> - <string name="more_keys_for_symbols_percent">‰</string> - <string name="keylabel_for_tablet_comma">,</string> - <string name="keyhintlabel_for_tablet_comma"></string> - <string name="more_keys_for_tablet_comma"></string> - <string name="keyhintlabel_for_period"></string> - <!-- U+2026: "…" HORIZONTAL ELLIPSIS --> - <string name="more_keys_for_period">…</string> - <string name="keylabel_for_apostrophe">\'</string> - <string name="keyhintlabel_for_apostrophe">\"</string> - <string name="more_keys_for_apostrophe">\"</string> - <string name="more_keys_for_q"></string> - <string name="more_keys_for_x"></string> - <string name="keylabel_for_q">q</string> - <string name="keylabel_for_w">w</string> - <string name="keylabel_for_y">y</string> - <string name="keylabel_for_x">x</string> - <string name="keylabel_for_spanish_row2_10"></string> - <string name="more_keys_for_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string> - <string name="settings_as_more_key">!icon/settings_key|!code/key_settings</string> - <string name="shortcut_as_more_key">!icon/shortcut_key|!code/key_shortcut</string> - <string name="action_next_as_more_key">!hasLabels!,\@string/label_next_key|!code/key_action_next</string> - <string name="action_previous_as_more_key">!hasLabels!,\@string/label_previous_key|!code/key_action_previous</string> - <!-- Label for "switch to more symbol" modifier key. Must be short to fit on key! --> - <string name="label_to_more_symbol_key">= \\ <</string> + <string name="morekeys_symbols_percent">‰</string> + <string name="morekeys_am_pm">!fixedColumnOrder!2,!hasLabels!,!text/keylabel_time_am,!text/keylabel_time_pm</string> + <string name="keyspec_settings">!icon/settings_key|!code/key_settings</string> + <string name="keyspec_shortcut">!icon/shortcut_key|!code/key_shortcut</string> + <string name="keyspec_action_next">!hasLabels!,!text/label_next_key|!code/key_action_next</string> + <string name="keyspec_action_previous">!hasLabels!,!text/label_previous_key|!code/key_action_previous</string> + <!-- Label for "switch to more symbol" modifier key ("= \ <"). Must be short to fit on key! --> + <string name="keylabel_to_more_symbol">= \\\\ <</string> <!-- Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! --> - <string name="label_to_more_symbol_for_tablet_key">~ [ <</string> - <!-- Label for "Tab" key. Must be short to fit on key! --> - <string name="label_tab_key">Tab</string> + <string name="keylabel_tablet_to_more_symbol">~ [ <</string> <!-- Label for "switch to phone numeric" key. Must be short to fit on key! --> - <string name="label_to_phone_numeric_key">123</string> + <string name="keylabel_to_phone_numeric">123</string> <!-- Label for "switch to phone symbols" key. Must be short to fit on key! --> <!-- U+FF0A: "*" FULLWIDTH ASTERISK U+FF03: "#" FULLWIDTH NUMBER SIGN --> - <string name="label_to_phone_symbols_key">*#</string> + <string name="keylabel_to_phone_symbols">*#</string> <!-- Key label for "ante meridiem" --> - <string name="label_time_am">"AM"</string> + <string name="keylabel_time_am">"AM"</string> <!-- Key label for "post meridiem" --> - <string name="label_time_pm">"PM"</string> - <string name="keylabel_for_popular_domain">".com"</string> + <string name="keylabel_time_pm">"PM"</string> + <string name="keyspec_popular_domain">".com"</string> <!-- popular web domains for the locale - most popular, displayed on the keyboard --> - <string name="more_keys_for_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string> - <string name="more_keys_for_smiley">"!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ "</string> - <!-- U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK - U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - The following characters don't need BIDI mirroring. + <string name="morekeys_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string> + <string name="keyspecs_left_parenthesis_more_keys">!text/keyspec_less_than,!text/keyspec_left_curly_bracket,!text/keyspec_left_square_bracket</string> + <string name="keyspecs_right_parenthesis_more_keys">!text/keyspec_greater_than,!text/keyspec_right_curly_bracket,!text/keyspec_right_square_bracket</string> + <!-- The following characters don't need BIDI mirroring. U+2018: "‘" LEFT SINGLE QUOTATION MARK U+2019: "’" RIGHT SINGLE QUOTATION MARK U+201A: "‚" SINGLE LOW-9 QUOTATION MARK @@ -221,30 +234,29 @@ <!-- Abbreviations are: laqm: LEFT-POINTING ANGLE QUOTATION MARK raqm: RIGHT-POINTING ANGLE QUOTATION MARK - rtl: Right-To-Left script order lqm: LEFT QUOTATION MARK rqm: RIGHT QUOTATION MARK 9qm: LOW-9 QUOTATION MARK --> <!-- The following each quotation mark pair consist of <opening quotation mark>, <closing quotation mark> and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. --> - <string name="single_laqm_raqm">‹,›</string> - <string name="single_laqm_raqm_rtl">‹|›,›|‹</string> - <string name="single_raqm_laqm">›,‹</string> - <string name="double_laqm_raqm">«,»</string> - <string name="double_laqm_raqm_rtl">«|»,»|«</string> - <string name="double_raqm_laqm">»,«</string> + <string name="single_laqm_raqm">!text/keyspec_left_single_angle_quote,!text/keyspec_right_single_angle_quote</string> + <string name="single_raqm_laqm">!text/keyspec_right_single_angle_quote,!text/keyspec_left_single_angle_quote</string> + <string name="double_laqm_raqm">!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote</string> + <string name="double_raqm_laqm">!text/keyspec_right_double_angle_quote,!text/keyspec_left_double_angle_quote</string> <!-- The following each quotation mark triplet consists of <another quotation mark>, <opening quotation mark>, <closing quotation mark> and is named after (single|double)_<opening quotation mark>_<closing quotation mark>. --> <string name="single_lqm_rqm">‚,‘,’</string> <string name="single_9qm_lqm">’,‚,‘</string> <string name="single_9qm_rqm">‘,‚,’</string> + <string name="single_rqm_9qm">‘,’,‚</string> <string name="double_lqm_rqm">„,“,”</string> <string name="double_9qm_lqm">”,„,“</string> <string name="double_9qm_rqm">“,„,”</string> - <string name="more_keys_for_single_quote">!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes</string> - <string name="more_keys_for_double_quote">!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes</string> - <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes</string> - <string name="emoji_key_as_more_key">!icon/emoji_key|!code/key_emoji</string> + <string name="double_rqm_9qm">“,”,„</string> + <string name="morekeys_single_quote">!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes</string> + <string name="morekeys_double_quote">!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes</string> + <string name="morekeys_tablet_double_quote">!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes</string> + <string name="keyspec_emoji_key">!icon/emoji_key|!code/key_emoji</string> </resources> diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java index 331003e67..48bf8010a 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java @@ -22,17 +22,26 @@ public class ArrayInitializerFormatter { private final PrintStream mOut; private final int mMaxWidth; private final String mIndent; + // String resource names array; indexed by {@link #CurrentIndex} and + // {@link #mStartIndexOfBuffer}. + private final String[] mResourceNames; private int mCurrentIndex = 0; - private String mFixedElement; + private String mLastElement; private final StringBuilder mBuffer = new StringBuilder(); private int mBufferedLen; - private int mBufferedIndex = Integer.MIN_VALUE; + private int mStartIndexOfBuffer = Integer.MIN_VALUE; - public ArrayInitializerFormatter(PrintStream out, int width, String indent) { + public ArrayInitializerFormatter(final PrintStream out, final int width, final String indent, + final String[] resourceNames) { mOut = out; mMaxWidth = width - indent.length(); mIndent = indent; + mResourceNames = resourceNames; + } + + public int getCurrentIndex() { + return mCurrentIndex; } public void flush() { @@ -40,42 +49,48 @@ public class ArrayInitializerFormatter { return; } final int lastIndex = mCurrentIndex - 1; - if (mBufferedIndex == lastIndex) { - mOut.format("%s/* %d */ %s\n", mIndent, mBufferedIndex, mBuffer); - } else if (mBufferedIndex == lastIndex - 1) { - final String[] elements = mBuffer.toString().split(" "); - mOut.format("%s/* %d */ %s\n" - + "%s/* %d */ %s\n", - mIndent, mBufferedIndex, elements[0], - mIndent, lastIndex, elements[1]); + if (mStartIndexOfBuffer == lastIndex) { + mOut.format("%s/* %s */ %s\n", + mIndent, mResourceNames[mStartIndexOfBuffer], mBuffer); + } else if (mStartIndexOfBuffer == lastIndex - 1) { + final String startElement = mBuffer.toString() + .substring(0, mBuffer.length() - mLastElement.length()) + .trim(); + mOut.format("%s/* %s */ %s\n" + + "%s/* %s */ %s\n", + mIndent, mResourceNames[mStartIndexOfBuffer], startElement, + mIndent, mResourceNames[lastIndex], mLastElement); } else { - mOut.format("%s/* %d~ */\n" + mOut.format("%s/* %s ~ */\n" + "%s%s\n" - + "%s/* ~%d */\n", mIndent, mBufferedIndex, + + "%s/* ~ %s */\n", + mIndent, mResourceNames[mStartIndexOfBuffer], mIndent, mBuffer, - mIndent, lastIndex); + mIndent, mResourceNames[lastIndex]); } mBuffer.setLength(0); mBufferedLen = 0; } - public void outCommentLines(String lines) { + public void outCommentLines(final String lines) { flush(); mOut.print(lines); - mFixedElement = null; + mLastElement = null; } - public void outElement(String element) { - if (!element.equals(mFixedElement)) { + public void outElement(final String element) { + if (!element.equals(mLastElement)) { flush(); - mBufferedIndex = mCurrentIndex; + mStartIndexOfBuffer = mCurrentIndex; } final int nextLen = mBufferedLen + " ".length() + element.length(); if (mBufferedLen != 0 && nextLen < mMaxWidth) { + // Element can fit in the current line. mBuffer.append(' '); mBuffer.append(element); mBufferedLen = nextLen; } else { + // Element should be on the next line. if (mBufferedLen != 0) { mBuffer.append('\n'); mBuffer.append(mIndent); @@ -84,6 +99,6 @@ public class ArrayInitializerFormatter { mBufferedLen = element.length(); } mCurrentIndex++; - mFixedElement = element; + mLastElement = element; } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java index a74096e79..c947a63bf 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java @@ -16,6 +16,7 @@ package com.android.inputmethod.keyboard.tools; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -23,6 +24,7 @@ import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; +import java.util.Locale; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -58,7 +60,7 @@ public final class JarUtils { public boolean accept(String dirName, String name); } - public static ArrayList<String> getNameListing(final JarFile jar, final JarFilter filter) { + public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) { final ArrayList<String> result = new ArrayList<String>(); final Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { @@ -74,12 +76,42 @@ public final class JarUtils { return result; } - public static ArrayList<String> getNameListing(final JarFile jar, final String filterName) { - return getNameListing(jar, new JarFilter() { + public static ArrayList<String> getEntryNameListing(final JarFile jar, + final String filterName) { + return getEntryNameListing(jar, new JarFilter() { @Override public boolean accept(final String dirName, final String name) { return name.equals(filterName); } }); } + + // The locale is taken from string resource jar entry name (values-<locale>/) + // or {@link LocaleUtils#DEFAULT_LOCALE} for the default string resource + // directory (values/). + public static Locale getLocaleFromEntryName(final String jarEntryName) { + final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/')); + final int pos = dirName.lastIndexOf('/'); + final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName; + final int localePos = parentName.indexOf('-'); + if (localePos < 0) { + // Default resource name. + return LocaleUtils.DEFAULT_LOCALE; + } + final String localeStr = parentName.substring(localePos + 1); + final int regionPos = localeStr.indexOf("-r"); + if (regionPos < 0) { + return LocaleUtils.constructLocaleFromString(localeStr); + } + return LocaleUtils.constructLocaleFromString(localeStr.replace("-r", "_")); + } + + public static void close(final Closeable stream) { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java new file mode 100644 index 000000000..0dfa37667 --- /dev/null +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2013 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.tools; + +import java.util.HashMap; +import java.util.Locale; + +/** + * A class to help with handling Locales in string form. + * + * This is a subset of com/android/inputmethod/latin/utils/LocaleUtils.java in order to use + * for the make-keyboard-text tool. + */ +public final class LocaleUtils { + public static final Locale DEFAULT_LOCALE = Locale.ROOT; + private static final String DEFAULT_LOCALE_CODE = "DEFAULT"; + public static final String NO_LANGUAGE_LOCALE_CODE = "zz"; + public static final String NO_LANGUAGE_LOCALE_DISPLAY_NAME = "Alphabet"; + + private LocaleUtils() { + // Intentional empty constructor for utility class. + } + + private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>(); + + private static final int INDEX_LANGUAGE = 0; + private static final int INDEX_SCRIPT = 1; + private static final int INDEX_REGION = 2; + private static final int ELEMENT_LIMIT = INDEX_REGION + 1; + + /** + * Creates a locale from a string specification. + * + * Locale string is: language(_script)?(_region)? + * where: language := [a-zA-Z]{2,3} + * script := [a-zA-Z]{4} + * region := [a-zA-Z]{2,3}|[0-9]{3} + */ + public static Locale constructLocaleFromString(final String localeStr) { + if (localeStr == null) { + return null; + } + synchronized (sLocaleCache) { + if (sLocaleCache.containsKey(localeStr)) { + return sLocaleCache.get(localeStr); + } + boolean hasRegion = false; + final Locale.Builder builder = new Locale.Builder(); + final String[] localeElements = localeStr.split("_", ELEMENT_LIMIT); + if (localeElements.length > INDEX_LANGUAGE) { + final String text = localeElements[INDEX_LANGUAGE]; + if (isValidLanguage(text)) { + builder.setLanguage(text); + } else { + throw new RuntimeException("Unknown locale format: " + localeStr); + } + } + if (localeElements.length > INDEX_SCRIPT) { + final String text = localeElements[INDEX_SCRIPT]; + if (isValidScript(text)) { + builder.setScript(text); + } else if (isValidRegion(text)) { + builder.setRegion(text); + hasRegion = true; + } else { + throw new RuntimeException("Unknown locale format: " + localeStr); + } + } + if (localeElements.length > INDEX_REGION) { + final String text = localeElements[INDEX_REGION]; + if (!hasRegion && isValidRegion(text)) { + builder.setRegion(text); + } else { + throw new RuntimeException("Unknown locale format: " + localeStr); + } + } + final Locale locale = builder.build(); + sLocaleCache.put(localeStr, locale); + return locale; + } + } + + private static final int MIN_LENGTH_OF_LANGUAGE = 2; + private static final int MAX_LENGTH_OF_LANGUAGE = 2; + private static final int LENGTH_OF_SCRIPT = 4; + private static final int MIN_LENGTH_OF_REGION = 2; + private static final int MAX_LENGTH_OF_REGION = 2; + private static final int LENGTH_OF_AREA_CODE = 3; + + private static boolean isValidLanguage(final String text) { + return isAlphabetSequence(text, MIN_LENGTH_OF_LANGUAGE, MAX_LENGTH_OF_LANGUAGE); + } + + private static boolean isValidScript(final String text) { + return isAlphabetSequence(text, LENGTH_OF_SCRIPT, LENGTH_OF_SCRIPT); + } + + private static boolean isValidRegion(final String text) { + return isAlphabetSequence(text, MIN_LENGTH_OF_REGION, MAX_LENGTH_OF_REGION) + || isDigitSequence(text, LENGTH_OF_AREA_CODE, LENGTH_OF_AREA_CODE); + } + + private static boolean isAlphabetSequence(final String text, final int lower, final int upper) { + final int length = text.length(); + if (length < lower || length > upper) { + return false; + } + for (int index = 0; index < length; index++) { + if (!isAsciiAlphabet(text.charAt(index))) { + return false; + } + } + return true; + } + + private static boolean isDigitSequence(final String text, final int lower, final int upper) { + final int length = text.length(); + if (length < lower || length > upper) { + return false; + } + for (int index = 0; index < length; ++index) { + if (!isAsciiDigit(text.charAt(index))) { + return false; + } + } + return true; + } + + private static boolean isAsciiAlphabet(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + private static boolean isAsciiDigit(char c) { + return c >= '0' && c <= '9'; + } + + public static String getLocaleCode(final Locale locale) { + if (locale == DEFAULT_LOCALE) { + return DEFAULT_LOCALE_CODE; + } + return locale.toString(); + } + + public static String getLocaleDisplayName(final Locale locale) { + if (locale == DEFAULT_LOCALE) { + return DEFAULT_LOCALE_CODE; + } + if (locale.getLanguage().equals(NO_LANGUAGE_LOCALE_CODE)) { + return NO_LANGUAGE_LOCALE_DISPLAY_NAME; + } + return locale.getDisplayName(Locale.ENGLISH); + } +} diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java index 2643e01ec..c8cb4acec 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java @@ -16,78 +16,101 @@ package com.android.inputmethod.keyboard.tools; -import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Locale; +import java.util.TreeMap; import java.util.jar.JarFile; public class MoreKeysResources { private static final String TEXT_RESOURCE_NAME = "donottranslate-more-keys.xml"; - private static final String JAVA_TEMPLATE = "KeyboardTextsSet.tmpl"; + private static final String JAVA_TEMPLATE = "KeyboardTextsTable.tmpl"; private static final String MARK_NAMES = "@NAMES@"; private static final String MARK_DEFAULT_TEXTS = "@DEFAULT_TEXTS@"; private static final String MARK_TEXTS = "@TEXTS@"; - private static final String MARK_LANGUAGES_AND_TEXTS = "@LANGUAGES_AND_TEXTS@"; - private static final String DEFAUT_LANGUAGE_NAME = "DEFAULT"; - private static final String ARRAY_NAME_FOR_LANGUAGE = "LANGUAGE_%s"; + private static final String TEXTS_ARRAY_NAME_PREFIX = "TEXTS_"; + private static final String MARK_LOCALES_AND_TEXTS = "@LOCALES_AND_TEXTS@"; private static final String EMPTY_STRING_VAR = "EMPTY"; - private static final String NO_LANGUAGE_CODE = "zz"; - private static final String NO_LANGUAGE_DISPLAY_NAME = "Alphabet"; - private final JarFile mJar; - // Language to string resources map. - private final HashMap<String, StringResourceMap> mResourcesMap = - new HashMap<String, StringResourceMap>(); - // Name to id map. - private final HashMap<String, Integer> mNameToIdMap = new HashMap<String,Integer>(); + // String resources maps sorted by its language. The language is determined from the jar entry + // name by calling {@link JarUtils#getLocaleFromEntryName(String)}. + private final TreeMap<String, StringResourceMap> mResourcesMap = + new TreeMap<String, StringResourceMap>(); + // Default string resources map. + private final StringResourceMap mDefaultResourceMap; + // Histogram of string resource names. This is used to sort {@link #mSortedResourceNames}. + private final HashMap<String, Integer> mNameHistogram = new HashMap<String, Integer>(); + // Sorted string resource names array; Descending order of histogram count. + // The string resource name is specified as an attribute "name" in string resource files. + // The string resource can be accessed by specifying name "!text/<name>" + // via {@link KeyboardTextsSet#getText(String)}. + private final String[] mSortedResourceNames; public MoreKeysResources(final JarFile jar) { mJar = jar; - final ArrayList<String> resources = JarUtils.getNameListing(jar, TEXT_RESOURCE_NAME); - for (final String name : resources) { - final String dirName = name.substring(0, name.lastIndexOf('/')); - final int pos = dirName.lastIndexOf('/'); - final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName; - final String language = getLanguageFromResDir(parentName); - final InputStream stream = JarUtils.openResource(name); - try { - mResourcesMap.put(language, new StringResourceMap(stream)); - } finally { - close(stream); - } + final ArrayList<String> resourceEntryNames = JarUtils.getEntryNameListing( + jar, TEXT_RESOURCE_NAME); + for (final String entryName : resourceEntryNames) { + final StringResourceMap resMap = new StringResourceMap(entryName); + mResourcesMap.put(LocaleUtils.getLocaleCode(resMap.mLocale), resMap); } - } + mDefaultResourceMap = mResourcesMap.get( + LocaleUtils.getLocaleCode(LocaleUtils.DEFAULT_LOCALE)); - private static String getLanguageFromResDir(final String dirName) { - final int languagePos = dirName.indexOf('-'); - if (languagePos < 0) { - // Default resource. - return DEFAUT_LANGUAGE_NAME; + // Initialize name histogram and names list. + final HashMap<String, Integer> nameHistogram = mNameHistogram; + final ArrayList<String> resourceNamesList = new ArrayList<String>(); + for (final StringResource res : mDefaultResourceMap.getResources()) { + nameHistogram.put(res.mName, 0); // Initialize histogram value. + resourceNamesList.add(res.mName); } - final String language = dirName.substring(languagePos + 1); - final int countryPos = language.indexOf("-r"); - if (countryPos < 0) { - return language; + // Make name histogram. + for (final String locale : mResourcesMap.keySet()) { + final StringResourceMap resMap = mResourcesMap.get(locale); + if (resMap == mDefaultResourceMap) continue; + for (final StringResource res : resMap.getResources()) { + if (!mDefaultResourceMap.contains(res.mName)) { + throw new RuntimeException(res.mName + " in " + locale + + " doesn't have default resource"); + } + final int histogramValue = nameHistogram.get(res.mName); + nameHistogram.put(res.mName, histogramValue + 1); + } } - return language.replace("-r", "_"); + // Sort names list. + Collections.sort(resourceNamesList, new Comparator<String>() { + @Override + public int compare(final String leftName, final String rightName) { + final int leftCount = nameHistogram.get(leftName); + final int rightCount = nameHistogram.get(rightName); + // Descending order of histogram count. + if (leftCount > rightCount) return -1; + if (leftCount < rightCount) return 1; + // TODO: Add further criteria to order the same histogram value names to be able to + // minimize footprints of string resources arrays. + return 0; + } + }); + mSortedResourceNames = resourceNamesList.toArray(new String[resourceNamesList.size()]); } public void writeToJava(final String outDir) { - final ArrayList<String> list = JarUtils.getNameListing(mJar, JAVA_TEMPLATE); - if (list.isEmpty()) + final ArrayList<String> list = JarUtils.getEntryNameListing(mJar, JAVA_TEMPLATE); + if (list.isEmpty()) { throw new RuntimeException("Can't find java template " + JAVA_TEMPLATE); - if (list.size() > 1) + } + if (list.size() > 1) { throw new RuntimeException("Found multiple java template " + JAVA_TEMPLATE); + } final String template = list.get(0); final String javaPackage = template.substring(0, template.lastIndexOf('/')); PrintStream ps = null; @@ -107,8 +130,8 @@ public class MoreKeysResources { } catch (IOException e) { throw new RuntimeException(e); } finally { - close(lnr); - close(ps); + JarUtils.close(lnr); + JarUtils.close(ps); } } @@ -122,8 +145,8 @@ public class MoreKeysResources { dumpDefaultTexts(out); } else if (line.contains(MARK_TEXTS)) { dumpTexts(out); - } else if (line.contains(MARK_LANGUAGES_AND_TEXTS)) { - dumpLanguageMap(out); + } else if (line.contains(MARK_LOCALES_AND_TEXTS)) { + dumpLocalesMap(out); } else { out.println(line); } @@ -131,70 +154,62 @@ public class MoreKeysResources { } private void dumpNames(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - int id = 0; - for (final StringResource res : defaultResMap.getResources()) { - out.format(" /* %2d */ \"%s\",\n", id, res.mName); - mNameToIdMap.put(res.mName, id); - id++; + final int namesCount = mSortedResourceNames.length; + for (int index = 0; index < namesCount; index++) { + final String name = mSortedResourceNames[index]; + final int histogramValue = mNameHistogram.get(name); + out.format(" /* %3d:%2d */ \"%s\",\n", index, histogramValue, name); } } private void dumpDefaultTexts(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - dumpTextsInternal(out, defaultResMap, defaultResMap); + final int outputArraySize = dumpTextsInternal(out, mDefaultResourceMap); + mDefaultResourceMap.setOutputArraySize(outputArraySize); } - private void dumpTexts(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - final ArrayList<String> allLanguages = new ArrayList<String>(); - allLanguages.addAll(mResourcesMap.keySet()); - Collections.sort(allLanguages); - for (final String language : allLanguages) { - if (language.equals(DEFAUT_LANGUAGE_NAME)) { - continue; - } - out.format(" /* Language %s: %s */\n", language, getLanguageDisplayName(language)); - out.format(" private static final String[] " + ARRAY_NAME_FOR_LANGUAGE + " = {\n", - language); - final StringResourceMap resMap = mResourcesMap.get(language); - for (final StringResource res : resMap.getResources()) { - if (!defaultResMap.contains(res.mName)) { - throw new RuntimeException(res.mName + " in " + language - + " doesn't have default resource"); - } - } - dumpTextsInternal(out, resMap, defaultResMap); - out.format(" };\n\n"); - } + private static String getArrayNameForLocale(final Locale locale) { + return TEXTS_ARRAY_NAME_PREFIX + LocaleUtils.getLocaleCode(locale); } - private void dumpLanguageMap(final PrintStream out) { - final ArrayList<String> allLanguages = new ArrayList<String>(); - allLanguages.addAll(mResourcesMap.keySet()); - Collections.sort(allLanguages); - for (final String language : allLanguages) { - out.format(" \"%s\", " + ARRAY_NAME_FOR_LANGUAGE + ", /* %s */\n", - language, language, getLanguageDisplayName(language)); + private void dumpTexts(final PrintStream out) { + for (final StringResourceMap resMap : mResourcesMap.values()) { + final Locale locale = resMap.mLocale; + if (resMap == mDefaultResourceMap) continue; + out.format(" /* Locale %s: %s */\n", + locale, LocaleUtils.getLocaleDisplayName(locale)); + out.format(" private static final String[] " + getArrayNameForLocale(locale) + + " = {\n"); + final int outputArraySize = dumpTextsInternal(out, resMap); + resMap.setOutputArraySize(outputArraySize); + out.format(" };\n\n"); } } - private static String getLanguageDisplayName(final String language) { - if (language.equals(NO_LANGUAGE_CODE)) { - return NO_LANGUAGE_DISPLAY_NAME; - } else { - return new Locale(language).getDisplayLanguage(); + private void dumpLocalesMap(final PrintStream out) { + for (final StringResourceMap resMap : mResourcesMap.values()) { + final Locale locale = resMap.mLocale; + final String localeStr = LocaleUtils.getLocaleCode(locale); + final String localeToDump = (locale == LocaleUtils.DEFAULT_LOCALE) + ? String.format("\"%s\"", localeStr) + : String.format("\"%s\"%s", localeStr, " ".substring(localeStr.length())); + out.format(" %s, %-12s /* %3d/%3d %s */\n", + localeToDump, getArrayNameForLocale(locale) + ",", + resMap.getResources().size(), resMap.getOutputArraySize(), + LocaleUtils.getLocaleDisplayName(locale)); } } - private static void dumpTextsInternal(final PrintStream out, final StringResourceMap resMap, - final StringResourceMap defaultResMap) { + private int dumpTextsInternal(final PrintStream out, final StringResourceMap resMap) { final ArrayInitializerFormatter formatter = - new ArrayInitializerFormatter(out, 100, " "); + new ArrayInitializerFormatter(out, 100, " ", mSortedResourceNames); + int outputArraySize = 0; boolean successiveNull = false; - for (final StringResource defaultRes : defaultResMap.getResources()) { - if (resMap.contains(defaultRes.mName)) { - final StringResource res = resMap.get(defaultRes.mName); + final int namesCount = mSortedResourceNames.length; + for (int index = 0; index < namesCount; index++) { + final String name = mSortedResourceNames[index]; + final StringResource res = resMap.get(name); + if (res != null) { + // TODO: Check whether the resource value is equal to the default. if (res.mComment != null) { formatter.outCommentLines(addPrefix(" // ", res. mComment)); } @@ -205,6 +220,7 @@ public class MoreKeysResources { formatter.outElement(String.format("\"%s\",", escaped)); } successiveNull = false; + outputArraySize = formatter.getCurrentIndex(); } else { formatter.outElement("null,"); successiveNull = true; @@ -213,6 +229,7 @@ public class MoreKeysResources { if (!successiveNull) { formatter.flush(); } + return outputArraySize; } private static String addPrefix(final String prefix, final String lines) { @@ -234,31 +251,6 @@ public class MoreKeysResources { sb.append(String.format("\\u%04X", (int)c)); } } - return replaceIncompatibleEscape(sb.toString()); - } - - private static String replaceIncompatibleEscape(final String text) { - String t = text; - t = replaceAll(t, "\\?", "?"); - t = replaceAll(t, "\\@", "@"); - t = replaceAll(t, "@string/", "!text/"); - return t; - } - - private static String replaceAll(final String text, final String target, final String replace) { - String t = text; - while (t.indexOf(target) >= 0) { - t = t.replace(target, replace); - } - return t; - } - - private static void close(Closeable stream) { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - } + return sb.toString(); } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java index cc7ff6a9c..6a79268e5 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; @@ -34,27 +35,41 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public class StringResourceMap { + // Locale of this string resource map. + public final Locale mLocale; // String resource list. private final List<StringResource> mResources; // Name to string resource map. private final Map<String, StringResource> mResourcesMap; - public StringResourceMap(final InputStream is) { + // The length of String[] that is created from this {@link StringResourceMap}. The length is + // calculated in {@link MoreKeysResources#dumpTexts(OutputStream)} and recorded by + // {@link #setOutputArraySize(int)}. The recorded length is used as a part of comment by + // {@link MoreKeysResources#dumpLocaleMap(OutputStream)} via {@link #getOutputArraySize()}. + private int mOutputArraySize; + + public StringResourceMap(final String jarEntryName) { + mLocale = JarUtils.getLocaleFromEntryName(jarEntryName); final StringResourceHandler handler = new StringResourceHandler(); final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); + final InputStream stream = JarUtils.openResource(jarEntryName); try { final SAXParser parser = factory.newSAXParser(); // In order to get comment tag. parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - parser.parse(is, handler); + parser.parse(stream, handler); } catch (ParserConfigurationException e) { + throw new RuntimeException(e.getMessage(), e); } catch (SAXParseException e) { throw new RuntimeException(e.getMessage() + " at line " + e.getLineNumber() - + ", column " + e.getColumnNumber()); + + ", column " + e.getColumnNumber(), e); } catch (SAXException e) { - throw new RuntimeException(e.getMessage()); + throw new RuntimeException(e.getMessage(), e); } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } finally { + JarUtils.close(stream); } mResources = Collections.unmodifiableList(handler.mResources); @@ -77,6 +92,14 @@ public class StringResourceMap { return mResourcesMap.get(name); } + public void setOutputArraySize(final int arraySize) { + mOutputArraySize = arraySize; + } + + public int getOutputArraySize() { + return mOutputArraySize; + } + static class StringResourceHandler extends DefaultHandler2 { private static final String TAG_RESOURCES = "resources"; private static final String TAG_STRING = "string"; |