aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/AndroidManifest.xml14
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal.9.pngbin1134 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.pngbin1243 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.pngbin1307 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_pressed.9.pngbin1088 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.pngbin1233 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.pngbin1271 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/ic_launcher_keyboard.pngbin0 -> 8523 bytes
-rw-r--r--java/res/drawable-hdpi/ic_subtype_mic_dark.pngbin1005 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_background_klp.9.pngbin2138 -> 2147 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.pngbin787 -> 1542 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal.9.pngbin991 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.pngbin1083 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.pngbin1151 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_pressed.9.pngbin956 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.pngbin1078 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.pngbin1119 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/ic_launcher_keyboard.pngbin0 -> 4772 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_background_klp.9.pngbin1383 -> 1353 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.pngbin498 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_mic_holo_light.pngbin525 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.pngbin585 -> 1051 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal.9.pngbin1172 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal_off.9.pngbin1278 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal_on.9.pngbin1345 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.pngbin1131 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_pressed_off.9.pngbin1273 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_pressed_on.9.pngbin1312 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_launcher_keyboard.pngbin0 -> 13098 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_subtype_mic_dark.pngbin1259 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_background_klp.9.pngbin3326 -> 3316 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.pngbin1062 -> 2136 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_launcher_keyboard.pngbin0 -> 25067 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_subtype_mic_dark.pngbin1846 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_background_klp.9.pngbin7452 -> 5251 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.pngbin1455 -> 2825 bytes
-rw-r--r--java/res/drawable/btn_keyboard_spacebar_gb.xml21
-rw-r--r--java/res/drawable/btn_keyboard_spacebar_ics.xml21
-rw-r--r--java/res/drawable/btn_keyboard_spacebar_klp.xml21
-rw-r--r--java/res/layout/emoji_keyboard_page.xml17
-rw-r--r--java/res/layout/emoji_palettes_view.xml20
-rw-r--r--java/res/layout/hint_add_to_dictionary.xml36
-rw-r--r--java/res/layout/input_view.xml6
-rw-r--r--java/res/layout/key_preview.xml (renamed from java/res/layout/key_preview_ics.xml)2
-rw-r--r--java/res/layout/more_keys_keyboard.xml4
-rw-r--r--java/res/layout/more_suggestions.xml9
-rw-r--r--java/res/layout/research_feedback_fragment_layout.xml56
-rw-r--r--java/res/layout/seek_bar_dialog.xml2
-rw-r--r--java/res/layout/setup_steps_title.xml4
-rw-r--r--java/res/layout/setup_welcome_title.xml4
-rw-r--r--java/res/layout/suggestion_word.xml39
-rw-r--r--java/res/layout/suggestions_strip.xml37
-rw-r--r--java/res/layout/user_dictionary_add_word.xml55
-rw-r--r--java/res/layout/user_dictionary_add_word_fullscreen.xml4
-rw-r--r--java/res/layout/user_dictionary_item.xml5
-rw-r--r--java/res/mipmap-hdpi/ic_launcher_keyboard.pngbin7646 -> 0 bytes
-rw-r--r--java/res/mipmap-mdpi/ic_launcher_keyboard.pngbin4349 -> 0 bytes
-rw-r--r--java/res/mipmap-xhdpi/ic_launcher_keyboard.pngbin12231 -> 0 bytes
-rw-r--r--java/res/mipmap-xxhdpi/ic_launcher_keyboard.pngbin21221 -> 0 bytes
-rw-r--r--java/res/raw/main_de.dictbin1605727 -> 1605763 bytes
-rw-r--r--java/res/raw/main_fr.dictbin1329192 -> 1329188 bytes
-rw-r--r--java/res/raw/main_it.dictbin1143338 -> 1143338 bytes
-rw-r--r--java/res/values-af/strings-config-important-notice.xml26
-rw-r--r--java/res/values-af/strings.xml40
-rw-r--r--java/res/values-am/strings-config-important-notice.xml26
-rw-r--r--java/res/values-am/strings.xml40
-rw-r--r--java/res/values-ar-sw600dp/config-spacing-and-punctuations.xml (renamed from java/res/values-iw/donottranslate.xml)6
-rw-r--r--java/res/values-ar/config-spacing-and-punctuations.xml (renamed from java/res/values-ar/donottranslate.xml)5
-rw-r--r--java/res/values-ar/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ar/strings.xml40
-rw-r--r--java/res/values-az-rAZ/strings-action-keys.xml30
-rw-r--r--java/res/values-az-rAZ/strings-appname.xml (renamed from java/res/values-be/strings-appname.xml)8
-rw-r--r--java/res/values-az-rAZ/strings-config-important-notice.xml26
-rw-r--r--java/res/values-az-rAZ/strings.xml244
-rw-r--r--java/res/values-be-rBY/bools.xml (renamed from java/res/values-be/bools.xml)0
-rw-r--r--java/res/values-be-rBY/strings-action-keys.xml (renamed from java/res/values-be/strings-action-keys.xml)0
-rw-r--r--java/res/values-be/strings.xml253
-rw-r--r--java/res/values-bg/strings-config-important-notice.xml26
-rw-r--r--java/res/values-bg/strings.xml40
-rw-r--r--java/res/values-ca/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ca/strings.xml42
-rw-r--r--java/res/values-cs/strings-config-important-notice.xml26
-rw-r--r--java/res/values-cs/strings.xml40
-rw-r--r--java/res/values-da/strings-config-important-notice.xml26
-rw-r--r--java/res/values-da/strings.xml40
-rw-r--r--java/res/values-de/strings-config-important-notice.xml26
-rw-r--r--java/res/values-de/strings.xml50
-rw-r--r--java/res/values-el/strings-config-important-notice.xml26
-rw-r--r--java/res/values-el/strings.xml40
-rw-r--r--java/res/values-en-rGB/strings-config-important-notice.xml26
-rw-r--r--java/res/values-en-rGB/strings.xml40
-rw-r--r--java/res/values-en-rIN/strings-config-important-notice.xml26
-rw-r--r--java/res/values-en-rIN/strings.xml40
-rw-r--r--java/res/values-es-rUS/strings-config-important-notice.xml26
-rw-r--r--java/res/values-es-rUS/strings.xml40
-rw-r--r--java/res/values-es/strings-config-important-notice.xml26
-rw-r--r--java/res/values-es/strings.xml40
-rw-r--r--java/res/values-et-rEE/strings-config-important-notice.xml26
-rw-r--r--java/res/values-et-rEE/strings.xml40
-rw-r--r--java/res/values-fa-sw600dp/config-spacing-and-punctuations.xml27
-rw-r--r--java/res/values-fa/config-spacing-and-punctuations.xml (renamed from java/res/values-fa/donottranslate.xml)5
-rw-r--r--java/res/values-fa/strings-config-important-notice.xml26
-rw-r--r--java/res/values-fa/strings.xml40
-rw-r--r--java/res/values-fi/strings-config-important-notice.xml26
-rw-r--r--java/res/values-fi/strings.xml40
-rw-r--r--java/res/values-fr-rCA/config-spacing-and-punctuations.xml (renamed from java/res/values-fr-rCA/donottranslate.xml)8
-rw-r--r--java/res/values-fr-rCA/strings-config-important-notice.xml26
-rw-r--r--java/res/values-fr-rCA/strings.xml40
-rw-r--r--java/res/values-fr/config-spacing-and-punctuations.xml (renamed from java/res/values-fr/donottranslate.xml)8
-rw-r--r--java/res/values-fr/strings-config-important-notice.xml26
-rw-r--r--java/res/values-fr/strings.xml40
-rw-r--r--java/res/values-h1200dp-port/setup-dimens-large-tablet-port.xml1
-rw-r--r--java/res/values-h330dp-land/setup-dimens-large-phone-land.xml1
-rw-r--r--java/res/values-h520dp-land/setup-dimens-small-tablet-land.xml1
-rw-r--r--java/res/values-h540dp-port/setup-dimens-large-phone-port.xml1
-rw-r--r--java/res/values-h720dp-land/setup-dimens-large-tablet-land.xml1
-rw-r--r--java/res/values-h800dp-port/setup-dimens-small-tablet-port.xml1
-rw-r--r--java/res/values-hi/strings-config-important-notice.xml26
-rw-r--r--java/res/values-hi/strings.xml40
-rw-r--r--java/res/values-hr/strings-config-important-notice.xml26
-rw-r--r--java/res/values-hr/strings.xml40
-rw-r--r--java/res/values-hu/strings-config-important-notice.xml26
-rw-r--r--java/res/values-hu/strings.xml40
-rw-r--r--java/res/values-hy-rAM/config-spacing-and-punctuations.xml (renamed from java/res/values-hy-rAM/donottranslate.xml)6
-rw-r--r--java/res/values-hy-rAM/strings-config-important-notice.xml26
-rw-r--r--java/res/values-hy-rAM/strings.xml40
-rw-r--r--java/res/values-in/strings-config-important-notice.xml26
-rw-r--r--java/res/values-in/strings.xml40
-rw-r--r--java/res/values-is/strings.xml12
-rw-r--r--java/res/values-it/strings-config-important-notice.xml26
-rw-r--r--java/res/values-it/strings.xml40
-rw-r--r--java/res/values-iw/strings-config-important-notice.xml26
-rw-r--r--java/res/values-iw/strings.xml40
-rw-r--r--java/res/values-ja/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ja/strings.xml40
-rw-r--r--java/res/values-ka-rGE/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ka-rGE/strings.xml40
-rw-r--r--java/res/values-kk/strings.xml8
-rw-r--r--java/res/values-km-rKH/config-spacing-and-punctuations.xml (renamed from java/res/values-km-rKH/donottranslate.xml)0
-rw-r--r--java/res/values-km-rKH/strings-config-important-notice.xml26
-rw-r--r--java/res/values-km-rKH/strings.xml40
-rw-r--r--java/res/values-ko/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ko/strings.xml40
-rw-r--r--java/res/values-ky/strings.xml12
-rw-r--r--java/res/values-land/config.xml61
-rw-r--r--java/res/values-land/dimens.xml83
-rw-r--r--java/res/values-land/keyboard-heights.xml2
-rw-r--r--java/res/values-land/setup-dimens-small-phone-land.xml1
-rw-r--r--java/res/values-lo-rLA/config-spacing-and-punctuations.xml (renamed from java/res/values-lo-rLA/donottranslate.xml)0
-rw-r--r--java/res/values-lo-rLA/strings-config-important-notice.xml26
-rw-r--r--java/res/values-lo-rLA/strings.xml40
-rw-r--r--java/res/values-lt/strings-config-important-notice.xml26
-rw-r--r--java/res/values-lt/strings.xml40
-rw-r--r--java/res/values-lv/strings-config-important-notice.xml26
-rw-r--r--java/res/values-lv/strings.xml40
-rw-r--r--java/res/values-mk/strings.xml12
-rw-r--r--java/res/values-mn-rMN/strings-config-important-notice.xml26
-rw-r--r--java/res/values-mn-rMN/strings.xml40
-rw-r--r--java/res/values-ms-rMY/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ms-rMY/strings.xml40
-rw-r--r--java/res/values-nb/strings-config-important-notice.xml26
-rw-r--r--java/res/values-nb/strings.xml40
-rw-r--r--java/res/values-ne-rNP/strings-action-keys.xml30
-rw-r--r--java/res/values-ne-rNP/strings-appname.xml27
-rw-r--r--java/res/values-ne-rNP/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ne-rNP/strings.xml244
-rw-r--r--java/res/values-nl/strings-config-important-notice.xml26
-rw-r--r--java/res/values-nl/strings.xml40
-rw-r--r--java/res/values-pl/strings-config-important-notice.xml26
-rw-r--r--java/res/values-pl/strings.xml48
-rw-r--r--java/res/values-port/setup-dimens-small-phone-port.xml1
-rw-r--r--java/res/values-pt-rPT/strings-config-important-notice.xml26
-rw-r--r--java/res/values-pt-rPT/strings.xml40
-rw-r--r--java/res/values-pt/strings-config-important-notice.xml26
-rw-r--r--java/res/values-pt/strings.xml56
-rw-r--r--java/res/values-rm/strings.xml12
-rw-r--r--java/res/values-ro/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ro/strings.xml40
-rw-r--r--java/res/values-ru/strings-config-important-notice.xml26
-rw-r--r--java/res/values-ru/strings.xml40
-rw-r--r--java/res/values-sk/strings-config-important-notice.xml26
-rw-r--r--java/res/values-sk/strings.xml48
-rw-r--r--java/res/values-sl/strings-config-important-notice.xml26
-rw-r--r--java/res/values-sl/strings.xml40
-rw-r--r--java/res/values-sr/strings-config-important-notice.xml26
-rw-r--r--java/res/values-sr/strings.xml40
-rw-r--r--java/res/values-sv/strings-config-important-notice.xml26
-rw-r--r--java/res/values-sv/strings.xml42
-rw-r--r--java/res/values-sw/strings-config-important-notice.xml26
-rw-r--r--java/res/values-sw/strings.xml40
-rw-r--r--java/res/values-sw430dp/config-per-form-factor.xml33
-rw-r--r--java/res/values-sw430dp/config-screen-metrics.xml (renamed from java/res/values-sw540dp-land/config.xml)5
-rw-r--r--java/res/values-sw540dp-land/dimens.xml72
-rw-r--r--java/res/values-sw540dp/dimens.xml98
-rw-r--r--java/res/values-sw600dp-land/config.xml71
-rw-r--r--java/res/values-sw600dp/config-per-form-factor.xml33
-rw-r--r--java/res/values-sw600dp/config-screen-metrics.xml (renamed from java/res/layout/key_preview_klp.xml)11
-rw-r--r--java/res/values-sw600dp/config-spacing-and-punctuations.xml23
-rw-r--r--java/res/values-sw600dp/config.xml76
-rw-r--r--java/res/values-sw600dp/touch-position-correction.xml (renamed from java/res/values-sw540dp/touch-position-correction.xml)0
-rw-r--r--java/res/values-sw768dp-land/config.xml50
-rw-r--r--java/res/values-sw768dp-land/dimens.xml73
-rw-r--r--java/res/values-sw768dp/config-per-form-factor.xml (renamed from java/res/values-sw540dp/config.xml)18
-rw-r--r--java/res/values-sw768dp/config-screen-metrics.xml (renamed from java/res/values-hdpi/config.xml)12
-rw-r--r--java/res/values-sw768dp/config.xml94
-rw-r--r--java/res/values-sw768dp/dimens.xml98
-rw-r--r--java/res/values-th/config-spacing-and-punctuations.xml (renamed from java/res/values-th/donottranslate.xml)0
-rw-r--r--java/res/values-th/strings-config-important-notice.xml26
-rw-r--r--java/res/values-th/strings.xml40
-rw-r--r--java/res/values-tl/strings-config-important-notice.xml26
-rw-r--r--java/res/values-tl/strings.xml44
-rw-r--r--java/res/values-tr/strings-config-important-notice.xml26
-rw-r--r--java/res/values-tr/strings.xml40
-rw-r--r--java/res/values-uk/strings-config-important-notice.xml26
-rw-r--r--java/res/values-uk/strings.xml40
-rw-r--r--java/res/values-vi/strings-config-important-notice.xml26
-rw-r--r--java/res/values-vi/strings.xml40
-rw-r--r--java/res/values-zh-rCN/strings-config-important-notice.xml26
-rw-r--r--java/res/values-zh-rCN/strings.xml40
-rw-r--r--java/res/values-zh-rHK/strings-config-important-notice.xml26
-rw-r--r--java/res/values-zh-rHK/strings.xml40
-rw-r--r--java/res/values-zh-rTW/strings-config-important-notice.xml26
-rw-r--r--java/res/values-zh-rTW/strings.xml40
-rw-r--r--java/res/values-zu/strings-config-important-notice.xml26
-rw-r--r--java/res/values-zu/strings.xml40
-rw-r--r--java/res/values/attrs.xml50
-rw-r--r--java/res/values/config-auto-correction-thresholds.xml57
-rw-r--r--java/res/values/config-common.xml149
-rw-r--r--java/res/values/config-dictionary-pack.xml30
-rw-r--r--java/res/values/config-per-form-factor.xml32
-rw-r--r--java/res/values/config-screen-metrics.xml24
-rw-r--r--java/res/values/config-spacing-and-punctuations.xml39
-rw-r--r--java/res/values/config-spellchecker-thresholds.xml25
-rw-r--r--java/res/values/config.xml179
-rw-r--r--java/res/values/dimens.xml132
-rw-r--r--java/res/values/donottranslate.xml57
-rw-r--r--java/res/values/keyboard-heights.xml2
-rw-r--r--java/res/values/keyboard-icons-holo.xml1
-rw-r--r--java/res/values/keypress-vibration-durations.xml2
-rw-r--r--java/res/values/keypress-volumes.xml2
-rw-r--r--java/res/values/phantom-sudden-move-event-device-list.xml2
-rw-r--r--java/res/values/strings-config-important-notice.xml33
-rw-r--r--java/res/values/strings.xml97
-rw-r--r--java/res/values/themes-common.xml92
-rw-r--r--java/res/values/themes-gb.xml40
-rw-r--r--java/res/values/themes-ics.xml39
-rw-r--r--java/res/values/themes-klp.xml39
-rw-r--r--java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml2
-rw-r--r--java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml2
-rw-r--r--java/res/xml-sw600dp/key_azerty3_right.xml2
-rw-r--r--java/res/xml-sw600dp/key_colemak_colon.xml2
-rw-r--r--java/res/xml-sw600dp/key_f1.xml27
-rw-r--r--java/res/xml-sw600dp/key_greek_semicolon.xml2
-rw-r--r--java/res/xml-sw600dp/key_question_exclamation.xml4
-rw-r--r--java/res/xml-sw600dp/key_shortcut.xml8
-rw-r--r--java/res/xml-sw600dp/key_space_symbols.xml1
-rw-r--r--java/res/xml-sw600dp/key_styles_common.xml66
-rw-r--r--java/res/xml-sw600dp/key_styles_enter.xml50
-rw-r--r--java/res/xml-sw600dp/keys_arabic3_left.xml4
-rw-r--r--java/res/xml-sw600dp/keys_comma_period.xml93
-rw-r--r--java/res/xml-sw600dp/keys_dvorak_123.xml12
-rw-r--r--java/res/xml-sw600dp/keys_exclamation_question.xml6
-rw-r--r--java/res/xml-sw600dp/keys_farsi3_right.xml4
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty2_right3.xml12
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty3_right2.xml8
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty4_right3.xml16
-rw-r--r--java/res/xml-sw600dp/row_dvorak4.xml2
-rw-r--r--java/res/xml-sw600dp/rowkeys_dvorak3.xml18
-rw-r--r--java/res/xml-sw600dp/rowkeys_pcqwerty1.xml28
-rw-r--r--java/res/xml-sw600dp/rows_hebrew.xml6
-rw-r--r--java/res/xml-sw600dp/rows_number_normal.xml42
-rw-r--r--java/res/xml-sw600dp/rows_phone.xml16
-rw-r--r--java/res/xml-sw600dp/rows_swiss.xml63
-rw-r--r--java/res/xml-sw600dp/rows_symbols.xml5
-rw-r--r--java/res/xml-sw600dp/rows_symbols_shift.xml5
-rw-r--r--java/res/xml-v16/key_devanagari_sign_anusvara.xml2
-rw-r--r--java/res/xml-v16/key_devanagari_sign_candrabindu.xml2
-rw-r--r--java/res/xml-v16/key_devanagari_sign_nukta.xml2
-rw-r--r--java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml2
-rw-r--r--java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_sign_virama.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_sign_visarga.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml2
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml2
-rw-r--r--java/res/xml/kbd_armenian_phonetic.xml6
-rw-r--r--java/res/xml/kbd_emoji_category1.xml4
-rw-r--r--java/res/xml/kbd_emoji_category2.xml4
-rw-r--r--java/res/xml/kbd_emoji_category3.xml4
-rw-r--r--java/res/xml/kbd_emoji_category4.xml4
-rw-r--r--java/res/xml/kbd_emoji_category5.xml4
-rw-r--r--java/res/xml/kbd_emoji_category6.xml4
-rw-r--r--java/res/xml/kbd_emoji_recents.xml6
-rw-r--r--java/res/xml/kbd_khmer.xml6
-rw-r--r--java/res/xml/kbd_lao.xml6
-rw-r--r--java/res/xml/kbd_more_keys_keyboard_template.xml2
-rw-r--r--java/res/xml/kbd_pcqwerty.xml6
-rw-r--r--java/res/xml/kbd_suggestions_pane_template.xml2
-rw-r--r--java/res/xml/kbd_swiss.xml (renamed from java/res/layout/suggestion_info.xml)15
-rw-r--r--java/res/xml/kbd_thai.xml6
-rw-r--r--java/res/xml/key_armenian_sha.xml2
-rw-r--r--java/res/xml/key_armenian_xeh.xml2
-rw-r--r--java/res/xml/key_azerty3_right.xml4
-rw-r--r--java/res/xml/key_colemak_colon.xml4
-rw-r--r--java/res/xml/key_devanagari_sign_anusvara.xml3
-rw-r--r--java/res/xml/key_devanagari_sign_candrabindu.xml3
-rw-r--r--java/res/xml/key_devanagari_sign_nukta.xml3
-rw-r--r--java/res/xml/key_devanagari_vowel_sign_candra_o.xml3
-rw-r--r--java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml3
-rw-r--r--java/res/xml/key_f1.xml16
-rw-r--r--java/res/xml/key_greek_semicolon.xml4
-rw-r--r--java/res/xml/key_period.xml (renamed from java/res/xml/key_nepali_traditional_period.xml)23
-rw-r--r--java/res/xml/key_space_symbols.xml6
-rw-r--r--java/res/xml/key_styles_common.xml107
-rw-r--r--java/res/xml/key_styles_currency.xml20
-rw-r--r--java/res/xml/key_styles_currency_dollar.xml10
-rw-r--r--java/res/xml/key_styles_currency_euro.xml10
-rw-r--r--java/res/xml/key_styles_enter.xml54
-rw-r--r--java/res/xml/key_styles_number.xml46
-rw-r--r--java/res/xml/key_symbols_period.xml47
-rw-r--r--java/res/xml/key_thai_kho_khuat.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_swiss.xml42
-rw-r--r--java/res/xml/keys_arabic3_left.xml2
-rw-r--r--java/res/xml/keys_comma_period.xml87
-rw-r--r--java/res/xml/keys_comma_period_symbols.xml31
-rw-r--r--java/res/xml/keys_curly_brackets.xml6
-rw-r--r--java/res/xml/keys_dvorak_123.xml16
-rw-r--r--java/res/xml/keys_farsi3_right.xml2
-rw-r--r--java/res/xml/keys_less_greater.xml14
-rw-r--r--java/res/xml/keys_parentheses.xml6
-rw-r--r--java/res/xml/keys_pcqwerty2_right3.xml12
-rw-r--r--java/res/xml/keys_pcqwerty3_right2.xml8
-rw-r--r--java/res/xml/keys_pcqwerty4_right3.xml16
-rw-r--r--java/res/xml/keys_square_brackets.xml6
-rw-r--r--java/res/xml/keystyle_devanagari_sign_virama.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_sign_visarga.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_aa.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_ai.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_au.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_e.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_i.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_ii.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_o.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_u.xml3
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_uu.xml3
-rw-r--r--java/res/xml/method.xml141
-rw-r--r--java/res/xml/prefs.xml7
-rw-r--r--java/res/xml/prefs_for_debug.xml92
-rw-r--r--java/res/xml/row_dvorak4.xml4
-rw-r--r--java/res/xml/row_pcqwerty5.xml3
-rw-r--r--java/res/xml/row_qwerty4.xml32
-rw-r--r--java/res/xml/row_symbols4.xml24
-rw-r--r--java/res/xml/row_symbols_shift4.xml2
-rw-r--r--java/res/xml/rowkeys_arabic1.xml22
-rw-r--r--java/res/xml/rowkeys_arabic2.xml22
-rw-r--r--java/res/xml/rowkeys_arabic3.xml18
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic1.xml20
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic2.xml21
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic3.xml18
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic4.xml14
-rw-r--r--java/res/xml/rowkeys_azerty1.xml20
-rw-r--r--java/res/xml/rowkeys_azerty2.xml20
-rw-r--r--java/res/xml/rowkeys_azerty3.xml12
-rw-r--r--java/res/xml/rowkeys_bulgarian1.xml22
-rw-r--r--java/res/xml/rowkeys_bulgarian2.xml22
-rw-r--r--java/res/xml/rowkeys_bulgarian3.xml16
-rw-r--r--java/res/xml/rowkeys_bulgarian_bds1.xml22
-rw-r--r--java/res/xml/rowkeys_bulgarian_bds2.xml22
-rw-r--r--java/res/xml/rowkeys_bulgarian_bds3.xml18
-rw-r--r--java/res/xml/rowkeys_colemak1.xml18
-rw-r--r--java/res/xml/rowkeys_colemak2.xml20
-rw-r--r--java/res/xml/rowkeys_colemak3.xml14
-rw-r--r--java/res/xml/rowkeys_dvorak1.xml14
-rw-r--r--java/res/xml/rowkeys_dvorak2.xml20
-rw-r--r--java/res/xml/rowkeys_dvorak3.xml14
-rw-r--r--java/res/xml/rowkeys_east_slavic1.xml22
-rw-r--r--java/res/xml/rowkeys_east_slavic2.xml22
-rw-r--r--java/res/xml/rowkeys_east_slavic3.xml18
-rw-r--r--java/res/xml/rowkeys_farsi1.xml22
-rw-r--r--java/res/xml/rowkeys_farsi2.xml22
-rw-r--r--java/res/xml/rowkeys_farsi3.xml18
-rw-r--r--java/res/xml/rowkeys_georgian1.xml40
-rw-r--r--java/res/xml/rowkeys_georgian2.xml36
-rw-r--r--java/res/xml/rowkeys_georgian3.xml28
-rw-r--r--java/res/xml/rowkeys_greek1.xml20
-rw-r--r--java/res/xml/rowkeys_greek2.xml18
-rw-r--r--java/res/xml/rowkeys_greek3.xml14
-rw-r--r--java/res/xml/rowkeys_hebrew1.xml24
-rw-r--r--java/res/xml/rowkeys_hebrew2.xml20
-rw-r--r--java/res/xml/rowkeys_hebrew3.xml18
-rw-r--r--java/res/xml/rowkeys_hindi1.xml32
-rw-r--r--java/res/xml/rowkeys_hindi2.xml34
-rw-r--r--java/res/xml/rowkeys_hindi3.xml26
-rw-r--r--java/res/xml/rowkeys_khmer1.xml49
-rw-r--r--java/res/xml/rowkeys_khmer2.xml59
-rw-r--r--java/res/xml/rowkeys_khmer3.xml50
-rw-r--r--java/res/xml/rowkeys_khmer4.xml44
-rw-r--r--java/res/xml/rowkeys_lao1.xml48
-rw-r--r--java/res/xml/rowkeys_lao2.xml48
-rw-r--r--java/res/xml/rowkeys_lao3.xml48
-rw-r--r--java/res/xml/rowkeys_lao4.xml40
-rw-r--r--java/res/xml/rowkeys_mongolian1.xml22
-rw-r--r--java/res/xml/rowkeys_mongolian2.xml22
-rw-r--r--java/res/xml/rowkeys_mongolian3.xml18
-rw-r--r--java/res/xml/rowkeys_nepali_romanized1.xml26
-rw-r--r--java/res/xml/rowkeys_nepali_romanized2.xml40
-rw-r--r--java/res/xml/rowkeys_nepali_romanized3.xml28
-rw-r--r--java/res/xml/rowkeys_nepali_traditional1.xml42
-rw-r--r--java/res/xml/rowkeys_nepali_traditional2.xml30
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_left6.xml22
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_right3.xml6
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_right5.xml10
-rw-r--r--java/res/xml/rowkeys_nordic1.xml2
-rw-r--r--java/res/xml/rowkeys_nordic2.xml4
-rw-r--r--java/res/xml/rowkeys_pcqwerty1.xml28
-rw-r--r--java/res/xml/rowkeys_pcqwerty1_shift.xml28
-rw-r--r--java/res/xml/rowkeys_qwerty1.xml20
-rw-r--r--java/res/xml/rowkeys_qwerty2.xml18
-rw-r--r--java/res/xml/rowkeys_qwerty3.xml14
-rw-r--r--java/res/xml/rowkeys_qwertz1.xml20
-rw-r--r--java/res/xml/rowkeys_qwertz3.xml14
-rw-r--r--java/res/xml/rowkeys_south_slavic1.xml22
-rw-r--r--java/res/xml/rowkeys_south_slavic2.xml22
-rw-r--r--java/res/xml/rowkeys_south_slavic3.xml18
-rw-r--r--java/res/xml/rowkeys_spanish2.xml2
-rw-r--r--java/res/xml/rowkeys_swiss1.xml (renamed from java/res/layout/key_preview_gb.xml)18
-rw-r--r--java/res/xml/rowkeys_swiss2.xml (renamed from java/res/xml/key_space_3kw.xml)25
-rw-r--r--java/res/xml/rowkeys_symbols1.xml20
-rw-r--r--java/res/xml/rowkeys_symbols2.xml16
-rw-r--r--java/res/xml/rowkeys_symbols3.xml26
-rw-r--r--java/res/xml/rowkeys_symbols_shift1.xml20
-rw-r--r--java/res/xml/rowkeys_symbols_shift2.xml6
-rw-r--r--java/res/xml/rowkeys_symbols_shift3.xml10
-rw-r--r--java/res/xml/rowkeys_thai1.xml51
-rw-r--r--java/res/xml/rowkeys_thai2.xml52
-rw-r--r--java/res/xml/rowkeys_thai3.xml48
-rw-r--r--java/res/xml/rowkeys_thai4.xml44
-rw-r--r--java/res/xml/rows_number_normal.xml38
-rw-r--r--java/res/xml/rows_phone.xml7
-rw-r--r--java/res/xml/rows_phone_symbols.xml18
-rw-r--r--java/res/xml/rows_swiss.xml57
-rw-r--r--java/res/xml/rows_symbols.xml1
-rw-r--r--java/res/xml/rows_symbols_shift.xml1
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java2
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java23
-rw-r--r--java/src/com/android/inputmethod/compat/AppWorkaroundsUtils.java6
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java14
-rw-r--r--java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java17
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java3
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java21
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/CommonPreferences.java2
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryDownloadProgressBar.java11
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java6
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java113
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java109
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java58
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/MetadataHandler.java17
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java32
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/WordListPreference.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java469
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java148
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java53
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java34
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java46
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java29
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java59
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java736
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java15
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java35
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java793
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java181
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/BogusMoveEventDetector.java115
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java22
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/CustomViewPager.java47
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java77
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DrawingPreviewPlacerView.java (renamed from java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java)16
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java58
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java (renamed from java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java)30
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/EmojiPageKeyboardView.java (renamed from java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java)128
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureEnabler.java54
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java)9
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingParams.java58
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java)110
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionParams.java109
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java)184
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingParams.java79
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java)80
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureTrailsDrawingPreview.java (renamed from java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java)59
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java285
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java103
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java491
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java61
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java90
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java3530
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java3655
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java232
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java24
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java66
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java (renamed from java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java)10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java220
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TypingTimeRecorder.java72
-rw-r--r--java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java26
-rw-r--r--java/src/com/android/inputmethod/latin/AssetFileAddress.java10
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java202
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java49
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java6
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java77
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java99
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java7
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryDumpBroadcastReceiver.java50
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java582
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java50
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryWriter.java43
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java524
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java894
-rw-r--r--java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java78
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java297
-rw-r--r--java/src/com/android/inputmethod/latin/InputPointers.java67
-rw-r--r--java/src/com/android/inputmethod/latin/InputView.java245
-rw-r--r--java/src/com/android/inputmethod/latin/LastComposedWord.java4
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java2531
-rw-r--r--java/src/com/android/inputmethod/latin/PunctuationSuggestions.java116
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java404
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java99
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java235
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java84
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java28
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java26
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java30
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java79
-rw-r--r--java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java8
-rw-r--r--java/src/com/android/inputmethod/latin/define/ProductionFlag.java3
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java1962
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java198
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/SpaceState.java54
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java187
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java309
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java252
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java368
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictDecoder.java37
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictEncoder.java4
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictUpdater.java54
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java81
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java492
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java196
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java315
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/ProbabilityInfo.java89
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java12
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/SparseTable.java223
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java316
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java (renamed from java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java)64
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java271
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java82
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java341
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java460
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java59
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Word.java100
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/WordProperty.java164
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java174
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java190
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java55
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java (renamed from java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java)19
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java128
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java106
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java37
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java32
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java128
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AdditionalSubtypeSettings.java8
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java166
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java130
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsFragment.java128
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java306
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java119
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java10
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java4
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java14
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java9
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java1
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java2
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java27
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java2
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java194
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java242
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java31
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java20
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java79
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java20
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java12
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java47
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java29
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CollectionUtils.java15
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java99
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java46
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CsvUtils.java7
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java49
-rw-r--r--java/src/com/android/inputmethod/latin/utils/FileUtils.java54
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java114
-rw-r--r--java/src/com/android/inputmethod/latin/utils/JsonUtils.java103
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java171
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java (renamed from java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java)20
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LocaleUtils.java47
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java1
-rw-r--r--java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java18
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ResourceUtils.java60
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java22
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java247
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java25
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java14
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TextRange.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java36
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java182
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java233
-rw-r--r--java/src/com/android/inputmethod/research/JsonUtils.java2
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java29
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java113
636 files changed, 22075 insertions, 19815 deletions
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 031d62e0c..a7e64bfaa 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"
@@ -57,7 +58,7 @@
<activity android:name=".setup.SetupActivity"
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>
@@ -110,13 +111,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>
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png
deleted file mode 100644
index 3e25180f0..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index bad360f77..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 49f519860..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
deleted file mode 100644
index e784eddf8..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index a4731cf1a..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 03e163c9c..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_launcher_keyboard.png b/java/res/drawable-hdpi/ic_launcher_keyboard.png
new file mode 100644
index 000000000..7ae00ed3f
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_subtype_mic_dark.png b/java/res/drawable-hdpi/ic_subtype_mic_dark.png
deleted file mode 100644
index eacbcd255..000000000
--- a/java/res/drawable-hdpi/ic_subtype_mic_dark.png
+++ /dev/null
Binary files differ
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
index 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
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png
index 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
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png
deleted file mode 100644
index 12bc97928..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 44bd414a1..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 43fdf5b88..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
deleted file mode 100644
index 1c1f3d711..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index dacb675a9..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 3daa69f31..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_launcher_keyboard.png b/java/res/drawable-mdpi/ic_launcher_keyboard.png
new file mode 100644
index 000000000..cc73f3be1
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_launcher_keyboard.png
Binary files differ
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
index 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
Binary files differ
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
deleted file mode 100644
index 537f39b02..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png b/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png
deleted file mode 100644
index 84a63dc7f..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png
index 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
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png
deleted file mode 100644
index 026005d6f..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 38c5f244b..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index f1223e50e..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png
deleted file mode 100644
index ec35db54d..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index bd30464d6..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_off.9.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index a3ff5d1bb..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_pressed_on.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_launcher_keyboard.png b/java/res/drawable-xhdpi/ic_launcher_keyboard.png
new file mode 100644
index 000000000..f2ac50dfe
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_subtype_mic_dark.png b/java/res/drawable-xhdpi/ic_subtype_mic_dark.png
deleted file mode 100644
index 17581ba89..000000000
--- a/java/res/drawable-xhdpi/ic_subtype_mic_dark.png
+++ /dev/null
Binary files differ
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
index 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
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png
index 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
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_launcher_keyboard.png b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png
new file mode 100644
index 000000000..df386e827
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png b/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png
deleted file mode 100644
index 811103a56..000000000
--- a/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png
+++ /dev/null
Binary files differ
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
index 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
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png
index 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
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_spacebar_gb.xml b/java/res/drawable/btn_keyboard_spacebar_gb.xml
new file mode 100644
index 000000000..4d51f3c9c
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_spacebar_gb.xml
@@ -0,0 +1,21 @@
+<?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">
+ <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_spacebar_ics.xml b/java/res/drawable/btn_keyboard_spacebar_ics.xml
new file mode 100644
index 000000000..4530ea079
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_spacebar_ics.xml
@@ -0,0 +1,21 @@
+<?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">
+ <item android:state_pressed="true"
+ 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_spacebar_klp.xml b/java/res/drawable/btn_keyboard_spacebar_klp.xml
new file mode 100644
index 000000000..6b07a392f
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_spacebar_klp.xml
@@ -0,0 +1,21 @@
+<?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">
+ <item android:state_pressed="true"
+ 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/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_palettes_view.xml b/java/res/layout/emoji_palettes_view.xml
index 1c6da90ba..4fb744ed2 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"
@@ -73,7 +73,7 @@
android:background="@color/emoji_key_background_color"
android:src="@drawable/sym_keyboard_delete_holo_dark" />
</LinearLayout>
- <android.support.v4.view.ViewPager
+ <com.android.inputmethod.keyboard.internal.CustomViewPager
android:id="@+id/emoji_keyboard_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@@ -89,22 +89,22 @@
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"
+ <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_ics.xml b/java/res/layout/key_preview.xml
index 33b6947ef..16d4c72c3 100644
--- a/java/res/layout/key_preview_ics.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_ics"
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_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
deleted file mode 100644
index 36b1ccae2..000000000
--- a/java/res/mipmap-hdpi/ic_launcher_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/mipmap-mdpi/ic_launcher_keyboard.png b/java/res/mipmap-mdpi/ic_launcher_keyboard.png
deleted file mode 100644
index 67ef189ff..000000000
--- a/java/res/mipmap-mdpi/ic_launcher_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/mipmap-xhdpi/ic_launcher_keyboard.png b/java/res/mipmap-xhdpi/ic_launcher_keyboard.png
deleted file mode 100644
index b33208332..000000000
--- a/java/res/mipmap-xhdpi/ic_launcher_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png b/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png
deleted file mode 100644
index acc424fe2..000000000
--- a/java/res/mipmap-xxhdpi/ic_launcher_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/raw/main_de.dict b/java/res/raw/main_de.dict
index 69796bbaa..c65698d7b 100644
--- a/java/res/raw/main_de.dict
+++ b/java/res/raw/main_de.dict
Binary files differ
diff --git a/java/res/raw/main_fr.dict b/java/res/raw/main_fr.dict
index 0e5a71360..c240d9665 100644
--- a/java/res/raw/main_fr.dict
+++ b/java/res/raw/main_fr.dict
Binary files differ
diff --git a/java/res/raw/main_it.dict b/java/res/raw/main_it.dict
index e161c2475..98135ce8e 100644
--- a/java/res/raw/main_it.dict
+++ b/java/res/raw/main_it.dict
Binary files differ
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..d0f328fd3
--- /dev/null
+++ b/java/res/values-af/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-af/strings.xml
index 045e97d94..df43b13c7 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> voer outokorrigering 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Wys tans <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"tyd"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisioneel)"</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 +165,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">"Gooi kontaktewoordeboek weg"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Gooi persoonlike woordeboek weg"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Gooi gebruikergeskiedeniswoordeboek weg"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Gooi personaliseringwoordeboek weg"</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 +208,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.&lt;br/&gt; Ons beveel aan dat die <xliff:g id="LANGUAGE">%1$s</xliff:g>-woordeboek &lt;b&gt;afgelaai&lt;/b&gt; word om jou tikervaring te verbeter.&lt;br/&gt; &lt;br/&gt; Dit kan \'n minuut of twee neem om oor 3G af te laai. Heffings kan dalk geld as jy nie \'n &lt;b&gt;onbeperkte dataplan&lt;/b&gt; het nie.&lt;br/&gt; As jy onseker oor jou dataplan is, beveel ons aan dat jy \'n Wi-Fi-verbinding soek om outomaties te begin aflaai.&lt;br/&gt; &lt;br/&gt; Wenk: Jy kan woordeboeke aflaai en verwyder deur te gaan na &lt;b&gt;Taal en invoer&lt;/b&gt; in die &lt;b&gt;Instellings&lt;/b&gt;-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.&lt;br/&gt; Ons beveel aan dat die <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-woordeboek &lt;b&gt;afgelaai&lt;/b&gt; word om jou tikervaring te verbeter.&lt;br/&gt; &lt;br/&gt; Dit kan \'n minuut of twee duur om oor 3G af te laai. Heffings kan dalk geld as jy nie \'n &lt;b&gt;onbeperkte dataplan&lt;/b&gt; het nie.&lt;br/&gt; As jy onseker is oor watter dataplan jy het, beveel ons aan dat jy \'n Wi-Fi-verbinding soek om outomaties te begin aflaai.&lt;br/&gt; &lt;br/&gt; Wenk: Jy kan woordeboeke aflaai en verwyder deur te gaan na &lt;b&gt;Taal en invoer&lt;/b&gt; in die &lt;b&gt;Instellings&lt;/b&gt;-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..5bef0436c
--- /dev/null
+++ b/java/res/values-am/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"የአስተያየት ጥቆማዎችን ለማሻሻል ከእርስዎ ግንኙነቶች እና የተተየበ ውሂብ ይማሩ"</string>
+</resources>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 0b81034f4..3921fd135 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"የሐረግ ምልክት"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ምልክት በሚሰጡበት ጊዜ ወደ ክፍተት ቁልፉ በማንሸራተት ክፍተቶችን ያስገቡ"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"የ<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"ጊዜ"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"ዩ አር ኤል"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"ተንቀሳቃሽ መሣሪያዎ ላይ ለተመረጠው ቋንቋ የሚሆን መዝገበ-ቃላት ይገኛል።&lt;br/&gt; የትየባ ተሞክሮዎን ለማሻሻል የ<xliff:g id="LANGUAGE">%1$s</xliff:g> መዝገበ-ቃላቱን &lt;b&gt;እንዲያወርዱ&lt;/b&gt; እንመክራለን።&lt;br/&gt; &lt;br/&gt; ውርዱ በ3ጂ ላይ አንድ ወይም ሁለት ደቂቃ ሊወስድ ይችላል። &lt;b&gt;ያልተገደበ የውሂብ ዕቅድ&lt;/b&gt; ከሌለዎት ክፍያዎች መከፈል ሊኖርባቸው ይችላል።&lt;br/&gt; የትኛው የውሂብ ዕቅድ እንዳለዎት እርግጠኛ ካልሆኑ ውርዱን በራስ-ሰር ለመጀመር የWi-Fi ግንኙነት እንዲፈልጉ እንመክራለን።&lt;br/&gt; &lt;br/&gt; ጠቃሚ ምክር፦ የተንቀሳቃሽ መሣሪያዎ &lt;b&gt;ቅንብሮች&lt;/b&gt; ምናሌ ውስጥ ወዳለው &lt;b&gt;ቋንቋ እና ግብዓት&lt;/b&gt; በመሄድ መዝገበ-ቃላትን ማውረድና ማስወገድ ይችላሉ።"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"በተንቀሳቃሽ መሣሪያዎ ላይ ለተመረጠው ቋንቋ የሚሆን መዝገበ-ቃላት ይገኛል።&lt;br/&gt; የትየባ ተሞክሮዎን ለማሻሻል የ<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> መዝገበ-ቃላቱን &lt;b&gt;እንዲያወርዱ&lt;/b&gt; እንመክራለን።&lt;br/&gt; &lt;br/&gt; ማውረድ በ3ጂ ላይ አንድ ወይም ሁለት ደቂቃ ሊወስድ ይችላል። &lt;b&gt;ያልተገደበ የውሂብ ዕቅድ&lt;/b&gt; ከሌለዎት ክፍያዎች መከፈል ሊኖርባቸው ይችላል።&lt;br/&gt; የትኛው የውሂብ ዕቅድ እንዳለዎት እርግጠኛ ካልሆኑ ውርዱን በራስ-ሰር ለመጀመር የWi-Fi ግንኙነት እንዲፈልጉ እንመክራለን።&lt;br/&gt; &lt;br/&gt; ጠቃሚ ምክር፦ የተንቀሳቃሽ መሣሪያዎ &lt;b&gt;ቅንብሮች&lt;/b&gt; ምናሌ ውስጥ ወዳለው &lt;b&gt;ቋንቋ እና ግብዓት&lt;/b&gt; በመሄድ መዝገበ-ቃላትን ማውረድና ማስወገድ ይችላሉ።"</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-iw/donottranslate.xml b/java/res/values-ar-sw600dp/config-spacing-and-punctuations.xml
index 57de2538b..56296361f 100644
--- a/java/res/values-iw/donottranslate.xml
+++ b/java/res/values-ar-sw600dp/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,7 @@
<!-- 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+061B: "؛" ARABIC SEMICOLON -->
+ <string name="suggested_punctuations" translatable="false">!,&#x061F;,:,&#x061B;,\",\',(|),)|(,-,/,@,_</string>
</resources>
diff --git a/java/res/values-ar/donottranslate.xml b/java/res/values-ar/config-spacing-and-punctuations.xml
index 57de2538b..d33a104df 100644
--- a/java/res/values-ar/donottranslate.xml
+++ b/java/res/values-ar/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" translatable="false">!,&#x061F;,&#x060C;,:,&#x061B;,\",(|),)|(,\',-,/,@,_</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..36600af24
--- /dev/null
+++ b/java/res/values-ar/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"التعلم من اتصالاتك والبيانات التي تكتبها لتحسين الاقتراحات"</string>
+</resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index da331196c..a0c26cf9c 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"عبارة الإيماء"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"إدخال مسافات خلال الإيماءات من خلال تمرير مفتاح المسافة"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"إظهار لوحة مفاتيح <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"‏اللغة المحددة على جهازك الجوال تشتمل على قاموس متوفر.&lt;br/&gt; نوصي &lt;b&gt;بتنزيل&lt;/b&gt; قاموس <xliff:g id="LANGUAGE">%1$s</xliff:g> لتحسين تجربة الكتابة.&lt;br/&gt; &lt;br/&gt; قد يستغرق التنزيل دقيقة أو دقيقتين أكثر من المدة التي يستغرقها التنزيل عبر شبكة الجيل الثالث. قد تنطبق الرسوم إذا لم تكن مشتركًا في &lt;b&gt;خطة البيانات غير المحدودة&lt;/b&gt;.&lt;br/&gt; إذا لم تكن متأكدًا من خطة البيانات المتوفرة لديك، فنحن نوصي بالبحث عن اتصال Wi-Fi لبدء عملية التنزيل تلقائيًا.&lt;br/&gt; &lt;br/&gt; نصيحة: يمكنك تنزيل القواميس وإزالتها عن طريق الانتقال إلى &lt;b&gt;اللغة والإدخال&lt;/b&gt; في قائمة &lt;b&gt;إعدادات&lt;/b&gt; في جهازك الجوَّال."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"‏اللغة المحددة على جهازك الجوّال تشتمل على قاموس متوفر.&lt;br/&gt; نوصي &lt;b&gt;بتنزيل&lt;/b&gt; قاموس <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> لتحسين تجربة الكتابة.&lt;br/&gt; &lt;br/&gt; قد يستغرق التنزيل دقيقة أو دقيقتين عبر شبكة الجيل الثالث. قد تنطبق الرسوم إذا لم تكن مشتركًا في &lt;b&gt;خطة البيانات غير المحدودة&lt;/b&gt;.&lt;br/&gt; إذا لم تكن متأكدًا من خطة البيانات المتوفرة لديك، فنحن نوصي بالبحث عن اتصال Wi-Fi لبدء عملية التنزيل تلقائيًا.&lt;br/&gt; &lt;br/&gt; نصيحة: يمكنك تنزيل القواميس وإزالتها من خلال الانتقال إلى &lt;b&gt;اللغة والإدخال&lt;/b&gt; في القائمة &lt;b&gt;إعدادات&lt;/b&gt; في جهازك الجوّال."</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..1815443c2
--- /dev/null
+++ b/java/res/values-az-rAZ/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-az-rAZ/strings.xml
new file mode 100644
index 000000000..2fe102a47
--- /dev/null
+++ b/java/res/values-az-rAZ/strings.xml
@@ -0,0 +1,244 @@
+<?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="spoken_use_headphones" msgid="896961781287283493">"Parolu səsli eşitmək üçün qulaqcığı taxın"</string>
+ <string name="spoken_current_text_is" msgid="2485723011272583845">"Cari mətn %s\'dir"</string>
+ <string name="spoken_no_text_entered" msgid="7479685225597344496">"Mətn daxil edilməyib"</string>
+ <string name="spoken_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> avto-korreksiyanı həyata keçirir"</string>
+ <string name="spoken_description_unknown" msgid="3197434010402179157">"%d açar kodu"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Sürüşdürmə"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Sürüşdürmə aktivdir (deaktiv etmək üçün klikləyin)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Böyük hərf kilidi aktivdir (deaktiv etmək üçün klikləyin)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Sil"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simvollar"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Hərflər"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Nömrələr"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Parametrlər"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Boşluq"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Səs daxiletməsi"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Smaylik"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Qayıt"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Axtar"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Nöqtə"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Dil keçidi"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Növbəti"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Əvvəlki"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Sürüşdürmə aktivdir"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Böyük hərf kilidi aktivdir"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Sürüşdürmə deaktivdir"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Simvol rejimi"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Hərf rejimi"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefon rejimi"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefon simvol rejimi"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Gizlədilmiş klaviatura"</string>
+ <string name="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> klaviaturası göstərilir"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"tarix"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"gün və tarix"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"E-poçt"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"mesajlaşma"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"nömrə"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"mətn"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"vaxt"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Ənənəvi)"</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&gt;Dil&gt;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">"Для выбранай мовы на мабільнай прыладзе ёсць слоўнік.&lt;br/&gt; Мы рэкамендуем &lt;b&gt;спампаваць&lt;/b&gt; слоўнік для мовы \"<xliff:g id="LANGUAGE">%1$s</xliff:g>\" для паляпшэння зручнасці набору.&lt;br/&gt; &lt;br/&gt; Спампоўка можа заняць хвіліну або дзве ў 3G-сетках. Калі ў вас няма &lt;b&gt;безлімітнага тарыфнага плану перадачы дадзеных&lt;/b&gt;, могуць прымяняцца дадатковыя плацяжы&lt;br/&gt;. Калі вы не ведаеце дакладна, які ў вас тарыфны план, мы рэкамендуем знайсці падлучэнне да сеткі Wi-Fi, каб пачаць аўтаматычную спампоўку.&lt;br/&gt; &lt;br/&gt; Парада: можна спампоўваць і выдаляць слоўнікі, перайшоўшы ў раздзел &lt;b&gt;Мова і ўвод&lt;/b&gt; у меню &lt;b&gt;Налады&lt;/b&gt; вашай мабільнай прылады."</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..b6b766637
--- /dev/null
+++ b/java/res/values-bg/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Ползване на съобщ. ви и въведени от вас данни за подобр. на предлож."</string>
+</resources>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index c3fbd7982..7e86abf5b 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Жест за фрази"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"При жестове въвеждaйте интервали чрез плъзгане през съотв. клавиш"</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_auto_correct" msgid="5150455215290003221">"„<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="2309828861778711939">"„<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Показва се клавиатурата за <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"Налице е речник за избрания език на мобилното ви устройство.&lt;br/&gt; Препоръчваме ви &lt;b&gt;dда изтеглите&lt;/b&gt; речника за <xliff:g id="LANGUAGE">%1$s</xliff:g>, за да подобрите практическата си работа при писане.&lt;br/&gt; &lt;br/&gt; Изтеглянето през 3G може да отнеме една до две минути. Възможно е да бъдете таксувани, ако нямате &lt;b&gt;неограничен план за данни&lt;/b&gt;.&lt;br/&gt; В случай че не сте сигурни какъв е вашият план, ви препоръчваме да намерите Wi-Fi връзка, за да започнете автоматично изтеглянето.&lt;br/&gt; &lt;br/&gt; Съвет: Можете да изтегляте и премахвате речници, като отворите &lt;b&gt;Език и въвеждане&lt;/b&gt; в менюто &lt;b&gt;Настройки&lt;/b&gt; на мобилното си устройство."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Налице е речник за избрания език на мобилното ви устройство.&lt;br/&gt; Препоръчваме ви &lt;b&gt;да изтеглите&lt;/b&gt; речника за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>, за да подобрите практическата си работа при писане.&lt;br/&gt; &lt;br/&gt; Изтеглянето през 3G може да отнеме една до две минути. Възможно е да бъдете таксувани, ако нямате &lt;b&gt;неограничен план за данни&lt;/b&gt;.&lt;br/&gt; В случай че не сте сигурни какъв е вашият план, ви препоръчваме да намерите Wi-Fi връзка, за да започнете автоматично изтеглянето.&lt;br/&gt; &lt;br/&gt; Съвет: Можете да изтегляте и премахвате речници, като отворите &lt;b&gt;Език и въвеждане&lt;/b&gt; в менюто &lt;b&gt;Настройки&lt;/b&gt; на мобилното си устройство."</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..eadb5695e
--- /dev/null
+++ b/java/res/values-ca/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Considera comunicacions i dades introduïdes per millorar sugger."</string>
+</resources>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index 0b9ee037e..7137aa59c 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> executa la correcció automàtica."</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>
@@ -88,7 +90,7 @@
<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_tab" msgid="2667716002663482248">"Tabulador"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Es mostra el teclat per a <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</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 +165,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">"Esborrar 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 +208,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.&lt;br/&gt; Et recomanem que &lt;b&gt;baixis&lt;/b&gt; el diccionari de <xliff:g id="LANGUAGE">%1$s</xliff:g> per millorar la teva experiència d\'escriptura.&lt;br/&gt; &lt;br/&gt; La baixada pot trigar un parell de minuts en xarxes 3G. Si no tens un &lt;b&gt;pla de dades il·limitat&lt;/b&gt;.&lt;br/&amp;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.&lt;br/&gt; &lt;br/&gt; Consell: Pots baixar i suprimir diccionaris a la secció &lt;b&gt;Idioma i introducció de text&lt;/b&gt; del menú &lt;b&gt;Configuració&lt;/b&gt; 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.&lt;br/&gt; Et recomanem que &lt;b&gt;baixis&lt;/b&gt; el diccionari per a <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> per millorar la teva experiència d\'escriptura.&lt;br/&gt; &lt;br/&gt; La baixada pot trigar un parell de minuts en xarxes 3G. Si no tens un &lt;b&gt;pla de dades il·limitat&lt;/b&gt;,&lt;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.&lt;br/&gt; &lt;br/&gt;Consell: Pots baixar i suprimir diccionaris a la secció &lt;b&gt;Idioma i introducció de text&lt;/b&gt; del menú &lt;b&gt;Configuració&lt;/b&gt; 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..bb2f03abc
--- /dev/null
+++ b/java/res/values-cs/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-cs/strings.xml
index c73e8ab1c..e517043bb 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Klávesou <xliff:g id="KEY_NAME">%1$s</xliff:g> provedete 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Je zobrazena klávesnice <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"adresy URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradiční)"</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 +165,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 +208,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.&lt;br/&gt; Doporučujeme slovník pro jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> &lt;b&gt;stáhnout&lt;/b&gt;. Usnadníte si tím zadávání textu.&lt;br/&gt; &lt;br/&gt; V síti 3G bude stahování chvíli trvat. Pokud nemáte &lt;b&gt;neomezený datový tarif&lt;/b&gt;, mohou vám být účtovány poplatky.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky můžete stahovat a odstraňovat v nabídce mobilního zařízení &lt;b&gt;Jazyk a vstup&lt;/b&gt; v &lt;b&gt;Nastavení&lt;/b&gt;."</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.&lt;br/&gt; Doporučujeme slovník pro jazyk <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> &lt;b&gt;stáhnout&lt;/b&gt;. Usnadníte si tím zadávání textu. &lt;br/&gt; &lt;br/&gt; V síti 3G bude stahování trvat minutu až dvě. Pokud nemáte &lt;b&gt;neomezený datový tarif&lt;/b&gt;, mohou vám být účtovány poplatky.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky můžete stahovat a odstraňovat v nabídce mobilního zařízení &lt;b&gt;Jazyk a zadávání&lt;/b&gt; v &lt;b&gt;Nastavení&lt;/b&gt;."</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/values-da/strings-config-important-notice.xml b/java/res/values-da/strings-config-important-notice.xml
new file mode 100644
index 000000000..57d32cd74
--- /dev/null
+++ b/java/res/values-da/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-da/strings.xml
index 86bdad469..babea965c 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -46,6 +46,7 @@
<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>
@@ -73,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> udfører automatisk stavekontrol"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Viser tastatur til <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionelt)"</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 +165,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">"Eksportér ordbog for kontakter"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Eksportér personlig ordbog"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Eksportér ordbog for brugerhistorik"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Eksportér 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>
@@ -207,18 +208,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.&lt;br/&gt; Vi anbefaler, at du &lt;b&gt;downloader&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g>-ordbogen for at forbedre din skriveoplevelse.&lt;br/&gt; &lt;br/&gt; Downloaden kan tage 1-2 minutter via 3G. Der bliver muligvis opkrævet et gebyr, hvis du ikke har et &lt;b&gt;ubegrænset dataabonnement&lt;/b&gt;.&lt;br/&gt;. Hvis du ikke er sikker på, hvilket dataabonnement du har, anbefaler vi, at du finder en Wi-Fi-forbindelse for at starte automatisk download.&lt;br/&gt; &lt;br/&gt;Tip! Du kan downloade og fjerne ordbøger ved at gå til &lt;b&gt;Sprog og input &lt;/b&gt; i menuen &lt;b&gt;Indstillinger&lt;/b&gt; på din mobilenhed."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Det valgte sprog på din mobilenhed har en tilgængelig ordbog.&lt;br/&gt; Vi anbefaler, at du &lt;b&gt;downloader&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-ordbogen for at forbedre din skriveoplevelse.&lt;br/&gt; &lt;br/&gt; Downloaden kan tage 1-2 minutter via 3G. Der bliver muligvis opkrævet et gebyr, hvis du ikke har et &lt;b&gt;ubegrænset dataabonnement&lt;/b&gt;.&lt;br/&gt;. Hvis du ikke er sikker på, hvilket dataabonnement du har, anbefaler vi, at du finder en Wi-Fi-forbindelse for at starte automatisk download.&lt;br/&gt; &lt;br/&gt;Tip! Du kan downloade og fjerne ordbøger ved at gå til &lt;b&gt;Sprog og input &lt;/b&gt; i menuen &lt;b&gt;Indstillinger&lt;/b&gt; 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..5a8420229
--- /dev/null
+++ b/java/res/values-de/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-de/strings.xml
index b65053465..a42f85dc3 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,15 +74,16 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"Mit <xliff:g id="KEY_NAME">%1$s</xliff:g> wird \"<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>\" zu \"<xliff:g id="CORRECTED_WORD">%3$s</xliff:g>\" geändert."</string>
+ <string name="spoken_auto_correct_obscured" msgid="2309828861778711939">"Mit <xliff:g id="KEY_NAME">%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_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 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>
@@ -98,15 +100,15 @@
<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_on" msgid="5700440798609574589">"Shift 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_shiftmode_off" msgid="657219998449174808">"Shift 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="announce_keyboard_mode" msgid="7486740369324538848">"Tastatur für <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</string>
<string name="keyboard_mode_date" msgid="3137520166817128102">"Datum"</string>
<string name="keyboard_mode_date_time" msgid="339593358488851072">"Datum &amp; Uhrzeit"</string>
<string name="keyboard_mode_email" msgid="6216248078128294262">"E-Mail-Adresse"</string>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"Zeit"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 &amp; 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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionell)"</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 +165,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 +208,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.&lt;br/&gt; &lt;b&gt;Laden Sie das <xliff:g id="LANGUAGE">%1$s</xliff:g>-Wörterbuch herunter&lt;/b&gt; und verbessern Sie Ihre Eingabeerfahrung.&lt;br/&gt; &lt;br/&gt;Der Download über 3G kann ein bis zwei Minuten dauern. Falls Sie keine &lt;b&gt;Datenflatrate&lt;/b&gt; haben, fallen eventuell Gebühren an.&lt;br/&gt; Sollten Sie sich nicht sicher sein, welchen Datentarif Sie haben, suchen Sie eine WLAN-Verbindung, um den Download automatisch zu starten.&lt;br/&gt; &lt;br/&gt;Tipp: Im Menü &lt;b&gt;Einstellungen&lt;/b&gt; Ihres Mobilgeräts können Sie unter &lt;b&gt;Sprache &amp; Eingabe&lt;/b&gt; 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.&lt;br/&gt; &lt;b&gt;Laden Sie das <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-Wörterbuch herunter&lt;/b&gt; und verbessern Sie Ihre Eingabeerfahrung.&lt;br/&gt; &lt;br/&gt; Der Download über 3G kann ein bis zwei Minuten dauern. Falls Sie keine &lt;b&gt;Datenflatrate&lt;/b&gt; haben, fallen eventuell Gebühren an.&lt;br/&gt; Sollten Sie sich nicht sicher sein, welchen Datentarif Sie haben, suchen Sie eine WLAN-Verbindung, um den Download automatisch zu starten.&lt;br/&gt; &lt;br/&gt; Tipp: Im Menü &lt;b&gt;Einstellungen&lt;/b&gt; Ihres Mobilgeräts können Sie unter &lt;b&gt;Sprache &amp; Eingabe&lt;/b&gt; 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..4ee3532c8
--- /dev/null
+++ b/java/res/values-el/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Χρήση επικοινωνιών/δεδομένων πληκτρολόγησης για βελτίωση προτάσεων"</string>
+</resources>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 79e83423c..5e888e0fd 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Εισαγωγή φράσεων με κίνηση"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Εισαγάγετε κενά στις κινήσεις με ολίσθηση στο πλήκτρο διαστήματος"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Εμφάνιση πληκτρολογίου <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"Η επιλ. γλώσσα στην κιν. συσκευή σας διαθέτει λεξικό.&lt;br/&gt; Προτείνουμε να &lt;b&gt;κάνετε λήψη&lt;/b&gt; του λεξικού <xliff:g id="LANGUAGE">%1$s</xliff:g> για να βελτ. την πληκτρολόγηση.&lt;br/&gt; &lt;br/&gt; Για τη λήψη μπορεί να χρειαστούν 1 ή 2 λεπτά μέσω 3G. Ίσως ισχύουν χρεώσεις αν δεν έχετε &lt;b&gt;πρόγρ. απερ. δεδομ.&lt;/b&gt;.&lt;br/&gt; Αν δεν γνωρίζετε ποιο πρόγ. δεδ. έχετε, προτείνουμε να βρείτε μια σύνδ. Wi-Fi για να ξεκιν. αυτόμ. η λήψη.&lt;br/&gt; &lt;br/&gt; Συμβουλή: Μπορείτε να λάβετε και να καταργ. λεξικά, από την περιοχή &lt;b&gt;Γλώσσα και εισαγωγή&lt;/b&gt;, στο μενού &lt;b&gt;Ρυθμίσεις&lt;/b&gt; της κιν. συσκ."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Η επιλεγμένη γλώσσα στην κινητή συσκευή σας διαθέτει λεξικό.&lt;br/&gt; Προτείνουμε να &lt;b&gt;κατεβάσετε&lt;/b&gt; το λεξικό <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> για βελτίωση της πληκτρολόγησης.&lt;br/&gt; &lt;br/&gt; Για τη λήψη μπορεί να χρειαστούν 1 ή 2 λεπτά μέσω 3G. Ενδέχεται να ισχύουν χρεώσεις αν δεν έχετε διαθέτετε&lt;b&gt;πρόγραμμα απεριόριστων δεδομένων&lt;/b&gt;.&lt;br/&gt; Αν δεν γνωρίζετε ποιο πρόγραμμα δεδομένων διαθέτετε, προτείνουμε να χρησιμοποιήσετε μια σύνδεση Wi-Fi για να ξεκινήσει αυτόματα η λήψη.&lt;br/&gt; &lt;br/&gt; Συμβουλή: Μπορείτε να κατεβάσετε και να καταργήσετε λεξικά, από την περιοχή &lt;b&gt;Γλώσσα και εισαγωγή&lt;/b&gt;, στο μενού &lt;b&gt;Ρυθμίσεις&lt;/b&gt; της κινητής συσκευής σας."</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..a7ae30062
--- /dev/null
+++ b/java/res/values-en-rGB/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-en-rGB/strings.xml
index 4bc1b15cf..a84b389bf 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Showing <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 &amp; 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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Traditional)"</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 +165,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 +208,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.&lt;br/&gt; We recommend &lt;b&gt;downloading&lt;/b&gt; the <xliff:g id="LANGUAGE">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/&gt; &lt;br/&gt; The download could take a minute or two over 3G. Charges may apply if you don\'t have an &lt;b&gt;unlimited data plan&lt;/b&gt;.&lt;br/&gt; If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.&lt;br/&gt; &lt;br/&gt; Tip: You can download and remove dictionaries by going to &lt;b&gt;Language &amp; input&lt;/b&gt; in the &lt;b&gt;Settings&lt;/b&gt; 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.&lt;br/&gt; We recommend &lt;b&gt;downloading&lt;/b&gt; the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/&gt; &lt;br/&gt; The download could take a minute or two over 3G. Charges may apply if you don\'t have an &lt;b&gt;unlimited data plan&lt;/b&gt;.&lt;br/&gt; If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.&lt;br/&gt; &lt;br/&gt; Tip: You can download and remove dictionaries by going to &lt;b&gt;Language &amp; input&lt;/b&gt; in the &lt;b&gt;Settings&lt;/b&gt; 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..a7ae30062
--- /dev/null
+++ b/java/res/values-en-rIN/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-en-rIN/strings.xml
index 4bc1b15cf..a84b389bf 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Showing <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 &amp; 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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Traditional)"</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 +165,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 +208,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.&lt;br/&gt; We recommend &lt;b&gt;downloading&lt;/b&gt; the <xliff:g id="LANGUAGE">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/&gt; &lt;br/&gt; The download could take a minute or two over 3G. Charges may apply if you don\'t have an &lt;b&gt;unlimited data plan&lt;/b&gt;.&lt;br/&gt; If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.&lt;br/&gt; &lt;br/&gt; Tip: You can download and remove dictionaries by going to &lt;b&gt;Language &amp; input&lt;/b&gt; in the &lt;b&gt;Settings&lt;/b&gt; 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.&lt;br/&gt; We recommend &lt;b&gt;downloading&lt;/b&gt; the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/&gt; &lt;br/&gt; The download could take a minute or two over 3G. Charges may apply if you don\'t have an &lt;b&gt;unlimited data plan&lt;/b&gt;.&lt;br/&gt; If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.&lt;br/&gt; &lt;br/&gt; Tip: You can download and remove dictionaries by going to &lt;b&gt;Language &amp; input&lt;/b&gt; in the &lt;b&gt;Settings&lt;/b&gt; 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..b39cfbabf
--- /dev/null
+++ b/java/res/values-es-rUS/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-es-rUS/strings.xml
index 1fd9cf8f0..c900c6aee 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Mostrando teclado de <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</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 +165,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">"Volcar 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 +208,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.&lt;br/&gt; Te recomendamos que &lt;b&gt;descargues&lt;/b&gt; el diccionario de <xliff:g id="LANGUAGE">%1$s</xliff:g> para mejorar tu experiencia de escritura.&lt;br/&gt; &lt;br/&gt; La descarga puede tardar unos minutos en redes 3G. Si no tienes un &lt;b&gt;plan de datos ilimitado&lt;/b&gt;, es posible que se apliquen cargos.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Sugerencia: Puedes descargar y eliminar diccionarios en la sección &lt;b&gt;Teclado e idioma&lt;/b&gt; del menú &lt;b&gt;Configuración&lt;/b&gt; 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.&lt;br/&gt; Te recomendamos que &lt;b&gt;descargues&lt;/b&gt; el diccionario de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para mejorar tu experiencia de escritura.&lt;br/&gt; &lt;br/&gt; La descarga puede tardar unos minutos en redes 3G. Si no tienes un &lt;b&gt;plan de datos ilimitado&lt;/b&gt;, es posible que se apliquen cargos.&lt;br/&gt; Si no sabes qué plan de datos tienes, te recomendamos que uses una conexión Wi-Fi para iniciar la descarga automáticamente.&lt;br/&gt; &lt;br/&gt; Sugerencia: Puedes descargar y eliminar diccionarios desde &lt;b&gt;Teclado e idioma&lt;/b&gt; en el menú &lt;b&gt;Configuración&lt;/b&gt; 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..4d82e8b37
--- /dev/null
+++ b/java/res/values-es/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-es/strings.xml
index 39b45e0c4..ad7547f70 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> corregirá la palabra 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Mostrando teclado de <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</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 +165,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">"Volcar 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 +208,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.&lt;br/&gt; Te recomendamos que &lt;b&gt;descargues&lt;/b&gt; el diccionario de <xliff:g id="LANGUAGE">%1$s</xliff:g> para mejorar tu experiencia de escritura.&lt;br/&gt; &lt;br/&gt; La descarga puede tardar unos minutos en redes 3G. Si no tienes un &lt;b&gt;plan de datos ilimitado&lt;/b&gt;, se pueden aplicar cargos.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Sugerencia: puedes descargar y eliminar diccionarios en la sección &lt;b&gt;Idioma e introducción de texto&lt;/b&gt; del menú &lt;b&gt;Ajustes&lt;/b&gt; 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.&lt;br/&gt; Te recomendamos que &lt;b&gt;descargues&lt;/b&gt; el diccionario de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para mejorar la experiencia de escritura.&lt;br/&gt; &lt;br/&gt; La descarga puede tardar unos minutos en redes 3G. Es posible que se apliquen cargos si no tienes un &lt;b&gt;plan de datos ilimitado&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Consejo: Puedes descargar y eliminar diccionarios en la sección &lt;b&gt;Idioma e introducción de texto&lt;/b&gt; en el menú &lt;b&gt;Ajustes&lt;/b&gt; 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..c08d04576
--- /dev/null
+++ b/java/res/values-et-rEE/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-et-rEE/strings.xml
index e0f992c0d..26ab93e95 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> teeb automaatse paranduse"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Näitab klaviatuuri režiimil <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"aeg"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditsiooniline)"</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 +165,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 +208,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.&lt;br/&gt; Teksti mugavamaks sisestamiseks soovitame &lt;b&gt;alla laadida&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> keele sõnastiku.&lt;br/&gt; &lt;br/&gt; 3G kaudu allalaadimisele võib kuluda minut või paar. Kehtida võivad tasud, kui te ei kasuta &lt;b&gt;piiramatut andmepaketti&lt;/b&gt;.&lt;br/&gt; Kui te ei tea, millist andmepaketti kasutate, soovitame allalaadimise automaatseks käivitamiseks leida WiFi-ühenduse.&lt;br/&gt; &lt;br/&gt; Nõuanne: sõnastikke saate alla laadida ja eemaldada, tehes valiku &lt;b&gt;Keel ja sisestamine&lt;/b&gt; mobiilseadme menüüs &lt;b&gt;Seaded&lt;/b&gt;."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobiilseadmes valitud keelele on saadaval sõnastik.&lt;br/&gt; Teksti mugavamaks sisestamiseks soovitame <b>alla laadida</b> <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> keele sõnastiku.&lt;br/&gt; &lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Nõuanne: sõnastikke saate alla laadida ja eemaldada, tehes mobiilseadme menüüs <b>Seaded</b> valiku &lt;b&gt;Keel ja sisend&lt;/b&gt;."</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/config-spacing-and-punctuations.xml b/java/res/values-fa-sw600dp/config-spacing-and-punctuations.xml
new file mode 100644
index 000000000..56296361f
--- /dev/null
+++ b/java/res/values-fa-sw600dp/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" translatable="false">!,&#x061F;,:,&#x061B;,\",\',(|),)|(,-,/,@,_</string>
+</resources>
diff --git a/java/res/values-fa/donottranslate.xml b/java/res/values-fa/config-spacing-and-punctuations.xml
index 57de2538b..d33a104df 100644
--- a/java/res/values-fa/donottranslate.xml
+++ b/java/res/values-fa/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" translatable="false">!,&#x061F;,&#x060C;,:,&#x061B;,\",(|),)|(,\',-,/,@,_</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..b4e0335d7
--- /dev/null
+++ b/java/res/values-fa/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"یادگیری از ارتباطات و اطلاعات تایپ شده شما برای بهبود پیشنهادات"</string>
+</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index af886ef8c..1ea69cbd3 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,14 +74,15 @@
<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="gesture_space_aware" msgid="2078291600664682496">"‫ورود عبارت با حرکت اشاره‌ای"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"با سراندن انگشت به کلید فاصله در زمان اشاره‌ها، فاصله را وارد کنید"</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 name="spoken_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> تصحیح خودکار را انجام می‌دهد"</string>
<!-- String.format failed for translation -->
<!-- no translation found for spoken_description_unknown (3197434010402179157) -->
<skip />
@@ -110,7 +112,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"در حال نمایش صفحه‌کلید <xliff:g id="KEYBOARD_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>
@@ -121,12 +123,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"زمان"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"نشانی اینترنتی"</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 +136,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +169,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 +212,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">"‏برای زبان انتخاب شده در دستگاه همراه شما فرهنگ لغتی موجود است.&lt;br/&gt; توصیه می‌کنیم فرهنگ لغت <xliff:g id="LANGUAGE">%1$s</xliff:g> را &lt;b&gt;دانلود کنید&lt;/b&gt; تا بهتر تایپ کنید.&lt;br/&gt; &lt;br/&gt; دانلود از طریق 3G ممکن است چند لحظه طول بکشد. اگر &lt;b&gt;طرح داده نامحدود&lt;/b&gt; نداشته باشید ممکن است برایتان هزینه داشته باشد.&lt;br/&gt; اگر مطمئن نیستید طرح داده شما چیست٬ توصیه می‌کنیم یک اتصال Wi-Fi پیدا کنید تا دانلود بطور خودکار شروع شود.&lt;br/&gt; &lt;br/&gt; نکته: می‌توانید فرهنگ لغت را با رفتن به منوی &lt;b&gt;زبان و ورودی&lt;/b&gt; در &lt;b&gt;تنظیمات&lt;/b&gt; در دستگاه همراه خود دانلود و حذف کنید."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"‏برای زبان انتخاب شده در دستگاه همراه شما فرهنگ لغتی در دسترس است.&lt;br/&gt; توصیه می‌کنیم برای بهبود بخشیدن به تجربه تایپ کردنتان، فرهنگ لغت <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> را &lt;b&gt;دانلود کنید&lt;/b&gt;.‏&lt;br/&gt; &lt;br/&gt; دانلود از طریق 3G ممکن است یک یا دو دقیقه طول بکشد. اگر &lt;b&gt;طرح داده نامحدود&lt;/b&gt; نداشته باشید، ممکن است هزینه‌هایی برای شما اعمال شوند.&lt;br/&gt; اگر مطمئن نیستید چه طرح داده‌ای دارید٬ توصیه می‌کنیم یک اتصال Wi-Fi بیابید تا دانلود به طور خودکار شروع شود.&lt;br/&gt; &lt;br/&gt; نکته: با رفتن به بخش &lt;b&gt;زبان و ورودی&lt;/b&gt; در منوی &lt;b&gt;تنظیمات&lt;/b&gt; دستگاهتان، فرهنگ‌های لغت را دانلود یا حذف کنید."</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..2646501d5
--- /dev/null
+++ b/java/res/values-fi/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-fi/strings.xml
index a58bfac3e..bfa5d01a9 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Näytetään näppäimistö <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"aika"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL-osoite"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (perinteinen)"</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 +165,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 +208,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.&lt;br/&gt; Suosittelemme <xliff:g id="LANGUAGE">%1$s</xliff:g>-sanakirjan &lt;b&gt;lataamista&lt;/b&gt;, sillä se helpottaa laitteella kirjoittamista.&lt;br/&gt; &lt;br/&gt; Lataus kestää useimmiten muutaman minuutin 3G-yhteydellä. Latauksesta saatetaan periä maksu, ellei käytössäsi ole &lt;b&gt;rajoittamatonta tiedonsiirtopakettia&lt;/b&gt;.&lt;br/&gt; Jos et ole varma tiedonsiirtosopimuksesi tyypistä, etsi käyttöösi wifi-yhteys, niin lataus alkaa automaattisesti.&lt;br/&gt; &lt;br/&gt; Vinkki: voit ladata ja poistaa sanakirjoja mobiililaitteesi &lt;b&gt;Asetukset&lt;/b&gt;-valikon &lt;b&gt;Kieli ja syöttötapa&lt;/b&gt; -osiossa."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Laitteesi käyttökielelle on saatavilla sanakirja.&lt;br/&gt; Suosittelemme <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>-sanakirjan &lt;b&gt;lataamista&lt;/b&gt;, sillä se helpottaa laitteella kirjoittamista.&lt;br/&gt; &lt;br/&gt; Lataus kestää useimmiten muutaman minuutin 3G-yhteydellä. Latauksesta saatetaan periä maksu, ellei käytössäsi ole &lt;b&gt;rajoittamatonta tiedonsiirtopakettia&lt;/b&gt;.&lt;br/&gt; Jos et ole varma tiedonsiirtosopimuksesi tyypistä, etsi käyttöösi wifi-yhteys, niin lataus alkaa automaattisesti.&lt;br/&gt; &lt;br/&gt; Vinkki: voit ladata ja poistaa sanakirjoja mobiililaitteesi &lt;b&gt;Asetukset&lt;/b&gt;-valikon &lt;b&gt;Kieli ja syöttötapa&lt;/b&gt; -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/config-spacing-and-punctuations.xml
index 21f18d852..ff9144920 100644
--- a/java/res/values-fr-rCA/donottranslate.xml
+++ b/java/res/values-fr-rCA/config-spacing-and-punctuations.xml
@@ -20,12 +20,12 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
<!-- This is similar to French with the exception of "!" "?" and ";" which do not take a space before in Canadian French. Note that ":" does take a space before according to Canadian rules. -->
- <string name="symbols_preceded_by_space">([{&amp;:</string>
+ <string name="symbols_preceded_by_space" translatable="false">([{&amp;:</string>
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
- <string name="symbols_followed_by_space">.,;:!?)]}&amp;</string>
+ <string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
<!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
- <string name="symbols_word_connectors">\'-</string>
+ <string name="symbols_word_connectors" translatable="false">\'-</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..05b452c51
--- /dev/null
+++ b/java/res/values-fr-rCA/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-fr-rCA/strings.xml
index 2551ce9f8..dcb1119c2 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet d\'effectuer une 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Affichage du clavier <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionnel)"</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 +165,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">"Vider le 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 +208,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.&lt;br/&gt; Nous vous invitons à &lt;b&gt;télécharger&lt;/b&gt; le dictionnaire <xliff:g id="LANGUAGE">%1$s</xliff:g> pour faciliter votre saisie.&lt;br/&gt; &lt;br/&gt; 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 &lt;b&gt;forfait Internet illimité&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section &lt;b&gt;Langue et saisie&lt;/b&gt; du menu &lt;b&gt;Paramètres&lt;/b&gt; 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.&lt;br/&gt; Nous vous invitons à &lt;b&gt;télécharger&lt;/b&gt; le dictionnaire pour la langue <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> pour faciliter votre réaction de texte.&lt;br/&gt; &lt;br/&gt; Le téléchargement peut prendre une à deux minutes par connexion 3G. Des frais peuvent s\'appliquer si vous ne disposez pas d\'un &lt;b&gt;forfait Internet illimité&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section &lt;b&gt;Langue et entrée&lt;/b&gt; du menu &lt;b&gt;Paramètres&lt;/b&gt; 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/config-spacing-and-punctuations.xml
index f0644118a..d09b0c011 100644
--- a/java/res/values-fr/donottranslate.xml
+++ b/java/res/values-fr/config-spacing-and-punctuations.xml
@@ -19,12 +19,12 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
- <string name="symbols_preceded_by_space">([{&amp;;:!?</string>
+ <string name="symbols_preceded_by_space" translatable="false">([{&amp;;:!?</string>
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
- <string name="symbols_followed_by_space">.,;:!?)]}&amp;</string>
+ <string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
<!-- Symbols that separate words -->
<!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
- <string name="symbols_word_connectors">\'-</string>
+ <string name="symbols_word_connectors" translatable="false">\'-</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..21000de07
--- /dev/null
+++ b/java/res/values-fr/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-fr/strings.xml
index b877db014..3cd6e2696 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"La touche <xliff:g id="KEY_NAME">%1$s</xliff:g> permet d\'effectuer une 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Affichage du clavier <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionnel)"</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 +165,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">"Supprimer dictionnaire des contacts"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Supprimer le dictionnaire personnel"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Supprimer l\'ancien dictionnaire"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Suppr. 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 +208,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.&lt;br/&gt; Nous vous invitons à &lt;b&gt;télécharger&lt;/b&gt; le dictionnaire <xliff:g id="LANGUAGE">%1$s</xliff:g> pour faciliter votre saisie.&lt;br/&gt; &lt;br/&gt; 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 &lt;b&gt;forfait Internet illimité&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Astuce : Vous pouvez télécharger et supprimer des dictionnaires dans la section &lt;b&gt;Langue et saisie&lt;/b&gt; du menu &lt;b&gt;Paramètres&lt;/b&gt; 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.&lt;br/&gt; Nous vous invitons à &lt;b&gt;télécharger&lt;/b&gt; le dictionnaire pour cette langue : <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Cela facilitera votre saisie.&lt;br/&gt; &lt;br/&gt; Le téléchargement peut prendre une à deux minutes via une connexion 3G. Des frais peuvent s\'appliquer si vous n\'avez pas un &lt;b&gt;forfait Internet illimité&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Astuce : Vous pouvez télécharger et supprimer des dictionnaires sous &lt;b&gt;Langue et saisie&lt;/b&gt;, dans le menu &lt;b&gt;Paramètres&lt;/b&gt; 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..9a1c12b39
--- /dev/null
+++ b/java/res/values-hi/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"सुझावों में सुधार हेतु अपने संचार और लिखे गए डेटा से जानकारी पाएं"</string>
+</resources>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index d7735433d..04879863f 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"वाक्यांश जेस्चर"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"स्पेस कुंजी तक ग्लाइड करके जेस्चर के दौरान रिक्तियां इनपुट करें"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"आपके मोबाइल उपकरण पर चयनित भाषा में डिक्‍शनरी उपलब्‍ध है.&lt;br/&gt; आपके लेखन अनुभव को बेहतर बनाने के लिए हम <xliff:g id="LANGUAGE">%1$s</xliff:g> डिक्‍शनरी को &lt;b&gt;डाउनलोड करने&lt;/b&gt; की अनुशंसा करते हैं.&lt;br/&gt; &lt;br/&gt; 3G पर डाउनलोड होने में एक या दो मिनट लग सकते हैं. यदि आपके पास &lt;b&gt;असीमित डेटा प्लान&lt;/b&gt; नहीं है, तो शुल्‍क लग सकते हैं.&lt;br/&gt; यदि आप अपने डेटा प्लान के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए Wi-Fi कनेक्‍शन ढूंढने की अनुशंसा करते हैं.&lt;br/&gt; &lt;br/&gt; युक्ति: आप अपने मोबाइल उपकरण पर &lt;b&gt;सेटिंग&lt;/b&gt; मेनू में &lt;b&gt;भाषा और अक्षर&lt;/b&gt; पर जाकर डिक्‍शनरी डाउनलोड कर सकते हैं और निकाल सकते हैं."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"आपके मोबाइल पर चयनित भाषा के लिए शब्‍दकोश उपलब्‍ध है.&lt;br/&gt; हम आपके लेखन अनुभव को बेहतर बनाने के लिए <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> शब्‍दकोश &lt;b&gt;डाउनलोड करने&lt;/b&gt; की अनुशंसा करते हैं.&lt;br/&gt; &lt;br/&gt; 3G में डाउनलोड करने पर एक या दो मिनट लगेंगे. यदि आपके पास &lt;b&gt;असीमित डेटा योजना&lt;/b&gt; नहीं है, तो शुल्क लागू हो सकते हैं.&lt;br/&gt; यदि आप अपनी डेटा योजना के बारे में सुनिश्चित नहीं हैं, तो हम अपने आप डाउनलोड प्रारंभ करने के लिए Wi-Fi कनेक्‍शन ढूंढने की अनुशंसा करते हैं.&lt;br/&gt; &lt;br/&gt; युक्ति: आप अपने मोबाइल उपकरण के &lt;b&gt;सेटिंग&lt;/b&gt; मेनू में &lt;b&gt;भाषा और इनपुट&lt;/b&gt; पर जाकर शब्‍दकोशों को डाउनलोड कर सकते हैं और निकाल सकते हैं."</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..c93544ed3
--- /dev/null
+++ b/java/res/values-hr/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-hr/strings.xml
index b9cfef384..eb1391fe6 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Prikaz tipkovnice: <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"vrijeme"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionalna)"</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 +165,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">"Kopiranje 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 +208,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.&lt;br/&gt; Preporučujemo &lt;b&gt;preuzimanje&lt;/b&gt; rječnika za <xliff:g id="LANGUAGE">%1$s</xliff:g> radi boljeg doživljaja unosa teksta.&lt;br/&gt; &lt;br/&gt; Na 3G mreži preuzimanje može potrajati minutu ili dvije. Može podlijegati naplati ako nemate &lt;b&gt;neograničenu podatkovnu tarifu&lt;/b&gt;.&lt;br/&gt; Ako niste sigurni koju tarifu imate, preporučujemo da pronađete Wi-Fi mrežu i pokrenete automatsko preuzimanje.&lt;br/&gt; &lt;br/&gt; Savjet: rječnike možete preuzeti i ukloniti u odjeljku &lt;b&gt;Jezik i unos&lt;/b&gt; na izborniku &lt;b&gt;Postavke&lt;/b&gt; 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.&lt;br/&gt; Preporučujemo da &lt;b&gt;preuzmete&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> rječnik radi lakšeg unosa teksta.&lt;br/&gt; &lt;br/&gt; Preuzimanje može potrajati jednu do dvije minute putem 3G-a. Možda se naplaćuje dodatna naknada ako nemate &lt;b&gt;neograničenu podatkovnu tarifu&lt;/b&gt;.&lt;br/&gt; Ako niste sigurni koju tarifu imate, preporučujemo da pronađete Wi-Fi vezu kako bi se automatski pokrenulo preuzimanje.&lt;br/&gt; &lt;br/&gt; Savjet: rječnike možete preuzeti i ukloniti u odjeljku &lt;b&gt;Jezik i unos&lt;/b&gt; u izborniku &lt;b&gt;Postavke&lt;/b&gt; 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..b35c9f06c
--- /dev/null
+++ b/java/res/values-hu/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-hu/strings.xml
index a61378fca..d4fffecf4 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"idő"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (hagyományos)"</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 +165,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évjegyszótár törlése"</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 +208,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.&lt;br/&gt; A gépelési élmény javításához javasoljuk a(z) <xliff:g id="LANGUAGE">%1$s</xliff:g> szótár &lt;b&gt;letöltését.&lt;br/&gt; &lt;br/&gt; A letöltés 3G hálózaton keresztül néhány percig tart. Ha &lt;b&gt;előfizetése nem korlátlan&lt;/b&gt;, a letöltés költségekkel járhat.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tipp: a szótárakat a mobileszköz &lt;b&gt;Beállítások&lt;/b&gt; menüjében a &lt;b&gt;Nyelv és bevitel&lt;/b&gt; 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.&lt;br/&gt; 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 &lt;b&gt;letöltését.&lt;br/&gt; &lt;br/&gt; A letöltés 3G hálózaton keresztül néhány percig tart. Ha &lt;b&gt;előfizetése nem korlátlan&lt;/b&gt;, a letöltés költségekkel járhat.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tipp: szótárakat a mobileszköz a &lt;b&gt;Beállítások&lt;/b&gt; menü &lt;b&gt;Nyelv és bevitel&lt;/b&gt; 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/config-spacing-and-punctuations.xml
index 7b0c56655..792762dd7 100644
--- a/java/res/values-hy-rAM/donottranslate.xml
+++ b/java/res/values-hy-rAM/config-spacing-and-punctuations.xml
@@ -22,11 +22,11 @@
<!-- U+055D: "՝" ARMENIAN COMMA -->
<!-- U+0589: "։" ARMENIAN FULL STOP -->
<!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
- <string name="symbols_followed_by_space">.,;:!?)]}&amp;&#x0589;&#x055D;</string>
+ <string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;&#x0589;&#x055D;</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">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"&#x0589;&#x055D;</string>
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"&#x0589;&#x055D;</string>
<!-- The sentence separator code point, for capitalization -->
<!-- U+0589: "։" ARMENIAN FULL STOP ; 589h = 1417d -->
- <integer name="sentence_separator">1417</integer>
+ <integer name="sentence_separator" translatable="false">1417</integer>
</resources>
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..0d1588e13
--- /dev/null
+++ b/java/res/values-hy-rAM/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Բարելավեք առաջարկները` ձեր նամակագրությունից և մուտքագրած տվյալներից"</string>
+</resources>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
index 0b8e19a76..f24ea45d8 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Բառակապակցային ժեստ"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Ներմուծեք բացատներ ժեստերի ընթացքում՝ սահելով բացատ ստեղնի վրայով"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Ցուցադրվում է <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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/> Խորհուրդ ենք տալիս &lt;b&gt;ներբեռնել&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> բառարանը ձեր մուտքագրման հմտությունների բարելավման համար:&lt;br/&gt; &lt;br/&gt; Ներբեռնումը կարող է խլել մեկ կամ երկու րոպե 3G-ի դեպքում: Հնարավոր է գանձում կատարվի, եթե դուք չունեք &lt;b&gt;տվյալների անսահմանափակ փաթեթ&lt;/b&gt;.&lt;br/&gt; Եթե դուք վստահ չեք, թե տվյալների որ փաթեթն ունեք, խորհուրդ ենք տալիս գտնել Wi-Fi կապ՝ ներբեռնումն ավտոմատ սկսելու համար:&lt;br/&gt; &lt;br/&gt; Հուշում. դուք կարող եք ներբեռնել և հեռացնել բառարաններ՝ գնալով ձեր բջջային սարքի &lt;b&gt;Կարգավորումներ ցանկի Լեզու &amp; մուտքագրման&lt;/b&gt; բաժինը:"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Ձեր բջջային սարքում ընտրված լեզվով առկա է բառարան:<br/> Խորհուրդ ենք տալիս &lt;b&gt;ներբեռնել&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> բառարանը՝ ձեր մուտքագրման հմտությունների բարելավման համար:&lt;br/&gt; &lt;br/&gt; Ներբեռնումը կարող է խլել մեկ կամ երկու րոպե 3G-ի դեպքում: Հնարավոր է գանձում կատարվի, եթե դուք չունեք &lt;b&gt;տվյալների անսահմանափակ փաթեթ&lt;/b&gt;.&lt;br/&gt; Եթե դուք վստահ չեք, թե տվյալների որ փաթեթն ունեք, խորհուրդ ենք տալիս գտնել Wi-Fi կապ՝ ներբեռնումն ավտոմատ սկսելու համար:&lt;br/&gt; &lt;br/&gt; Հուշում. դուք կարող եք ներբեռնել և հեռացնել բառարաններ՝ անցնելով ձեր բջջային սարքի &lt;b&gt;Կարգավորումներ ցանկի Լեզու և մուտքագրում&lt;/b&gt; բաժինը:"</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..c1950c41a
--- /dev/null
+++ b/java/res/values-in/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Belajar dari komunikasi &amp; data terketik untuk meningkatkan saran"</string>
+</resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index d83a22c6c..b7907929e 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Menampilkan keyboard <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"waktu"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 &amp; 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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisional)"</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 +165,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">"Kosongkan kamus kontak"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Kosongkan kamus pribadi"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Kosongkan kamus riwayat pengguna"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Kosongkan kamus hasil 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>
@@ -207,18 +208,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.&lt;br/&gt; Silakan &lt;b&gt;mengunduh&lt;/b&gt; kamus <xliff:g id="LANGUAGE">%1$s</xliff:g> untuk meningkatkan pengalaman pengetikan.&lt;br/&gt; &lt;br/&gt; Unduhan dapat berlangsung selama satu atau dua menit melalui 3G. Mungkin dikenakan tagihan data jika Anda tidak memiliki &lt;b&gt;paket data tak terbatas&lt;/b&gt;.&lt;br/&gt; Jika tidak yakin paket data mana yang Anda miliki, sebaiknya Anda mencari sambungan Wi-Fi untuk memulai unduhan secara otomatis.&lt;br/&gt; &lt;br/&gt; Kiat: Anda dapat mengunduh atau menghapus kamus dengan membuka &lt;b&gt;Bahasa &amp; masukan&lt;/b&gt; di menu &lt;b&gt;Setelan&lt;/b&gt; perangkat seluler Anda."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Tersedia kamus untuk bahasa pilihan pada perangkat seluler Anda.&lt;br/&gt; Sebaiknya &lt;b&gt;unduh&lt;/b&gt; kamus <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> untuk meningkatkan pengalaman pengetikan.&lt;br/&gt; &lt;br/&gt; Unduhan dapat berlangsung selama satu atau dua menit melalui 3G. Mungkin dikenakan biaya data jika tidak memiliki &lt;b&gt;paket data tak terbatas&lt;/b&gt;.&lt;br/&gt; Jika tidak yakin dengan jenis paket data Anda, sebaiknya cari koneksi Wi-Fi untuk memulai unduhan secara otomatis.&lt;br/&gt; &lt;br/&gt; Kiat: Anda dapat mengunduh dan menghapus kamus dengan membuka &lt;b&gt;Bahasa &amp; masukan&lt;/b&gt; di menu &lt;b&gt;Setelan&lt;/b&gt; 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.xml b/java/res/values-is/strings.xml
index 6f685d395..1137fd09d 100644
--- a/java/res/values-is/strings.xml
+++ b/java/res/values-is/strings.xml
@@ -214,18 +214,6 @@
<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..deff79f89
--- /dev/null
+++ b/java/res/values-it/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-it/strings.xml
index 1111c4901..a9728f1de 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> esegue la 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Ecco la tastiera <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"ora"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradizionale)"</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 +165,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">"Scarica dizionario contatti"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Scarica dizionario personale"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Scarica dizion. cronologia utente"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Scarica 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 +208,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.&lt;br/&gt; Ti consigliamo di &lt;b&gt;scaricare&lt;/b&gt; il dizionario in <xliff:g id="LANGUAGE">%1$s</xliff:g> per migliorare l\'esperienza di digitazione.&lt;br/&gt; &lt;br/&gt; Il download potrebbe richiedere un paio di minuti su 3G. Potrebbero essere applicati costi se non disponi di un &lt;b&gt;piano dati illimitato&lt;/b&gt;.&lt;br/&gt; Se non sei sicuro di quale sia il tuo piano dati, dovresti trovare una connessione Wi-Fi per avviare il download automaticamente.&lt;br/&gt; &lt;br/&gt; Suggerimento. Puoi scaricare e rimuovere dizionari passando a &lt;b&gt;Lingue e immissione&lt;/b&gt; nel menu &lt;b&gt;Impostazioni&lt;/b&gt; del dispositivo mobile."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Per la lingua selezionata sul dispositivo mobile è disponibile un dizionario.&lt;br/&gt; Ti consigliamo di &lt;b&gt;scaricare&lt;/b&gt; il dizionario in <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> per migliorare la digitazione.&lt;br/&gt; &lt;br/&gt; Il download potrebbe richiedere un paio di minuti su 3G. Potrebbero essere applicati costi se non disponi di un &lt;b&gt;piano dati illimitato&lt;/b&gt;.&lt;br/&gt; Se non sei sicuro di quale sia il tuo piano dati, dovresti trovare una connessione Wi-Fi per avviare il download automaticamente.&lt;br/&gt; &lt;br/&gt; Suggerimento. Puoi scaricare e rimuovere dizionari selezionando &lt;b&gt;Lingua e immissione&lt;/b&gt; nel menu &lt;b&gt;Impostazioni&lt;/b&gt; 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-iw/strings-config-important-notice.xml b/java/res/values-iw/strings-config-important-notice.xml
new file mode 100644
index 000000000..c7f352968
--- /dev/null
+++ b/java/res/values-iw/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"למד מהתכתבויות ומנתונים שהקלדת כדי לשפר את ההצעות"</string>
+</resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 8d02e685b..870623f93 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"הקלדת משפט בהחלקה"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"הזן רווחים במהלך התנועה על ידי החלקה אל מקש הרווח"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"מציג מקלדת <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"זמן"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"כתובות אתרים"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"‏לשפה הנבחרת במכשיר הנייד שלך יש מילון זמין.&lt;br/&gt; אנו ממליצים &lt;b&gt;להוריד&lt;/b&gt; את המילון ב<xliff:g id="LANGUAGE">%1$s</xliff:g> כדי לשפר את חוויית ההקלדה.&lt;br/&gt; &lt;br/&gt; ההורדה עשויה לארוך דקה או שתיים ב-3G. ייתכן שתחויב אם אין לך &lt;b&gt;תכנית נתונים בלתי מוגבלת&lt;/b&gt;.&lt;br/&gt; אם אינך בטוח איזו תכנית נתונים יש לך, אנו ממליצים לחפש חיבור Wi-Fi כדי להתחיל בהורדה באופן אוטומטי.&lt;br/&gt; &lt;br/&gt; טיפ: ניתן להוריד ולהסיר מילונים ב&lt;b&gt;שפה וקלט&lt;/b&gt; בתפריט &lt;b&gt;הגדרות&lt;/b&gt; של המכשיר הנייד שלך."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"‏יש מילון זמין עבור השפה הנבחרת במכשיר הנייד שלך.&lt;br/&gt; אנחנו ממליצים &lt;b&gt;להוריד&lt;/b&gt; את המילון ב<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> לשיפור חוויית ההקלדה.&lt;br/&gt; &lt;br/&gt; ייתכן שההורדה תארך דקה או שתיים ברשת דור שלישי. ייתכנו חיובים אם אין לך &lt;b&gt;תכנית נתונים ללא הגבלה&lt;/b&gt;.&lt;br/&gt; אם אינך בטוח איזו תכנית נתונים יש לך, אנחנו ממליצים למצוא חיבור Wi-Fi כדי להתחיל את ההורדה באופן אוטומטי.&lt;br/&gt; &lt;br/&gt; טיפ: ניתן להוריד ולהסיר מילונים על ידי מעבר אל &lt;b&gt;שפה וקלט&lt;/b&gt; בתפריט &lt;b&gt;הגדרות&lt;/b&gt; של המכשיר הנייד."</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..937ddae5c
--- /dev/null
+++ b/java/res/values-ja/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"メッセージなどのやり取りや入力したデータから入力候補を予測します"</string>
+</resources>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index fbfd3b7f7..add4449a4 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"フレーズジェスチャー"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Spaceキーに指を滑らせると、ジェスチャー中にスペースを入力できます"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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">"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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"お使いの携帯端末で選択した言語に対応する辞書があります。&lt;br/&gt;入力機能をより快適にご利用いただくため、<xliff:g id="LANGUAGE">%1$s</xliff:g>の辞書の&lt;b&gt;ダウンロード&lt;/b&gt;をおすすめします。&lt;br/&gt; &lt;br/&gt;3G経由の場合、ダウンロードに要する時間は1~2分です。&lt;b&gt;定額制のデータプラン&lt;/b&gt;をご利用でない場合は通信料が発生する可能性があります。&lt;br/&gt;ご利用のデータプランが不明な場合は、自動的にダウンロードが開始されるWi-Fi接続を探すことをおすすめします。&lt;br/&gt; &lt;br/&gt;ヒント: 辞書のダウンロードや削除は、お使いの携帯端末の[&lt;b&gt;設定&lt;/b&gt;]メニューの[&lt;b&gt;言語と入力&lt;/b&gt;]で行えます。"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"お使いの携帯端末で選択した言語に対応する辞書があります。&lt;br/&gt;入力機能をより快適にご利用いただくため、<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>の辞書の&lt;b&gt;ダウンロード&lt;/b&gt;をおすすめします。&lt;br/&gt; &lt;br/&gt;3G経由の場合、ダウンロードに要する時間は1~2分です。&lt;b&gt;定額制のデータプラン&lt;/b&gt;をご利用でない場合は通信料が発生する可能性があります。&lt;br/&gt;ご利用のデータプランが不明な場合は、自動的にダウンロードが開始されるWi-Fi接続を探すことをおすすめします。&lt;br/&gt; &lt;br/&gt;ヒント: 辞書のダウンロードや削除は、お使いの携帯端末の[&lt;b&gt;設定&lt;/b&gt;]メニューの[&lt;b&gt;言語と入力&lt;/b&gt;]で行えます。"</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..e43ca01b1
--- /dev/null
+++ b/java/res/values-ka-rGE/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"უკეთესი შეთავაზებისთვის თქვენი კომუნიკაციიდან და ტექსტიდან სწავლა"</string>
+</resources>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
index dec6b3a6b..056bc355e 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"ფრაზის ჟესტი"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"შეიყვანეთ შორისები ჟესტიკულაციისას შორისის კლავიშზე გასრიალებით"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"ნაჩვენებია <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="voice_input_disabled_summary" msgid="8141750303464726129">"ხმოვანი შეყვანის მეთოდები ჩართული არ არის. შეამოწმეთ ენის &amp; შეყვანის პარამეტრები."</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"თქვენ მიერ მობილურ მოწყობილობაზე არჩეული ენისათვის ხელმისაწვდომია ლექსიკონი.&lt;br/&gt; გირჩევთ, &lt;b&gt;ჩამოტვირთოთ&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> ლექსიკონი, რათა გაიმარტივოთ ტექსტის შეყვანა.&lt;br/&gt; &lt;br/&gt; ჩამოტვირთვას შესაძლოა დაჭირდეს ერთი ან ორი წუთი 3G სისწრაფეზე. თუ ულიმიტო არ გაქვთ &lt;b&gt; მობილური ინტერნეტის ტარიფი&lt;/b&gt;.&lt;br/&amp;gt, შესაძლოა ჩამოტვირთვა დამატებით გადასახადებთან იყოს დაკავშირებული; თუ არ ხართ დარწმუნებული მობილური ინტერნეტის აქტიური ტარიფის შესახებ, გირჩევთ იპოვოთ Wi-Fi კავშირი და ავტომატურად დაიწყოთ ჩამოტვირთვა.&lt;br/&gt; &lt;br/&gt; რჩევა: ლექსიკონების ჩამოტვირთვა და ამოშლა შესაძლებელია სექციიდან &lt;b&gt;ენა და შეყვანა&lt;/b&gt; სექციიდან, თქვენი მობილური მოწყობილობის &lt;b&gt;პარამეტრების&lt;/b&gt; მენიუში."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"თქვენ მიერ მობილურ მოწყობილობაზე არჩეული ენისთვის ხელმისაწვდომია ლექსიკონი.&lt;br/&gt; გირჩევთ, &lt;b&gt;ჩამოტვირთოთ&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ლექსიკონი, რათა გაიმარტივოთ ტექსტის შეყვანა.&lt;br/&gt; &lt;br/&gt; ჩამოტვირთვას შესაძლოა დასჭირდეს ერთი ან ორი წუთი 3G სისწრაფეზე. თუ &lt;b&gt; მობილური ინტერნეტის ტარიფი&lt;/b&gt;.&lt;br/&amp;gt ულიმიტო არ გაქვთ, შესაძლოა გადახდა მოგიწიოთ; თუ არ ხართ დარწმუნებული მობილური ინტერნეტის აქტიური ტარიფის შესახებ, გირჩევთ, იპოვოთ Wi-Fi კავშირი და ავტომატურად დაიწყოთ ჩამოტვირთვა.&lt;br/&gt; &lt;br/&gt; რჩევა: ლექსიკონების ჩამოტვირთვა და ამოშლა შეიძლება სექციიდან &lt;b&gt;ენა და შეყვანა&lt;/b&gt; თქვენი მობილური მოწყობილობის &lt;b&gt;პარამეტრების&lt;/b&gt; მენიუში."</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.xml b/java/res/values-kk/strings.xml
index 947ff2fe9..d39c2d4d2 100644
--- a/java/res/values-kk/strings.xml
+++ b/java/res/values-kk/strings.xml
@@ -73,6 +73,8 @@
<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="8244483979855138643">"Фраза қимылы"</string>
+ <string name="gesture_space_aware_summary" msgid="3226298212755100667">"Бос орын пернесін жанау арқылы қимылдар барысында бос орындарды енгізу"</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>
@@ -119,12 +121,6 @@
<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">"Негізгі пернетақтадағы 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/config-spacing-and-punctuations.xml
index a9893feec..a9893feec 100644
--- a/java/res/values-km-rKH/donottranslate.xml
+++ b/java/res/values-km-rKH/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..ad0325adb
--- /dev/null
+++ b/java/res/values-km-rKH/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"សិក្សាការភ្ជាប់របស់អ្នកនិងទិន្នន័យ​ដែលបានបញ្ចូលដើម្បីធ្វើសំណើ​ឲ្យល្អ"</string>
+</resources>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index 86ecc5e10..71242b6aa 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"កាយវិការ​​ឃ្លា"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"បញ្ចូល​​ដកឃ្លា​​​អំឡុង​​​កាយវិការ​ ដោយ​រំកិល​ទៅ​គ្រាប់​ចុច​ដកឃ្លា"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"បង្ហាញ​ក្ដារ​ចុច <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="voice_input_disabled_summary" msgid="8141750303464726129">"គ្មាន​វិធីសាស្ត្រ​បញ្ចូល​សំឡេង​បាន​បើក។ ពិនិត្យ​មើល​ការ​កំណត់​ភាសា &amp; ការ​បញ្ចូល។"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"ភាសា​ដែល​បាន​ជ្រើស​នៅ​លើ​ឧបករណ៍​របស់​អ្នក​មាន​វចនានុក្រម។ &lt;br/&gt; យើង​បាន​ផ្ដល់​អនុសាសន៍ &lt;b&gt;ទាញ​យក​&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> វចនានុក្រម ដើម្បី​ធ្វើ​ឲ្យ​ការ​វាយ​បញ្ចូល​របស់​អ្នក​ប្រសើរ​ឡើង។ &lt;br/&gt; &lt;br/&gt; ការ​ទាញ​យក​អាច​ចំណាយ​ពេល​​មួយ ឬ​ពីរ​នាទី​​​តាម 3G ។ ការ​​កាត់​លុយ​អាច​អនុវត្ត​ ប្រសិន​​​បើ​អ្នក​​បាន​​ &lt;b&gt;កំណត់​ទិន្នន័យ​គ្មាន​ដែន​កំណត់ &lt;/b&gt;.&lt;br/&gt; ប្រសិនបើ​​អ្នក​មិន​ប្រាកដ​​ថា​ទិន្នន័យ​អ្នក​​មិន​បាន​​កំណត់ យើង​បាន​ផ្ដល់​អនុសាសន៍​ដោយ​ស្វែងរក​ការ​ភ្ជាប់​​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យប្រវត្តិ។&lt;br/&gt; &lt;br/&gt; ព័ត៌មាន​ជំនួយ៖ អ្នក​អាច​ទាញ​យក និង​លុប​​វចនានុក្រម​​ដោយ​ចូល​ទៅ​ &lt;b&gt;ភាសា&amp; បញ្ចូល&lt;/b&gt;​នៅ​ក្នុង​ម៉ឺនុយ &lt;b&gt;ការ​កំណត់ &lt;/b&gt; របស់​ឧបករណ៍​ចល័ត។"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសា​ដែល​បាន​ជ្រើស​នៅ​លើ​ឧបករណ៍​ចល័ត​មាន​វចនានុក្រម​អាច​ប្រើ​បាន។&lt;br/&gt; យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ &lt;b&gt;ទាញ​យក&lt;/b&gt; វចនានុក្រម​ភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បី​បង្កើន​បទពិសោធន៍​វាយ​បញ្ចូល​របស់​អ្នក។&lt;br/&gt; &lt;br/&gt; ការ​ទាញ​យក​អាច​ចំណាយ​ពេល​ប្រហែល​ពីរ​នាទី​នៅ​តាម 3G។ ការ​គិត​ថ្លៃ​អាច​អនុវត្ត​ប្រសិន​បើ​អ្នក​មិន​ប្រើ &lt;b&gt;ផែនការ​ទិន្នន័យ​គ្មាន​ដែន​កំណត់&lt;/b&gt;.&lt;br/&gt; បើ​អ្នក​មិន​ប្រាកដ​​ថា​ផែនការ​ណា​មួយ​ដែល​អ្នក​មាន យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ​​ភ្ជាប់​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យ​ប្រវត្តិ។&lt;br/&gt; &lt;br/&gt; ជំនួយ៖ អ្នក​អាច​ទាញ​យក និង​លុប​វចនានុក្រម​ដោយ​ចូល​ទៅ​ &lt;b&gt;ភាសា &amp; ការ​បញ្ចូល&lt;/b&gt; នៅ​ក្នុង​ម៉ឺនុយ &lt;b&gt;ការ​កំណត់&lt;/b&gt; សម្រាប់​ឧបករណ៍​ចល័ត។"</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..2ea6e49f4
--- /dev/null
+++ b/java/res/values-ko/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"사용자의 대화 내용과 입력한 데이터를 통해 단어 추천의 정확도를 개선합니다."</string>
+</resources>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index ca10bdf52..5d21d2a81 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"구문 동작"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"동작 중에 스페이스바 쪽으로 움직여 공백 입력"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"기기에서 선택한 언어로 사용할 수 있는 사전이 있습니다.&lt;br/&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> 사전을 &lt;b&gt;다운로드&lt;/b&gt;하여 입력 환경을 개선해 보세요..&lt;br/&gt; &lt;br/&gt; 3G로 다운로드하는 경우 1-2분 정도 걸립니다. &lt;b&gt;무제한 데이터 요금제&lt;/b&gt;가 아닌 경우 요금이 청구됩니다.&lt;br/&gt; 사용 중인 데이터 요금제를 잘 모르는 경우 Wi-Fi에 연결할 수 있는 곳을 찾아 자동 다운로드를 시작하는 것이 좋습니다.&lt;br/&gt; &lt;br/&gt; 도움말: 사전을 다운로드하거나 삭제하려면 &lt;b&gt;언어 및 키보드&lt;/b&gt;로 이동하면 되며 이는 휴대기기의 &lt;b&gt;설정&lt;/b&gt; 메뉴에 있습니다."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"휴대기기에서 선택한 언어로 사용할 수 있는 사전이 있습니다.&lt;br/&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> 사전을 &lt;b&gt;다운로드&lt;/b&gt;하여 입력 환경을 개선해 보세요.&lt;br/&gt; &lt;br/&gt; 3G로 다운로드하는 경우 1~2분 정도 걸립니다. &lt;b&gt;무제한 데이터 요금제&lt;/b&gt;가 아닌 경우 요금이 청구될 수 있습니다.&lt;br/&gt; 사용 중인 데이터 요금제를 잘 모르는 경우 Wi-Fi에 연결할 수 있는 곳을 찾아 자동 다운로드를 시작하는 것이 좋습니다.&lt;br/&gt; &lt;br/&gt; 도움말: 사전을 다운로드하거나 삭제하려면 휴대기기의 &lt;b&gt;설정&lt;/b&gt; 메뉴에 있는 &lt;b&gt;언어 및 입력&lt;/b&gt;으로 이동하면 됩니다."</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.xml b/java/res/values-ky/strings.xml
index e30c4b965..c3aab7858 100644
--- a/java/res/values-ky/strings.xml
+++ b/java/res/values-ky/strings.xml
@@ -168,18 +168,6 @@
<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..ade7d002c 100644
--- a/java/res/values-land/config.xml
+++ b/java/res/values-land/config.xml
@@ -18,6 +18,67 @@
*/
-->
+<!-- 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_gb">1.818%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">5.941%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">0.997%p</fraction>
+ <!-- config_more_keys_keyboard_key_height x -1.0 -->
+ <dimen name="config_more_keys_keyboard_vertical_correction_gb">-44.8dp</dimen>
+ <dimen name="config_key_preview_offset_gb">0.0dp</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/config-spacing-and-punctuations.xml
index a9893feec..a9893feec 100644
--- a/java/res/values-lo-rLA/donottranslate.xml
+++ b/java/res/values-lo-rLA/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..d4e5052bd
--- /dev/null
+++ b/java/res/values-lo-rLA/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"ຮຽນຮູ້ຈາກການສື່ສານ ແລະຂໍ້ມູນທີ່ທ່ານເຄີຍພິມເພື່ອປັບປຸງຄຳແນະນຳ"</string>
+</resources>
diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml
index a4dbc2de2..9f28cd1bb 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"ການສະແດງທ່າທາງດ້ວຍປະໂຫຍກ"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ໃສ່ຍະຫວ່າງເຂົ້າໄປໃນຂະນະທີ່ສະແດງທ່າທາງ ໂດຍການເລື່ອນໄປທີ່ປຸ່ມຍະຫວ່າງ"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"ກຳ​ລັງ​ສະ​ແດງແປ້ນ​ພິມ <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="voice_input_disabled_summary" msgid="8141750303464726129">"ບໍ່ມີວິທີການປ້ອນສຽງເປີດນໍາໃຊ້. ໃຫ້ກວດເບິ່ງການຕັ້ງຄ່າໃນເມນູ ພາສາ &amp; ການປ້ອນຂໍ້ມູນ."</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"ພາສາທີ່ທ່ານເລືອກໃຊ້ໃນອຸປະກອນຂອງທ່ານນັ້ນ ມີວັດຈະນານຸກົມໃຫ້ໃຊ້ພ້ອມ.&lt;br/&gt; ພວກເຮົາແນະນຳໃຫ້ &lt;b&gt;ດາວໂຫລດ&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> ວັດຈະນານຸກົມດັ່ງກ່າວ ເພື່ອເພີ່ມປະສົບການໃນການພິມຂອງທ່ານ.&lt;br/&gt; &lt;br/&gt; ການດາວໂຫລດອາດຈະໃຊ້ເວລາພຽງໜຶ່ງເຖິງສອງນາທີ ໂດຍການໃຊ້ 3G. ທ່ານອາດຈະເສຍຄ່າບໍລິການສຳລັບອິນເຕີເນັດ ຫາກທ່ານບໍ່ມີ &lt;b&gt;ການນຳໃຊ້ອິນເຕີເນັດແບບບໍ່ຈຳກັດ&lt;/b&gt;.&lt;br/&gt; ຫາກທ່ານບໍ່ແນ່ໃຈວ່າຮູບແບບການໃຊ້ໃດທີ່ທ່ານມີຢູ່ ພວກເຮົາແນະນຳໃຫ້ຊອກຫາການເຊື່ອມຕໍ່ Wi-Fi ເພື່ອດາວໂຫລດມັນໂດຍອັດຕະໂນມັດ.&lt;br/&gt; &lt;br/&gt; ເຄັດລັບ: ທ່ານສາມາດດາວໂຫລດ ແລະ ລຶບວັດຈະນານຸກົມໄດ້ທີ່ &lt;b&gt;ພາສາ &amp; ການປ້ອນຂໍ້ມູນ&lt;/b&gt; ຢູ່ໃນເມນູ &lt;b&gt;ການຕັ້ງຄ່າ&lt;/b&gt; ຂອງອຸປະກອນພົກພາຂອງທ່ານ."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ພາ​ສາ​ທີ່​ເລືອກ​ໃນ​ອຸ​ປະ​ກອນ​ມື​ຖື​ຂອງ​ທ່າ​ນັ້ນ​ມີ​ວັດ​ຈະ​ນາ​ນຸ​ກົມ​ທີ່​ສາ​ມາດ​ໃຊ້​ໄດ້.&lt;br/&gt; ພວ​ກ​ເຮົາ​ຂໍ​ແນະ​ນຳ​ໃຫ້ &lt;b&gt;ດາວ​ໂຫລດ&lt;/b&gt; ວັດ​ຈ​ະ​ນາ​ນຸ​ກົມ <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ເພື່ອ​ປັບ​ປຸງ​ປະ​ສົບ​ການ​ໃນ​ການ​ພິມ​ຂອງ​ທ່ານ.&lt;br/&gt; &lt;br/&gt; ການ​ດາວ​ໂຫລດ​ອາດ​ໃຊ້​ເວ​ລາ​ສອງ​ສາມ​ນາ​ທີ​ຜ່ານ​ເຄືອ​ຂ່າຍ 3G. ທ່ານ​ອາ​ດ​ຖືກ​ຮຽກ​ເກັບ​ຄ່າ​ຂໍ້​ມູນ​ໄດ້​ຫາກ​ທ່ານບໍ່​ໄດ້​ໃຊ້ &lt;b&gt;ແພັກ​ເກດ​ຂໍ້​ມູນ​ແບບບໍ່​ຈຳ​ກັດ&lt;/b&gt;.&lt;br/&gt; ຫາກ​ທ່ານບໍ່​ແນ່​ໃຈ​ວ່າ​ທ່ານ​ໃຊ້​ແພັກ​ເກດ​ແບບ​ໃດ​ຢູ່ ພວກ​ເຮົາ​ຂໍ​ແນະ​ນຳ​ໃຫ້​ທ່ານ​ເຊື່ອມ​ຕໍ່ເຄືອ​ຂ່າຍ Wi-Fi ໃດ​ນຶ່ງ​ແທນ​ເພື່ອ​ເລີ່ມ​ຕົ້ນ​ການ​ດາວ​ໂຫລດ​ໂດຍ​ອັດ​ຕະ​ໂນ​ມັດ.&lt;br/&gt; &lt;br/&gt; ເຄັດ​ລັບ: ທ່ານ​ສາ​ມາ​ດ​ດາວ​ໂຫລດ ແລະ​ລຶບ​ວັດ​ຈະ​ນາ​ນຸ​ກົມ​ອອກ​ໄດ້​ໂດຍ​ການ​ໄປ​ທີ່ &lt;b&gt;ພາ​ສາ &amp; ການ​ປ້ອນ​ຂໍ້​ມູນ&lt;/b&gt; ໃນ​ເມ​ນູ &lt;b&gt;ການ​ຕັ້ງ​ຄ່າ&lt;/b&gt; ຂອງ​ອຸ​ປະ​ກອນ​ມື​ຖື​ຂອງ​ທ່ານ."</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..633980ece
--- /dev/null
+++ b/java/res/values-lt/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-lt/strings.xml
index 1f943944c..9efdc679c 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Klaviatūra rodoma režimu „<xliff:g id="KEYBOARD_MODE">%s</xliff:g>“"</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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"laiko"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicinė)"</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 +165,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">"Iškelti 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 +208,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.&lt;br/&gt; Rekomenduojame &lt;b&gt;atsisiųsti&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> žodyną, kad būtų patogiau įvesti tekstą.&lt;br/&gt; &lt;br/&gt; Atsisiuntimas per 3G turėtų trukti 1–2 min. Jei neturite &lt;b&gt;neribotų duomenų plano&lt;/b&gt;, galite būti apmokestinti.&lt;br/&gt; Jei nežinote, kokį planą turite, rekomenduojame rasti „Wi-Fi“ ryšį, kad atsisiuntimas prasidėtų automatiškai.&lt;br/&gt; &lt;br/&gt; Patarimas: galite atsisiųsti ir pašalinti žodynus mobiliojo įrenginio meniu &lt;b&gt;Nustatymai&lt;/b&gt; skiltyje &lt;b&gt;Kalba ir įvestis&lt;/b&gt;."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Galimas jūsų mobiliajame įrenginyje pasirinktos kalbos žodynas.&lt;br/&gt; Rekomenduojame &lt;b&gt;atsisiųsti&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> žodyną, kad patobulintumėte teksto įvedimą.&lt;br/&gt; &lt;br/&gt; Naudojant 3G ryšį atsisiuntimas užtruks vieną ar dvi minutes. Jei naudojate ne &lt;b&gt;neribotų duomenų planą&lt;/b&gt;, gali būti taikomi mokesčiai.&lt;br/&gt; Jei nesate tikri, kurį duomenų planą naudojate, rekomenduojame rasti „Wi-Fi“ ryšį, kad atsisiuntimas būtų pradėtas automatiškai.&lt;br/&gt; &lt;br/&gt; Patarimas: žodynus galite atsisiųsti ir pašalinti apsilankę mobiliojo įrenginio skiltyje &lt;b&gt;Kalba ir įvestis&lt;/b&gt;, esančioje meniu &lt;b&gt;Nustatymai&lt;/b&gt;."</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..ce2062dd9
--- /dev/null
+++ b/java/res/values-lv/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-lv/strings.xml
index 8ea24edb7..ec4a38ba9 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Taustiņam <xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Tiek rādīts tastatūras režīms <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"laiks"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionālā)"</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 +165,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 +208,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.&lt;br/&gt;Ieteicams &lt;b&gt;lejupielādēt&lt;/b&gt; vārdnīcu (<xliff:g id="LANGUAGE">%1$s</xliff:g>), lai uzlabotu rakstīšanas iespējas.&lt;br/&gt;&lt;br/&gt;Lejupielāde, izmantojot 3G tīklu, ilgs dažas minūtes. Ja nelietojat &lt;b&gt;neierobežotu datu plānu&lt;/b&gt;, var tikt piemērota maksa.&lt;br/&gt;Ja nezināt, kādu datu plānu lietojat, ieteicams atrast Wi-Fi savienojumu, lai automātiski sāktu lejupielādi.&lt;br/&gt;&lt;br/&gt;Padoms. Vārdnīcas var lejupielādēt un noņemt mobilās ierīces izvēlnes &lt;b&gt;Iestatījumi&lt;/b&gt; sadaļā &lt;b&gt;Valoda un ievade&lt;/b&gt;."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Mobilajā ierīcē atlasītajai valodai ir pieejama vārdnīca.&lt;br/&gt; Ieteicams &lt;b&gt;lejupielādēt&lt;/b&gt; šo vārdnīcu (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>), lai uzlabotu rakstīšanas iespējas.&lt;br/&gt; &lt;br/&gt; Lejupielāde, izmantojot 3G tīklu, ilgs tikai dažas minūtes. Ja nelietojat &lt;b&gt;neierobežotu datu plānu&lt;/b&gt;, var tikt piemērota maksa.&lt;br/&gt; Ja nezināt, kādu datu plānu lietojat, ieteicams atrast Wi-Fi savienojumu, lai automātiski sāktu lejupielādi.&lt;br/&gt; &lt;br/&gt; Padoms: vārdnīcas var lejupielādēt un noņemt sadaļā &lt;b&gt;Valoda un ievade&lt;/b&gt;, kas atrodas mobilās ierīces izvēlnē &lt;b&gt;Iestatījumi&lt;/b&gt;."</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.xml b/java/res/values-mk/strings.xml
index 6f685d395..1137fd09d 100644
--- a/java/res/values-mk/strings.xml
+++ b/java/res/values-mk/strings.xml
@@ -214,18 +214,6 @@
<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..047cfc7bf
--- /dev/null
+++ b/java/res/values-mn-rMN/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Зөвлөмжүүдийг сайжруулахын тулд таны харилцсан, бичсэн зүйлсээс суралцана"</string>
+</resources>
diff --git a/java/res/values-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml
index d4175899f..ef8181faf 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Хэллэгийн зангалт"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Зангалтын явцад зай авах товчин дээр гулсуулах замаар зай оруулах"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"Таны мобайль төхөөрөмж дээр сонгосон хэлэнд толь бичиг байна.&lt;br/&gt; Тус  <xliff:g id="LANGUAGE">%1$s</xliff:g> толь бичгийг &lt;b&gt;татаж аван&lt;/b&gt; зөв бичилтээ сайжруулахыг бид зөвлөж байна.&lt;br/&gt; &lt;br/&gt; Татаж авахад 3G сүлжээгээр нэг хоёр минут болно. Танд &lt;b&gt;хязгааргүй дата эрх&lt;/b&gt; байхгүй бол нэмэлт төлбөр гарч болно.&lt;br/&gt; Та дата эрхийнхээ талаар сайн мэдэхгүй байгаа бол Wi-Fi холболттой газар очин автоматаар татаж авахыг зөвлөж байна.&lt;br/&gt; &lt;br/&gt; Зөвлөмж: Та өөрийн мобайль төхөөрөмжийн &lt;b&gt;Тохиргоо&lt;/b&gt; цэсний &lt;b&gt;Хэл &amp; оруулах&lt;/b&gt; руу очиж толь бичиг татаж авах буюу устгаж болно."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Таны мобайл төхөөрөмж дээр сонгосон хэлний толь бичиг байна. &lt;br/&gt; Бид танд <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> хэлний толь бичиг &lt;b&gt; татаж аван &lt;/ б&gt; бичихэд хялбар болгохыг зөвлөж байна. &lt;br/&gt; &lt;br/&gt; Татаж авахад 3G дээр нэг, хоёр минут болж магадгүй. Хэрэв та &lt;b&gt; хязгааргүй дата ашиглах эрхтэй &lt;/ б&gt; биш бол нэмэлт төлбөр гарч болно. Хэрэв та өөрийн дата ашиглалтын эрхийг сайн мэдэхгүй байгаа бол Wi-Fi холболт ашиглан автоматаар татан авахыг эхлүүлэхийг зөвлөж байна.&lt;br/&gt; &lt;br/&gt; &lt;br/&gt; Зөвлөмж: Та өөрийн мобайл төхөөрөмжийн &lt;b&gt; тохиргоо &lt;/ б&gt; цэсэнд &lt;/ б&gt; Хэл &amp; оролт &lt;b&gt; руу очиж толь бичиг татаж авах, устгах боломжтой."</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..e53ada237
--- /dev/null
+++ b/java/res/values-ms-rMY/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-ms-rMY/strings.xml
index c9b4a0359..6fbd38c76 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Menunjukkan papan kekunci <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"masa"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 &amp; 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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisional)"</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 +165,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">"Buang kamus kenalan"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Buang kamus peribadi"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Buang kamus sejarah pengguna"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Buang 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 +208,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.&lt;br/&gt; Kami mengesyorkan &lt;b&gt;memuat turun&lt;/b&gt; kamus <xliff:g id="LANGUAGE">%1$s</xliff:g> untuk memperbaik pengalaman menaip anda.&lt;br/&gt; &lt;br/&gt; Muat turun boleh mengambil masa seminit atau dua melalui 3G. Caj mungkin dikenakan jika anda tidak mempunyai &lt;b&gt;pelan data tanpa had&lt;/b&gt;.&lt;br/&gt; Jika anda tidak pasti jenis pelan data yang anda miliki, kami mengesyorkan agar anda mencari sambungan Wi-Fi untuk mula memuat turun secara automatik.&lt;br/&gt; &lt;br/&gt; Petua: Anda boleh memuat turun dan mengalih keluar kamus dengan pergi ke menu &lt;b&gt;Bahasa &amp; input&lt;/b&gt; dalam &lt;b&gt;Tetapan&lt;/b&gt; 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.&lt;br/&gt; Kami mengesyorkan &lt;b&gt;memuat turun&lt;/b&gt; kamus <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> untuk memperbaik pengalaman menaip anda.&lt;br/&gt; &lt;br/&gt; Muat turun boleh mengambil masa satu atau dua minit melalui 3G. Caj mungkin dikenakan jika anda tidak mempunyai &lt;b&gt;pelan data tanpa had&lt;/b&gt;.&lt;br/&gt; Jika anda tidak pasti jenis pelan data yang anda gunakan, kami mengesyorkan agar anda mencari sambungan Wi-Fi untuk mula memuat turun secara automatik.&lt;br/&gt; &lt;br/&gt; Petua: Anda boleh memuat turun dan mengalih keluar kamus dengan pergi ke menu &lt;b&gt;Bahasa&amp; input&lt;/b&gt; dalam &lt;b&gt;Tetapan&lt;/b&gt; 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..8c79eef0b
--- /dev/null
+++ b/java/res/values-nb/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-nb/strings.xml
index 00aa10da7..02f13bb41 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Viser <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"tid"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"Nettadresse"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradisjonell)"</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 +165,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">"Tøm kontakter-ordlisten"</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 +208,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.&lt;br/&gt; Vi anbefaler å &lt;b&gt;laste ned&lt;/b&gt; ordlisten for <xliff:g id="LANGUAGE">%1$s</xliff:g>. Dette forbedrer skriveopplevelsen din.&lt;br/&gt; &lt;br/&gt; Nedlastingen kan ta fra ett til to minutter via 3G. Belastninger kan påløpe hvis du ikke har et abonnement med &lt;b&gt;ubegrenset databruk&lt;/b&gt;.&lt;br/&gt; Hvis du er usikker på hvilken abonnementstype du har, anbefaler vi deg å finne en Wi-Fi-tilkobling for å starte nedlastingen automatisk.&lt;br/&gt; &lt;br/&gt; Tips: Du kan laste ned og fjerne ordlister ved å gå til &lt;b&gt;Språk og inndata&lt;/b&gt; i menyen for &lt;b&gt;Innstillinger&lt;/b&gt; på mobilenheten din."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Det valgte språket på mobilenheten din har en tilgjengelig ordliste.&lt;br/&gt; Vi anbefaler å &lt;b&gt;laste ned&lt;/b&gt; ordlisten for <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Dette forbedrer skriveopplevelsen din.&lt;br/&gt; &lt;br/&gt; Nedlastingen kan ta fra ett til to minutter via 3G. Belastninger kan påløpe hvis du ikke har et abonnement med &lt;b&gt;ubegrenset databruk&lt;/b&gt;.&lt;br/&gt; Hvis du er usikker på hvilken abonnementstype du har, anbefaler vi deg å finne en Wi-Fi-tilkobling for å starte nedlastingen automatisk.&lt;br/&gt; &lt;br/&gt; Tips: Du kan laste ned og fjerne ordlister ved å gå til &lt;b&gt;Språk og inndata&lt;/b&gt; i menyen for &lt;b&gt;Innstillinger&lt;/b&gt; 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..6945a61cb
--- /dev/null
+++ b/java/res/values-ne-rNP/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"सुझावहरू सुधार गर्न सञ्‍चारहरू र टाइप गरिएको डेटाबाट जान्नुहोस्"</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..65d15e3a0
--- /dev/null
+++ b/java/res/values-ne-rNP/strings.xml
@@ -0,0 +1,244 @@
+<?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="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="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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="7486740369324538848">"<xliff:g id="KEYBOARD_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="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_nepali_traditional" msgid="1994571919751163596">"<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">"तपाईँको मोबाइल उपकरणमा चयन गरिएको भाषाको शब्दकोश उपलब्ध छ। &lt;br/&gt; तपाईँको टाइप गर्ने अनुभव सुधार गर्न हामी <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>को शब्दकोश &lt;b&gt; डाउनलोड गर्न &lt;/b&gt; सिफारिस गर्दछौँ। यो डाउनलोड गर्न 3G मा एक वा दुई मिनेट लिन सक्छ। तपाईँ एक &lt;b&gt; तपाईँको असीमित डेटा योजना &lt;/b&gt; छैन भने शुल्क लागू हुन सक्छ। तपाईँसँग कुन डेटा योजना छ भन्ने निश्चित छैन भने Wi-Fi जडान गरेर स्वचालित डाउनलोड गर्न हामी सिफारिस गर्दछौँ। युक्ति: तपाईँ आफ्नो मोबाइल उपकरणको &lt;/b&gt; भाषा र इनपुट &lt;b&gt; &lt;b&gt;सेटिङ &lt;/b&gt; मेनुमा गएर शब्दकोशलाई डाउनलोड र हटाउन सक्नुहुन्छ।"</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..f77a1f45a
--- /dev/null
+++ b/java/res/values-nl/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-nl/strings.xml
index dcbf2c09c..1968a45de 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Met <xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"tijd"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditioneel)"</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 +165,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 +208,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.&lt;br/&gt; We raden u aan het woordenboek voor het <xliff:g id="LANGUAGE">%1$s</xliff:g> te &lt;b&gt;downloaden&lt;/b&gt; om uw typvaardigheid te verbeteren.&lt;br/&gt; &lt;br/&gt; De download kan één of twee minuten duren via 3G. Er kunnen kosten worden berekend als u geen &lt;b&gt;onbeperkt gegevensabonnement&lt;/b&gt; heeft.&lt;br/&gt; Als u niet zeker weet welk gegevensabonnement u heeft, raden we u aan een wifi-verbinding te zoeken om de download automatisch te starten.&lt;br/&gt; &lt;br/&gt; Tip: u kunt woordenboeken downloaden en verwijderen via &lt;b&gt;Taal en invoer&lt;/b&gt; in het menu &lt;b&gt;Instellingen&lt;/b&gt; 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.&lt;br/&gt; We raden u aan het woordenboek voor het <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> te &lt;b&gt;downloaden&lt;/b&gt; om uw typvaardigheid te verbeteren.&lt;br/&gt; &lt;br/&gt; De download kan één of twee minuten duren via 3G. Er kunnen kosten worden berekend als u geen &lt;b&gt;onbeperkt gegevensabonnement&lt;/b&gt; heeft.&lt;br/&gt; Als u niet zeker weet welk gegevensabonnement u heeft, raden we u aan een wifi-verbinding te zoeken om de download automatisch te starten.&lt;br/&gt; &lt;br/&gt; Tip: u kunt woordenboeken downloaden en verwijderen via &lt;b&gt;Taal en invoer&lt;/b&gt; in het menu &lt;b&gt;Instellingen&lt;/b&gt; 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..03da01d87
--- /dev/null
+++ b/java/res/values-pl/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-pl/strings.xml
index c78674a9b..9d46f61fe 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Pokazuję klawiaturę w trybie <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"godzina"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradycyjny)"</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 +159,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">"Zrzut słownika kontaktów"</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Zrzut słownika osobistego"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Zrzut słownika historii użytkownika"</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Zrzut 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 +208,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.&lt;br/&gt; Warto &lt;b&gt;pobrać&lt;/b&gt; ten słownik <xliff:g id="LANGUAGE">%1$s</xliff:g>, by ułatwić sobie pisanie.&lt;br/&gt; &lt;br/&gt; Pobieranie trwa do dwóch minut (przez 3G). Jeśli nie masz &lt;b&gt;abonamentu z nieograniczoną transmisją danych&lt;/b&gt;, operator może naliczyć opłatę.&lt;br/&gt; Jeśli nie wiesz, jaki masz abonament, połącz się z Wi-Fi, by automatycznie rozpocząć pobieranie.&lt;br/&gt; &lt;br/&gt; Wskazówka: słowniki możesz pobierać i usuwać na urządzeniu w sekcji &lt;b&gt;Język, klawiatura, głos&lt;/b&gt; w menu &lt;b&gt;Ustawienia&lt;/b&gt;."</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.&lt;br/&gt; Warto &lt;b&gt;pobrać&lt;/b&gt; ten słownik <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>, by ułatwić sobie pisanie.&lt;br/&gt; &lt;br/&gt; Pobieranie trwa do dwóch minut (przez 3G). Jeśli nie masz &lt;b&gt;abonamentu z nieograniczoną transmisją danych&lt;/b&gt;, operator może naliczyć opłatę.&lt;br/&gt; Jeśli nie wiesz, jaki masz abonament, połącz się z Wi-Fi, by automatycznie rozpocząć pobieranie.&lt;br/&gt; &lt;br/&gt; Wskazówka: słowniki możesz pobierać i usuwać w sekcji &lt;b&gt;Język, klawiatura, głos&lt;/b&gt; w menu &lt;b&gt;Ustawienia&lt;/b&gt; 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..0724173b4
--- /dev/null
+++ b/java/res/values-pt-rPT/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-pt-rPT/strings.xml
index c27758116..8adaa4dde 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> executa a 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"A mostrar o teclado de <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URLs"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</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 +165,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">"Descarregar 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 +208,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.&lt;br/&gt; Recomendamos que &lt;b&gt;transfira&lt;/b&gt; o dicionário de <xliff:g id="LANGUAGE">%1$s</xliff:g> para melhorar a sua experiência de introdução de texto.&lt;br/&gt; &lt;br/&gt; A transferência pode demorar um ou dois minutos acima de 3G. Poderão ser aplicadas taxas se não tiver um &lt;b&gt;plano de dados ilimitado&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Sugestão: pode transferir e remover dicionários acedendo a &lt;b&gt;Idioma e introdução&lt;/b&gt; no menu &lt;b&gt;Definições&lt;/b&gt; 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.&lt;br/&gt; Recomendamos que &lt;b&gt;transfira&lt;/b&gt; o dicionário de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para melhorar a sua experiência de introdução de texto.&lt;br/&gt; &lt;br/&gt; A transferência pode demorar um ou dois minutos através de 3G. Poderão ser aplicadas taxas se não tiver um &lt;b&gt;plano de dados ilimitado&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Sugestão: Pode transferir e remover dicionários acedendo a &lt;b&gt;Idioma e introdução&lt;/b&gt; no menu &lt;b&gt;Definições&lt;/b&gt; 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..041a04c26
--- /dev/null
+++ b/java/res/values-pt/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-pt/strings.xml
index f98ef8cd6..966c4021b 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,19 +67,20 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Mostrando teclado <xliff:g id="KEYBOARD_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>
@@ -116,13 +118,8 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicional)"</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 +165,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">"Despejar 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 +208,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.&lt;br/&gt; Recomendamos &lt;b&gt;fazer o download&lt;/b&gt; do dicionário de <xliff:g id="LANGUAGE">%1$s</xliff:g> para melhorar sua experiência de digitação.&lt;br/&gt; O download pode levar um ou dois minutos por conexão 3G. Tarifas podem ser aplicáveis caso você não tenha um &lt;b&gt;plano de dados ilimitado&lt;/b&gt;.&lt;br/&gt; Se você não tem certeza quanto a seu plano de dados, recomendamos encontrar uma conexão Wi-Fi para iniciar o download automaticamente.&lt;br/&gt; Dica: você pode fazer o download de dicionários e removê-los acessando &lt;b&gt;Idioma e entrada&lt;/b&gt; no menu &lt;b&gt;Configurações&lt;/b&gt; 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.&lt;br/&gt; Recomendamos &lt;b&gt;fazer o download&lt;/b&gt; do dicionário de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> para melhorar sua experiência de digitação.&lt;br/&gt; O download pode levar um ou dois minutos por conexão 3G. Tarifas podem ser aplicáveis caso você não tenha um &lt;b&gt;plano de dados ilimitado&lt;/b&gt;.&lt;br/&gt; Se você não tem certeza quanto a seu plano de dados, recomendamos encontrar uma conexão Wi-Fi para iniciar o download automaticamente.&lt;br/&gt; Dica: você pode fazer o download de dicionários e removê-los acessando &lt;b&gt;Idioma e entrada&lt;/b&gt; no menu &lt;b&gt;Configurações&lt;/b&gt; 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.xml b/java/res/values-rm/strings.xml
index 3f0bab963..378c25426 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -209,18 +209,6 @@
<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..ff064577e
--- /dev/null
+++ b/java/res/values-ro/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Utilizați mesajele și datele introduse pt. a îmbunătăți sugestiile"</string>
+</resources>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 147f83e61..ac713d996 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Se afișează tastatura pentru <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"ore"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"adrese URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradițională)"</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 +165,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">"Eliminați dicționar pers. cont."</string>
+ <string name="prefs_dump_user_dict" msgid="294870685041741951">"Eliminați dicționar personal"</string>
+ <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"Eliminați dicționar istoric utiliz."</string>
+ <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"Eliminaț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 +208,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.&lt;br/&gt; Vă recomandăm să &lt;b&gt;descărcați&lt;/b&gt; dicționarul de <xliff:g id="LANGUAGE">%1$s</xliff:g> pentru a vă îmbunătăți experiența la introducerea textului.&lt;br/&gt; &lt;br/&gt; Descărcarea prin 3G poate dura un minut sau două. Se pot aplica taxe dacă nu aveți un &lt;b&gt;plan de date nelimitat&lt;/b&gt;.&lt;br/&gt; Dacă nu știți sigur ce plan de date aveți, găsiți o conexiune Wi-Fi și descărcați automat.&lt;br/&gt; &lt;br/&gt; Sfat: puteți să descărcați și să eliminați dicționare accesând &lt;b&gt;Limbă și introducere de text&lt;/b&gt; din meniul &lt;b&gt;Setări&lt;/b&gt;, 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.&lt;br/&gt; Vă recomandăm să &lt;b&gt;descărcați&lt;/b&gt; dicționarul de <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> pentru o mai bună experiență a introducerii de text.&lt;br/&gt; &lt;br/&gt; Descărcarea poate dura un minut sau două prin 3G. Dacă nu aveți un &lt;b&gt;plan de date nelimitat&lt;/b&gt;, se pot aplica taxe.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Sfat: puteți să descărcați și să ștergeți dicționare accesând opțiunea &lt;b&gt;Limbă și introducere de text&lt;/b&gt; din meniul &lt;b&gt;Setări&lt;/b&gt; 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..b2f215c4b
--- /dev/null
+++ b/java/res/values-ru/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Устройство будет запоминать то, что вы вводите чаще всего"</string>
+</resources>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 8bbaead0a..2d2326388 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Непрерывный ввод фраз"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Проводите по клавише пробела после каждого слова"</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_auto_correct" msgid="5150455215290003221">"При нажатии клавиши <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="2309828861778711939">"Клавиша <xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Включен режим <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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> словарь для проверки правописания.&lt;br/&gt;Рекомендуем &lt;b&gt;установить&lt;/b&gt; его, чтобы быстрее вводить текст.&lt;br/&gt;&lt;br/&gt;Если вашим тарифом предусмотрена &lt;b&gt;безлимитная передача данных&lt;/b&gt;, словарь можно загрузить через сеть 3G (это займет всего пару минут).&lt;br/&gt;Если вы не помните подробностей своего тарифного плана, лучше подключитесь к сети Wi-Fi (загрузка начнется автоматически).&lt;br/&gt;&lt;br/&gt;Совет. Чтобы добавить, удалить или настроить словарь, откройте раздел &lt;b&gt;Язык и ввод&lt;/b&gt; в настройках своего устройства."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Доступен словарь для проверки правописания (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>).&lt;br/&gt;Рекомендуем &lt;b&gt;установить&lt;/b&gt; его, чтобы быстрее вводить текст.&lt;br/&gt;&lt;br/&gt;Если вашим тарифом предусмотрена &lt;b&gt;безлимитная передача данных&lt;/b&gt;, словарь можно загрузить через сеть 3G (это займет всего пару минут).&lt;br/&gt;Если вы не помните подробностей своего тарифного плана, лучше подключитесь к сети Wi-Fi (загрузка начнется автоматически).&lt;br/&gt;&lt;br/&gt;Совет. Чтобы добавлять, удалять и настраивать словари, откройте раздел &lt;b&gt;Язык и ввод&lt;/b&gt; в настройках устройства."</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..00365ab07
--- /dev/null
+++ b/java/res/values-sk/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-sk/strings.xml
index d1f966cea..d88759dfa 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Klávesom <xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Je zobrazená klávesnica <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"Adresa URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradičná)"</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 +163,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 +200,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 +208,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.&lt;br/&gt; Slovník jazyka <xliff:g id="LANGUAGE">%1$s</xliff:g> vám odporúčame &lt;b&gt;prevziať&lt;/b&gt;. Pomôže vám pri zadávaní textu.&lt;br/&gt; &lt;br/&gt; V sieti 3G môže preberanie chvíľu trvať. Ak nemáte &lt;b&gt;neobmedzený dátový program&lt;/b&gt;, môžu sa účtovať poplatky.&lt;br/&gt; Ak s určitosťou neviete aký dátový program používate, vyhľadajte pripojenie k sieti Wi-Fi a preberanie sa spustí automaticky.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky môžete v mobilnom zariadení preberať a odstraňovať v časti &lt;b&gt;Jazyk a vstup&lt;/b&gt; ponuky &lt;b&gt;Nastavenia&lt;/b&gt;."</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.&lt;br/&gt; Slovník jazyka <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> vám odporúčame &lt;b&gt;stiahnuť&lt;/b&gt;. Pomôže vám pri zadávaní textu.&lt;br/&gt; &lt;br/&gt; V sieti 3G môže sťahovanie trvať jednu až dve minúty. Ak nemáte &lt;b&gt;neobmedzený dátový program&lt;/b&gt;, môžu sa účtovať poplatky.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky môžete v mobilnom zariadení sťahovať a odstraňovať v časti &lt;b&gt;Jazyk a vstup&lt;/b&gt; ponuky &lt;b&gt;Nastavenia&lt;/b&gt;."</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..fd14a6a52
--- /dev/null
+++ b/java/res/values-sl/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-sl/strings.xml
index a0f83c12f..650b69f5f 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> izvede samopopravek"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Prikaz tipkovnice <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"ura"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (tradicionalna)"</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 +165,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">"Izvoz 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 +208,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.&lt;br/&gt; Za izboljšano izkušnjo tipkanja priporočamo, da &lt;b&gt;prenesete&lt;/b&gt; slovar za ta jezik: <xliff:g id="LANGUAGE">%1$s</xliff:g>.&lt;br/&gt; &lt;br/&gt; Prenos prek povezave 3G lahko traja minuto ali dve. Če nimate &lt;b&gt;neomejenega podatkovnega paketa&lt;/b&gt;.&lt;br/&gt;, 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.&lt;br/&gt; &lt;br/&gt; Nasvet: Slovarje lahko prenesete in odstranite tako, da v meniju &lt;b&gt;Nastavitve&lt;/b&gt; v mobilni napravi odprete &lt;b&gt;Jezik in vnos&lt;/b&gt;."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Za izbrani jezik v mobilni napravi je na voljo slovar.&lt;br/&gt; Za izboljšano izkušnjo tipkanja priporočamo, da &lt;b&gt;prenesete&lt;/b&gt; slovar za ta jezik: <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>.&lt;br/&gt; &lt;br/&gt; Prenos prek povezave 3G lahko traja minuto ali dve. Če nimate &lt;b&gt;neomejenega podatkovnega paketa&lt;/b&gt;.&lt;br/&gt;, 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.&lt;br/&gt; &lt;br/&gt; Nasvet: slovarje lahko prenesete in odstranite tako, da v meniju &lt;b&gt;Nastavitve&lt;/b&gt; v mobilni napravi odprete &lt;b&gt;Jezik in vnos&lt;/b&gt;."</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..a6eb25ed9
--- /dev/null
+++ b/java/res/values-sr/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Користи комуникације и унете податке ради побољшања предлога"</string>
+</resources>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index ce4978ff5..782830d6f 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Покрет за фразе"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Уносите размаке током покрета преласком до тастера за размак"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Приказујемо тастатуру у режиму <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"Доступан је речник за изабрани језик на мобилном уређају.&lt;br/&gt; Препоручујемо да &lt;b&gt;преузмете &lt;/b&gt; речник за <xliff:g id="LANGUAGE">%1$s</xliff:g> да бисте побољшали доживљај куцања.&lt;br/&gt; &lt;br/&gt; Преузимање може да траје минут или два преко 3G мреже. Трошкови ће можда бити наплаћени ако немате &lt;b&gt;претплатнички пакет без ограничења&lt;/b&gt;.&lt;br/&gt; Ако нисте сигурни који претплатнички пакет имате, препоручујемо да пронађете Wi-Fi везу да бисте аутоматски започели преузимање.&lt;br/&gt; &lt;br/&gt; Савет: Речнике можете да преузимате и уклањате тако што ћете посетити &lt;b&gt;Језик и унос&lt;/b&gt; у менију &lt;b&gt;Подешавања&lt;/b&gt; мобилног уређаја."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Доступан је речник за изабрани језик на мобилном уређају.&lt;br/&gt; Препоручујемо вам да &lt;b&gt;преузмете&lt;/b&gt; речник за <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> да бисте побољшали доживљај куцања.&lt;br/&gt; &lt;br/&gt; Преузимање може да траје минут или два преко 3G мреже. Трошкови ће можда бити наплаћени ако немате &lt;b&gt;претплатнички пакет без ограничења&lt;/b&gt;.&lt;br/&gt; Ако нисте сигурни који претплатнички пакет имате, препоручујемо вам да пронађете Wi-Fi везу да бисте аутоматски започели преузимање.&lt;br/&gt; &lt;br/&gt; Савет: Речнике можете да преузимате и уклањате ако одете на &lt;b&gt;Језик и унос&lt;/b&gt; у менију &lt;b&gt;Подешавања&lt;/b&gt; на мобилном уређају."</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..8d8a08934
--- /dev/null
+++ b/java/res/values-sv/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-sv/strings.xml
index afe349afd..22a5ce3ef 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Om du trycker på <xliff:g id="KEY_NAME">%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>
@@ -106,23 +108,18 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Tangentbord för <xliff:g id="KEYBOARD_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_im" msgid="1137405089766557048">"SMS/MMS"</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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (traditionell)"</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 +165,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">"Dumpa 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 +208,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.&lt;br/&gt; Vi rekommenderar att du &lt;b&gt;hämtar&lt;/b&gt; ordlistan för <xliff:g id="LANGUAGE">%1$s</xliff:g> så att det blir enklare att skriva.&lt;br/&gt; &lt;br/&gt; Det kan ta någon minut att hämta den via 3G. Avgifter kan tillkomma om du inte har ett abonnemang med &lt;b&gt;obegränsad datatrafik&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tips! Du kan hämta och ta bort ordlistor under &lt;b&gt;Språk och inmatning&lt;/b&gt; i menyn &lt;b&gt;Inställningar&lt;/b&gt; 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.&lt;br/&gt; Vi rekommenderar att du &lt;b&gt;hämtar&lt;/b&gt; ordboken på <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>. Då blir det enklare och smidigare att skriva.&lt;br/&gt; &lt;br/&gt; Hämtningen tar en minut eller två om du använder 3G. Avgifter kan tillkomma om du inte har ett &lt;b&gt;abonnemang med obegränsad data&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tips: Du kan hämta och ta bort ordböcker via &lt;b&gt;Språk och inmatning&lt;/b&gt; i menyn &lt;b&gt;Inställningar&lt;/b&gt; 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..10eab64cd
--- /dev/null
+++ b/java/res/values-sw/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-sw/strings.xml
index 191ad977c..50c6aaa38 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> hufanya marekebisho otomatiki"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Inaonyesha kibodi ya <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"wakati"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (cha Jadi)"</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 +165,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">"Tupa kamusi 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 +208,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.&lt;br/&gt; Tunapendekeza&lt;b&gt;upakuaji wa kamusi&lt;/b&gt; <xliff:g id="LANGUAGE">%1$s</xliff:g> ili kuboresha hali yako ya kucharaza.&lt;br/&gt; &lt;br/&gt; Upakuaji unaweza kuchukua dakika moja au mbili kukamilika kwenye 3G. Unaweza kutozwa pesa ikiwa huna mpango wa data &lt;b&gt;usio na kipimo &lt;/b&gt;.&lt;br/&gt;Ikiwa huna uhakika una mpango gani wa data, tunapendekeza utafute muunganisho wa Wi-Fi ili uanze upakuaji moja kwa moja.&lt;br/&gt; &lt;br/&gt; Kidokezo: Unaweza kupakua na kuondoa kamusi kwa kuenda kwenye&lt;b&gt;Ingizo la &amp; Lugha&lt;/b&gt; katika &lt;b&gt;menyu ya Mipangilio&lt;/b&gt; 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.&lt;br/&gt; Tunapendekeza&lt;b&gt;upakuaji wa kamusi ya&lt;/b&gt; <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ili kuboresha hali yako ya kuchapa.&lt;br/&gt; &lt;br/&gt; Upakuaji unaweza kuchukua dakika moja au mbili kukamilika kwenye mtandao wa 3G. Unaweza kutozwa ada ikiwa huna mpango wa data &lt;b&gt;usio na kipimo &lt;/b&gt;.&lt;br/&gt;Ikiwa huna uhakika una mpango gani wa data, tunapendekeza utafute muunganisho wa Wi-Fi ili uanze upakuaji kiotomatiki.&lt;br/&gt; &lt;br/&gt; Kidokezo: Unaweza kupakua na kuondoa kamusi kwa kuenda kwenye&lt;b&gt;Lugha na Zana za Kuingiza Datalt;/b&gt; katika &lt;b&gt;menyu ya Mipangilio&lt;/b&gt; 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..bd123c499
--- /dev/null
+++ b/java/res/values-sw600dp-land/config.xml
@@ -0,0 +1,71 @@
+<?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_gb">2.444%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">5.200%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">1.447%p</fraction>
+
+ <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/layout/key_preview_klp.xml b/java/res/values-sw600dp/config-screen-metrics.xml
index 160aeb9a9..d16c9253f 100644
--- a/java/res/layout/key_preview_klp.xml
+++ b/java/res/values-sw600dp/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_klp"
- android:minWidth="32dp"
- android:gravity="center"
-/>
+<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-spacing-and-punctuations.xml b/java/res/values-sw600dp/config-spacing-and-punctuations.xml
new file mode 100644
index 000000000..9c12cf49a
--- /dev/null
+++ b/java/res/values-sw600dp/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" translatable="false">:,;,\",!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,\',-,/,@,_</string>
+</resources>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index e72e4941e..700350c36 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,78 @@
*/
-->
+<!-- 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_gb">2.291%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">4.625%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">2.113%p</fraction>
+ <!-- config_more_keys_keyboard_key_height x -1.0 -->
+ <dimen name="config_more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen>
+ <dimen name="config_key_preview_offset_gb">16.0dp</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-sw540dp/touch-position-correction.xml b/java/res/values-sw600dp/touch-position-correction.xml
index 932b8fc72..932b8fc72 100644
--- a/java/res/values-sw540dp/touch-position-correction.xml
+++ b/java/res/values-sw600dp/touch-position-correction.xml
diff --git a/java/res/values-sw768dp-land/config.xml b/java/res/values-sw768dp-land/config.xml
index b3cd7278d..4040e29f7 100644
--- a/java/res/values-sw768dp-land/config.xml
+++ b/java/res/values-sw768dp-land/config.xml
@@ -18,6 +18,54 @@
*/
-->
+<!-- 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_gb">1.896%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">3.896%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">1.195%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/values-hdpi/config.xml b/java/res/values-sw768dp/config-screen-metrics.xml
index 4cf3562fe..7769ad80d 100644
--- a/java/res/values-hdpi/config.xml
+++ b/java/res/values-sw768dp/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,12 +19,6 @@
-->
<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>
+ <!-- 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..33286c686 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -18,28 +18,76 @@
*/
-->
+<!-- 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_gb">2.291%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">4.687%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">1.272%p</fraction>
+ <!-- config_more_keys_keyboard_key_height x -1.0 -->
+ <dimen name="config_more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen>
+ <dimen name="config_key_preview_offset_gb">16.0dp</dimen>
+
+ <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/config-spacing-and-punctuations.xml
index a9893feec..a9893feec 100644
--- a/java/res/values-th/donottranslate.xml
+++ b/java/res/values-th/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..78342ae70
--- /dev/null
+++ b/java/res/values-th/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"เรียนรู้จากการสื่อสารและข้อมูลที่พิมพ์ของคุณเพื่อปรับปรุงคำแนะนำ"</string>
+</resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 9249c05d5..fe86ff34d 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"ท่าทางสัมผัสสำหรับวลี"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"ใส่ช่องว่างระหว่างท่าทางสัมผัสโดยเลื่อนไปยังแป้นเคาะวรรค"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"กำลังแสดงแป้นพิมพ์ <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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="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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"ภาษาที่คุณเลือกใช้ในอุปกรณ์เคลื่อนที่มีพจนานุกรมที่สามารถใช้ได้&lt;br/&gt; เราขอแนะนำให้คุณ &lt;b&gt;ดาวน์โหลด&lt;/b&gt; พจนานุกรม <xliff:g id="LANGUAGE">%1$s</xliff:g> เพื่อรับประสบการณ์การพิมพ์ที่ดียิ่งขึ้น&lt;br/&gt; &lt;br/&gt;การดาวน์โหลดจะใช้เวลาหนึ่งถึงสองนาทีผ่านทาง 3G ซึ่งอาจมีการเรียกเก็บเงินหากคุณไม่ได้ใช้ &lt;b&gt;แผนบริการข้อมูลแบบไม่จำกัดปริมาณ&lt;/b&gt; &lt;br/&gt;หากคุณไม่แน่ใจว่าคุณใช้แผนบริการข้อมูลแบบใด เราขอแนะนำให้คุณเชื่อมต่อ WiFi เพื่อเริ่มการดาวน์โหลดอัตโนมัติ&lt;br/&gt; &lt;br/&gt;เคล็ดลับ: คุณสามารถดาวน์โหลดและนำพจนานุกรมออกได้โดยไปที่ &lt;b&gt;ภาษาและการป้อนข้อมูล&lt;/b&gt; ในเมนู &lt;b&gt;การตั้งค่า&lt;/b&gt; ในอุปกรณ์เคลื่อนที่ของคุณ"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ภาษาที่คุณเลือกในอุปกรณ์เคลื่อนที่มีพจนานุกรมที่สามารถใช้ได้&lt;br/&gt; เราขอแนะนำให้คุณ &lt;b&gt;ดาวน์โหลด&lt;/b&gt; พจนานุกรม <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> เพื่อรับประสบการณ์การพิมพ์ที่ดียิ่งขึ้น&lt;br/&gt; &lt;br/&gt; การดาวน์โหลดอาจใช้เวลาหนึ่งถึงสองนาทีผ่านทาง 3G ซึ่งอาจมีการเรียกเก็บเงินหากคุณไม่ได้ใช้ &lt;b&gt;แผนบริการข้อมูลแบบไม่จำกัดปริมาณ&lt;/b&gt;.&lt;br/&gt; หากไม่แน่ใจว่าใช้แผนบริการข้อมูลแบบใด เราขอแนะนำให้คุณเชื่อมต่อ Wi-Fi เพื่อเริ่มการดาวน์โหลดอัตโนมัติ&lt;br/&gt; &lt;br/&gt; เคล็ดลับ: คุณสามารถดาวน์โหลดและลบพจนานุกรมออกได้โดยไปที่ &lt;b&gt;ภาษาและการป้อนข้อมูล&lt;/b&gt; ในเมนู &lt;b&gt;การตั้งค่า&lt;/b&gt; ในอุปกรณ์เคลื่อนที่ของคุณ"</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..687f8610f
--- /dev/null
+++ b/java/res/values-tl/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-tl/strings.xml
index df6bda09b..ac3cb1c0e 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"Nagsasagawa ang <xliff:g id="KEY_NAME">%1$s</xliff:g> ng auto-correction"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Ipinapakita ang keyboard na <xliff:g id="KEYBOARD_MODE">%s</xliff:g>"</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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"oras"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Tradisyonal)"</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 +165,16 @@
<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>
+ <!-- no translation found for prefs_dump_contacts_dict (7227327764402323097) -->
+ <skip />
+ <!-- no translation found for prefs_dump_user_dict (294870685041741951) -->
+ <skip />
+ <!-- no translation found for prefs_dump_user_history_dict (6821075152449554628) -->
+ <skip />
+ <!-- no translation found for prefs_dump_personalization_dict (7558387996151745284) -->
+ <skip />
<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 +212,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.&lt;br/&gt; Inirerekomenda namin ang &lt;b&gt;pag-download&lt;/b&gt; sa diksyunaryong <xliff:g id="LANGUAGE">%1$s</xliff:g> upang mapabuti ang iyong karanasan sa pag-type.&lt;br/&gt; &lt;br/&gt; Maaaring umabot ng isa hanggang dalawang minuto ang pag-download gamit ang 3G. Maaaring may malapat na mga pagsingil kung wala kang &lt;b&gt;data plan na walang limitasyon&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tip: Maaari kang mag-download at mag-alis ng mga diksyunaryo sa pamamagitan ng pagpunta sa &lt;b&gt;Wika at input&lt;/b&gt; sa menu na &lt;b&gt;Mga Setting&lt;/b&gt; 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.&lt;br/&gt; Inirerekomenda naming &lt;b&gt;i-download&lt;/b&gt; ang diksyunaryo ng <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> upang pagbutihin ang iyong karanasan sa pagta-type.&lt;br/&gt; &lt;br/&gt; Maaaring magtagal nang ilang minuto ang pag-download sa 3G. Maaaring magkaroon ng mga pagsingil kung wala kang &lt;b&gt;unlimited data plan&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Tip: Maaari kang mag-download at mag-alis ng mga diksyunaryo sa pamamagitan ng pagpunta sa &lt;b&gt;Wika &amp; input&lt;/b&gt; sa menu ng &lt;b&gt;Mga Setting&lt;/b&gt; 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..06c837871
--- /dev/null
+++ b/java/res/values-tr/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Önerileri iyileştirmek için iletişimlerimden ve yazılan verilerden öğren"</string>
+</resources>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index a14295153..b168e8b70 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> otomatik düzeltme yapar"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"<xliff:g id="KEYBOARD_MODE">%s</xliff:g> klavyesi görüntüleniyor"</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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"saat"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Geleneksel)"</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 +165,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 +208,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.&lt;br/&gt; Daha iyi yazabilmek için bu <xliff:g id="LANGUAGE">%1$s</xliff:g> sözlüğü &lt;b&gt;indirmenizi&lt;/b&gt; öneririz.&lt;br/&gt; &lt;br/&gt; İndirme işlemi 3G üzerinden bir veya iki dakika sürebilir. &lt;b&gt;Sınırsız veri planınız&lt;/b&gt; yoksa ücret alınabilir.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; İpucu: Sözlükleri, mobil cihazınızın &lt;b&gt;Ayarlar&lt;/b&gt; menüsünde &lt;b&gt;Dil ve giriş&lt;/b&gt; 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.&lt;br/&gt; Daha iyi yazabilmek için bu <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> sözlüğü &lt;b&gt;indirmenizi&lt;/b&gt; öneririz.&lt;br/&gt; &lt;br/&gt; İndirme işlemi 3G üzerinden bir veya iki dakika sürebilir. &lt;b&gt;Sınırsız veri planınız &lt;/b&gt;yoksa ücret alınabilir.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; İpucu: Sözlükleri, mobil cihazınızın &lt;b&gt;Ayarlar&lt;/b&gt; menüsünde &lt;b&gt;Dil ve giriş&lt;/b&gt; 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..3d6a4e759
--- /dev/null
+++ b/java/res/values-uk/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"Пристрій буде запам’ятовувати, що ви пишете, надсилаєте й отримуєте"</string>
+</resources>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index da26d5005..1ed94ad7a 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"Безперервний ввід фраз"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"Вставляйте пробіли, проводячи пальцем по клавіші пробілу"</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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Режим клавіатури: <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<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">"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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"Для вибраної на вашому мобільному пристрої мови доступний словник.&lt;br/&gt; Радимо &lt;b&gt;завантажити&lt;/b&gt; словник для цієї мови (<xliff:g id="LANGUAGE">%1$s</xliff:g>), щоб покращити введення тексту.&lt;br/&gt; &lt;br/&gt; У мережі 3G завантаження триває 1–2 хвилини. Якщо у вас не &lt;b&gt;безлімітний тарифний план Інтернету&lt;/b&gt;, може стягуватися плата.&lt;br/&gt; Якщо ви не впевнені щодо тарифного плану, радимо скористатися з’єднанням Wi-Fi, щоб автоматично почати завантаження.&lt;br/&gt; &lt;br/&gt; Порада: завантажувати та вилучати словники можна в меню &lt;b&gt;Налаштування&lt;/b&gt; в розділі &lt;b&gt;Мова та введення&lt;/b&gt; вашого мобільного пристрою."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Для вибраної на вашому мобільному пристрої мови доступний словник.&lt;br/&gt; Радимо &lt;b&gt;завантажити&lt;/b&gt; словник для цієї мови (<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>), щоб покращити введення тексту.&lt;br/&gt; &lt;br/&gt; У мережі 3G завантаження триває 1–2 хвилини. Якщо у вас не &lt;b&gt;безлімітний тарифний план Інтернету&lt;/b&gt;, може стягуватися плата.&lt;br/&gt; Якщо ви не впевнені щодо тарифного плану, радимо скористатися з’єднанням Wi-Fi, щоб автоматично почати завантаження.&lt;br/&gt; &lt;br/&gt; Порада: завантажувати та видаляти словники можна в меню &lt;b&gt;Налаштування&lt;/b&gt; в розділі &lt;b&gt;Мова та введення&lt;/b&gt; вашого мобільного пристрою."</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-vi/strings-config-important-notice.xml b/java/res/values-vi/strings-config-important-notice.xml
new file mode 100644
index 000000000..6528f06ed
--- /dev/null
+++ b/java/res/values-vi/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-vi/strings.xml
index 81cd373e4..c0ccc7c52 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"<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="2309828861778711939">"<xliff:g id="KEY_NAME">%1$s</xliff:g> 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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Hiển thị bàn phím <xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"giờ"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Truyền thống)"</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 +165,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">"Lưu và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>
@@ -207,18 +208,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.&lt;br/&gt; Bạn nên &lt;b&gt;tải xuống&lt;/b&gt; 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.&lt;br/&gt; &lt;br/&gt; 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ó &lt;b&gt;gói dữ liệu không giới hạn&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Mẹo: Bạn có thể tải xuống và xóa từ điển bằng cách đi tới &lt;b&gt;Ngôn ngữ và nhập&lt;/b&gt; trong trình đơn &lt;b&gt;Cài đặt&lt;/b&gt; 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.&lt;br/&gt; Bạn nên &lt;b&gt;tải xuống&lt;/b&gt; 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.&lt;br/&gt; &lt;br/&gt; 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ó &lt;b&gt;gói dữ liệu không giới hạn&lt;/b&gt;.&lt;br/&gt; 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.&lt;br/&gt; &lt;br/&gt; Mẹo: Bạn có thể tải xuống và xóa từ điển bằng cách đi tới &lt;b&gt;Ngôn ngữ và nhập&lt;/b&gt; trong trình đơn &lt;b&gt;Cài đặt&lt;/b&gt; 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..2ffe7d953
--- /dev/null
+++ b/java/res/values-zh-rCN/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根据您的通信记录和以往输入的数据来完善建议"</string>
+</resources>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index d347c9ce8..c36362452 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"词组滑行输入"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"滑行输入时,滑过空格键即可输入空格"</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_auto_correct" msgid="5150455215290003221">"按<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="2309828861778711939">"按<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"当前显示的是<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"时间"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"网址"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"支持您移动设备上所选语言的词典现已可供下载啦!&lt;br/&gt;建议您&lt;b&gt;下载&lt;/b&gt;这部<xliff:g id="LANGUAGE">%1$s</xliff:g>词典,以享受更好的输入体验。&lt;br/&gt;&lt;br/&gt;通过 3G 进行下载可能需要 1 到 2 分钟的时间。如果您使用的不是&lt;b&gt;无流量限制的套餐&lt;/b&gt;,则可能需要支付一定的费用。&lt;br/&gt;如果您不确定自己使用的是哪种流量套餐,建议您使用 WLAN 连接自动开始下载。&lt;br/&gt;&lt;br/&gt;提示:您可以访问移动设备的&lt;b&gt;设置&lt;/b&gt;菜单中的&lt;b&gt;语言和输入法&lt;/b&gt;,来下载和删除词典。"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的移动设备上选择的语言有一个词典可供下载。&lt;br/&gt;我们建议您&lt;b&gt;下载&lt;/b&gt;这个<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>词典,以便获得更好的输入体验。&lt;br/&gt;&lt;br/&gt;通过3G网络下载可能需要一两分钟的时间。如果您使用的不是&lt;b&gt;无流量限制的套餐&lt;/b&gt;,则可能产生一定的流量费。&lt;br/&gt;如果您不确定自己使用的是哪种流量套餐,我们建议您连接到WLAN网络以便自动开始下载。&lt;br/&gt;&lt;br/&gt;提示:您可以在移动设备上的&lt;b&gt;语言和输入法&lt;/b&gt;部分(位于&lt;b&gt;设置&lt;/b&gt;菜单中)下载和删除词典。"</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..9e80655a3
--- /dev/null
+++ b/java/res/values-zh-rHK/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根據您的通訊記錄和已輸入的資料改善建議"</string>
+</resources>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index 306045591..806f73f48 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"詞組手勢"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"在手勢輸入過程中,滑過空白鍵即可輸入空格"</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_auto_correct" msgid="5150455215290003221">"按「<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="2309828861778711939">"按「<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"目前顯示的是<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"您的流動裝置所選取的語言現有字典可供使用。&lt;br/&gt;建議您&lt;b&gt;下載&lt;/b&gt;<xliff:g id="LANGUAGE">%1$s</xliff:g>字典,讓您輸入時更方便。&lt;br/&gt;&lt;br/&gt;經由 3G 網絡下載需時一兩分鐘。如果您未使用&lt;b&gt;無限上網計劃&lt;/b&gt;,可能須另外付費。&lt;br/&gt;如果您不確定自己使用哪種上網計劃,建議您在連接 Wi-Fi 網絡後才開始自動下載。&lt;br/&gt;&lt;br/&gt;提示:您可以前往流動裝置的 [設定] &lt;b&gt;&lt;/b&gt;選單,透過其中的 [語言和輸入] &lt;b&gt;&lt;/b&gt;下載和移除字典。"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的流動裝置所選取的語言現有字典可供使用。&lt;br/&gt;我們建議您&lt;b&gt;下載&lt;/b&gt;<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典,讓您輸入時更方便。&lt;br/&gt;&lt;br/&gt;經由 3G 網絡下載需時一、兩分鐘。如果您未使用&lt;b&gt;無限上網計劃&lt;/b&gt;,可能須另外付費。&lt;br/&gt;如果您不確定自己使用哪種上網計劃,我們建議您在連接 Wi-Fi 網絡後才開始自動下載。&lt;br/&gt;&lt;br/&gt;提示:您可以前往流動裝置的 [設定] &lt;b&gt;&lt;/b&gt;選單,透過其中的 [語言和輸入] &lt;b&gt;&lt;/b&gt;下載和移除字典。"</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..f1bdc7774
--- /dev/null
+++ b/java/res/values-zh-rTW/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <string name="use_personalized_dicts_summary" msgid="590432261305469627">"根據您的通訊紀錄和以往輸入的資料改善建議項目"</string>
+</resources>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 2c474b79e..8a56f2810 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,12 +74,13 @@
<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="gesture_space_aware" msgid="2078291600664682496">"詞組手勢"</string>
+ <string name="gesture_space_aware_summary" msgid="4371385818348528538">"手勢輸入時,滑過空格鍵即可輸入空格"</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_auto_correct" msgid="5150455215290003221">"按下「<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="2309828861778711939">"按下「<xliff:g id="KEY_NAME">%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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"目前顯示的是<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"<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 +165,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 +208,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">"您的行動裝置設定的語言,現有字典可供使用。&lt;br/&gt; 建議您&lt;b&gt;下載&lt;/b&gt;<xliff:g id="LANGUAGE">%1$s</xliff:g>字典,加強輸入功能。&lt;br/&gt; &lt;br/&gt; 透過 3G 網路下載約需一兩分鐘。若無&lt;b&gt;無限行動上網資費方案&lt;/b&gt;,可能必須另外付費。&lt;br/&gt;若不確定行動上網資費方案為何,可以等連上 Wi-Fi 網路後再自動下載。&lt;br/&gt; &lt;br/&gt;提示:進入行動裝置的 [設定] 選單,選擇 [語言和輸入] 即可下載及移除字典。&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;"</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"您的行動裝置選用的語言現有字典可供使用。&lt;br/&gt;建議您&lt;b&gt;下載&lt;/b&gt;<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>字典,藉此強化輸入功能。&lt;br/&gt;&lt;br/&gt;透過 3G 網路下載約需一兩分鐘。如果沒有&lt;b&gt;無限行動上網資費方案&lt;/b&gt;,可能必須另外付費。&lt;br/&gt;若不確定行動上網資費方案為何,可以等連上 Wi-Fi 網路後再自動下載。&lt;br/&gt;&lt;br/&gt;提示:前往行動裝置的 [設定] 選單,選擇 [語言和輸入] 即可下載及移除字典。&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;"</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..95d5a290c
--- /dev/null
+++ b/java/res/values-zu/strings-config-important-notice.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="important_notice_title" msgid="1836002733109536160"></string>
+ <string name="important_notice_contents" msgid="897137043719116217"></string>
+ <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.xml b/java/res/values-zu/strings.xml
index 27d11316c..42430ba27 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,12 +74,13 @@
<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="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="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_auto_correct" msgid="5150455215290003221">"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="2309828861778711939">"I-<xliff:g id="KEY_NAME">%1$s</xliff:g> yenza ukulungisa okuzenzakalelayo"</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>
@@ -106,7 +108,7 @@
<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="announce_keyboard_mode" msgid="7486740369324538848">"Ibonisa ikhibhodi ye-<xliff:g id="KEYBOARD_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>
@@ -117,12 +119,7 @@
<string name="keyboard_mode_time" msgid="4381856885582143277">"isikhathi"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"I-URL"</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 +132,10 @@
<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_nepali_traditional" msgid="1994571919751163596">"Isi-<xliff:g id="LANGUAGE_NAME">%s</xliff:g> (Eyosiko)"</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 +165,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">"Lahla 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 +208,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.&lt;br/&gt; Sincoma &lt;b&gt;ukulanda&lt;/b&gt; isichazamazwi sesi-<xliff:g id="LANGUAGE">%1$s</xliff:g> ukwenza kangcono isipiliyoni sakho sokuthayipha.&lt;br/&gt; &lt;br/&gt; Ukulanda ukungathatha iminithi noma amaminithi amabili nge-3G. Amashaja angasebenza uma ungenalo &lt;b&gt;icebo ledatha elinganqunyelwe&lt;/b&gt;.&lt;br/&gt; Uma ungenasiqinisekiso sokuthi iliphi icebo ledatha onalo, sincoma ukuthola uxhumo lwe-Wi-Fi ukuze uqale ukulanda ngokuzenzakalelayo.&lt;br/&gt; &lt;br/&gt; Ithiphu: Ungalanda futhi ususe izichazamazwi ngokuya ku-&lt;b&gt;Ulimi nokungenayo&lt;/b&gt; kumenyu ye-&lt;b&gt;Izilungiselelo&lt;/b&gt; yedivayisi yakho yeselula."</string>
+ <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"Ulimi olukhethiwe kudivayisi yakho yeselula lunesichazamazwi esitholakalayo.&lt;br/&gt; Sincoma &lt;b&gt;ukulanda&lt;/b&gt; isichazamazwi se-<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ukuze sithuthukise umuzwa wakho wokuthayipha.&lt;br/&gt; &lt;br/&gt; Ukulanda kungathatha iminithi noma amabili ngaphezulu kwe-3G. Ukukhokhiswa kungasebenza uma unganalo &lt;b&gt;uhlelo lwedatha elingenamkhawulo&lt;/b&gt;.&lt;br/&gt; Uma ungenaso isiqiniseko sokuthi ukuliphi uhlelo lwedatha, sincoma ukuthi uthole ukuxhumeka kwe-Wi-Fi ukuze uqale ukulanda ngokuzenzakalela.&lt;br/&gt; &lt;br/&gt; Ithiphu: Ungalanda uphinde ususe izichazamazwi ngokuya ku-&lt;b&gt;Ulimi nokokufaka&lt;/b&gt; kumenyu ye-&lt;b&gt;Izilungiselelo&lt;/b&gt; 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..055060642 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 -->
@@ -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/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..20d5860e3
--- /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 is an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. -->
+ <string name="config_default_keyboard_theme_index" 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/config-spacing-and-punctuations.xml b/java/res/values/config-spacing-and-punctuations.xml
new file mode 100644
index 000000000..1dd2e1f6b
--- /dev/null
+++ b/java/res/values/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" translatable="false">!,?,\\,,:,;,\",!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,\',-,/,@,_</string>
+ <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
+ <string name="symbols_preceded_by_space" translatable="false">([{&amp;</string>
+ <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
+ <string name="symbols_followed_by_space" translatable="false">.,;:!?)]}&amp;</string>
+ <!-- Symbols that separate words -->
+ <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
+ <string name="symbols_word_separators" translatable="false">"&#x0009;&#x0020;&#x000A;&#x00A0;"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
+ <!-- Word connectors -->
+ <string name="symbols_word_connectors" translatable="false">\'-</string>
+ <!-- The sentence separator code point, for capitalization -->
+ <!-- U+002E: "." FULL STOP ; 2Eh = 46d -->
+ <integer name="sentence_separator" translatable="false">46</integer>
+ <!-- Whether this language uses spaces between words -->
+ <bool name="current_language_has_spaces">true</bool>
+</resources>
diff --git a/java/res/values/config-spellchecker-thresholds.xml b/java/res/values/config-spellchecker-thresholds.xml
new file mode 100644
index 000000000..e99ba6621
--- /dev/null
+++ b/java/res/values/config-spellchecker-thresholds.xml
@@ -0,0 +1,25 @@
+<?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>
+ <!-- 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..e64b4b192 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -18,120 +18,79 @@
*/
-->
+<!-- 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_gb">1.556%p</fraction>
+ <fraction name="config_keyboard_bottom_padding_gb">4.669%p</fraction>
+ <fraction name="config_key_vertical_gap_gb">6.495%p</fraction>
+ <fraction name="config_key_horizontal_gap_gb">1.971%p</fraction>
+ <!-- config_more_keys_keyboard_key_height x -1.0 -->
+ <dimen name="config_more_keys_keyboard_vertical_correction_gb">-52.8dp</dimen>
+ <dimen name="config_key_preview_offset_gb">-8.0dp</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.xml b/java/res/values/donottranslate.xml
index af5ec061b..4be5863f2 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">([{&amp;</string>
- <!-- Symbols that are normally followed by a space (used to add an auto-space after these) -->
- <string name="symbols_followed_by_space">.,;:!?)]}&amp;</string>
- <!-- Symbols that separate words -->
- <!-- Don't remove the enclosing double quotes, they protect whitespace (not just U+0020) -->
- <string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</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,43 +38,9 @@
<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>
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/strings-config-important-notice.xml b/java/res/values/strings-config-important-notice.xml
new file mode 100644
index 000000000..f2229bec4
--- /dev/null
+++ b/java/res/values/strings-config-important-notice.xml
@@ -0,0 +1,33 @@
+<?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>
+ <!-- The array of the text of the important notices displayed on the suggestion strip. -->
+ <string-array name="important_notice_title_array">
+ <!-- empty -->
+ </string-array>
+ <!-- The array of the contents of the important notices. -->
+ <string-array name="important_notice_contents_array">
+ <!-- empty -->
+ </string-array>
+ <!-- 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.xml b/java/res/values/strings.xml
index 11b3ea3af..ddff7697c 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,9 +150,10 @@
<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>
+ <!-- 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>
<!-- 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>
@@ -160,9 +164,9 @@
<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>
+ <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" example="Space">%1$s</xliff:g> performs auto-correction</string>
+ <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>
@@ -222,7 +226,7 @@
<!-- 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>
+ <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. -->
@@ -244,21 +248,8 @@
<!-- 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 &amp; input settings.</string>
<!-- Title for configuring input method settings [CHAR LIMIT=35] -->
<string name="configure_input_method">Configure input methods</string>
@@ -354,15 +345,15 @@
<string name="subtype_es_US">Spanish (US)</string>
<!-- Description for English (United Kingdom) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25]
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>
+ <string name="subtype_with_layout_en_GB">English (UK) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string>
<!-- Description for English (United States) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25]
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>
+ <string name="subtype_with_layout_en_US">English (US) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string>
<!-- Description for Spanish (United States) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25]
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>
+ <string name="subtype_with_layout_es_US">Spanish (US) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%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>
+ <string name="subtype_nepali_traditional"><xliff:g id="LANGUAGE_NAME" example="Nepali">%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>
@@ -370,7 +361,7 @@
<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_sr-Latn">Serbian (Latin) (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</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
@@ -480,7 +471,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 +481,40 @@ 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 +522,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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 +546,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 +597,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&#x2026;</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 +616,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.&lt;br/>
-We recommend &lt;b>downloading&lt;/b> the <xliff:g id="language" example="English">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/>
+We recommend &lt;b>downloading&lt;/b> the <xliff:g id="LANGUAGE_NAME" example="English">%1$s</xliff:g> dictionary to improve your typing experience.&lt;br/>
&lt;br/>
The download could take a minute or two over 3G. Charges may apply if you don\'t have an &lt;b>unlimited data plan&lt;/b>.&lt;br/>
If you are not sure which data plan you have, we recommend finding a Wi-Fi connection to start the download automatically.&lt;br/>
&lt;br/>
Tip: You can download and remove dictionaries by going to &lt;b>Language &amp; input&lt;/b> in the &lt;b>Settings&lt;/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
index f52695f55..a460d4f7f 100644
--- a/java/res/values/themes-gb.xml
+++ b/java/res/values/themes-gb.xml
@@ -23,10 +23,10 @@
<item name="keyboardStyle">@style/Keyboard.GB</item>
<item name="keyboardViewStyle">@style/KeyboardView.GB</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.GB</item>
+ <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.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>
@@ -40,7 +40,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_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 -->
@@ -59,10 +58,10 @@
<!-- 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>
+ <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_gb</item>
+ <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_gb</item>
+ <item name="horizontalGap">@fraction/config_key_horizontal_gap_gb</item>
+ <item name="verticalGap">@fraction/config_key_vertical_gap_gb</item>
</style>
<style
name="KeyboardView.GB"
@@ -85,16 +84,22 @@
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="keyPreviewOffset">@dimen/config_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>
+ <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_gb</item>
+ <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_gb</item>
+ <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_gb</item>
+ </style>
+ <style
+ name="KeyPreviewTextView.GB"
+ parent="KeyPreviewTextView"
+ >
+ <item name="android:background">@drawable/keyboard_key_feedback_gb</item>
</style>
<!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it,
for instance delete button, need themed {@link KeyboardView} attributes. -->
@@ -118,15 +123,10 @@
name="MoreKeysKeyboardView.GB"
parent="KeyboardView.GB"
>
- <item name="android:background">@null</item>
+ <item name="android:background">@drawable/keyboard_popup_panel_background_gb</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>
+ <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_gb</item>
</style>
<style
name="SuggestionStripView.GB"
@@ -140,7 +140,11 @@
<item name="colorSuggested">@color/highlight_color_gb</item>
<item name="alphaObsoleted">50%</item>
</style>
- <style name="SuggestionWord.GB">
+ <style
+ name="SuggestionWord.GB"
+ parent="SuggestionWord"
+ >
<item name="android:background">@drawable/btn_suggestion_gb</item>
+ <item name="android:textColor">@color/highlight_color_gb</item>
</style>
</resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 432ad5122..caea92186 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,15 +102,10 @@
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"
@@ -118,7 +119,11 @@
<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..0599fb65e 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,15 +102,10 @@
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"
@@ -118,7 +119,11 @@
<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/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_azerty3_right.xml b/java/res/xml-sw600dp/key_azerty3_right.xml
index a5a6e9526..25b0e52b8 100644
--- a/java/res/xml-sw600dp/key_azerty3_right.xml
+++ b/java/res/xml-sw600dp/key_azerty3_right.xml
@@ -22,7 +22,7 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel=":"
+ latin:keySpec=":"
latin:keyHintLabel=";"
latin:moreKeys=";"
latin:keyStyle="hasShiftedLetterHintStyle" />
diff --git a/java/res/xml-sw600dp/key_colemak_colon.xml b/java/res/xml-sw600dp/key_colemak_colon.xml
index a5a6e9526..25b0e52b8 100644
--- a/java/res/xml-sw600dp/key_colemak_colon.xml
+++ b/java/res/xml-sw600dp/key_colemak_colon.xml
@@ -22,7 +22,7 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel=":"
+ latin:keySpec=":"
latin:keyHintLabel=";"
latin:moreKeys=";"
latin:keyStyle="hasShiftedLetterHintStyle" />
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_greek_semicolon.xml b/java/res/xml-sw600dp/key_greek_semicolon.xml
index 3f09419b1..9e2c1fad0 100644
--- a/java/res/xml-sw600dp/key_greek_semicolon.xml
+++ b/java/res/xml-sw600dp/key_greek_semicolon.xml
@@ -22,7 +22,7 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel=";"
+ latin:keySpec=";"
latin:keyHintLabel=":"
latin:moreKeys=":"
latin:keyStyle="hasShiftedLetterHintStyle" />
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..c869e745b 100644
--- a/java/res/xml-sw600dp/key_shortcut.xml
+++ b/java/res/xml-sw600dp/key_shortcut.xml
@@ -23,7 +23,7 @@
>
<switch>
<case
- latin:shortcutKeyEnabled="true"
+ latin:supportsSwitchingToShortcutIme="true"
latin:clobberSettingsKey="false"
>
<Key
@@ -32,20 +32,20 @@
latin:moreKeys="!text/settings_as_more_key" />
</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_symbols.xml b/java/res/xml-sw600dp/key_space_symbols.xml
index 07aa7d179..d6f7cab09 100644
--- a/java/res/xml-sw600dp/key_space_symbols.xml
+++ b/java/res/xml-sw600dp/key_space_symbols.xml
@@ -22,5 +22,6 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<include
+ latin:backgroundType="normal"
latin:keyboardLayout="@xml/key_space_5kw" />
</merge>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index d817add11..aa64f85b3 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|&#x200C;"
latin:moreKeys="!icon/zwj_key|&#x200D;"
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/label_to_symbol_key|!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/label_to_alpha_key|!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/label_to_more_symbol_for_tablet_key|!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/label_to_symbol_key|!code/key_shift"
latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="comKeyStyle"
- latin:keyLabel="!text/keylabel_for_popular_domain"
+ latin:keySpec="!text/keylabel_for_popular_domain"
latin:keyLabelFlags="autoXScale|fontNormal|hasPopupHint|preserveCase"
- latin:keyOutputText="!text/keylabel_for_popular_domain"
latin:moreKeys="!text/more_keys_for_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..38a38fd45 100644
--- a/java/res/xml-sw600dp/key_styles_enter.xml
+++ b/java/res/xml-sw600dp/key_styles_enter.xml
@@ -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="!text/label_go_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="&#x0630;"
+ latin:keySpec="&#x0630;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x0626;"
+ latin:keySpec="&#x0626;"
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..eda96b288 100644
--- a/java/res/xml-sw600dp/keys_comma_period.xml
+++ b/java/res/xml-sw600dp/keys_comma_period.xml
@@ -21,83 +21,18 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:mode="email|url"
- >
- <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: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="&#x055D;"
- latin:backgroundType="functional" />
- <!-- U+0589: "։" ARMENIAN FULL STOP -->
- <Key
- latin:keyLabel="&#x0589;"
- 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>
+ <Key
+ latin:keySpec="!text/keylabel_for_tablet_comma"
+ latin:keyHintLabel="!text/keyhintlabel_for_tablet_comma"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:moreKeys="!text/more_keys_for_tablet_comma"
+ latin:backgroundType="functional"
+ latin:keyStyle="hasShiftedLetterHintStyle" />
+ <Key
+ latin:keySpec="!text/keylabel_for_tablet_period"
+ latin:keyHintLabel="!text/keyhintlabel_for_tablet_period"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:moreKeys="!text/more_keys_for_tablet_period"
+ latin:backgroundType="functional"
+ latin:keyStyle="hasShiftedLetterHintStyle" />
</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="&quot;"
+ latin:keySpec="&quot;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<Key
- latin:keyLabel="&lt;"
+ latin:keySpec="&lt;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<Key
- latin:keyLabel="&gt;"
+ latin:keySpec="&gt;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
</case>
<default>
<Key
- latin:keyLabel="\'"
+ latin:keySpec="\'"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:moreKeys="!,&quot;" />
<Key
- latin:keyLabel=","
+ latin:keySpec=","
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="\?,&lt;" />
<Key
- latin:keyLabel="."
+ latin:keySpec="."
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&gt;" />
diff --git a/java/res/xml-sw600dp/keys_exclamation_question.xml b/java/res/xml-sw600dp/keys_exclamation_question.xml
index cd38282ee..116bef2be 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/more_keys_for_exclamation" />
<Key
- latin:keyLabel="\?" />
+ latin:keySpec="\?"
+ latin:moreKeys="!text/more_keys_for_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="&#x0622;"
+ latin:keySpec="&#x0622;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0686: "چ" ARABIC LETTER TCHEH -->
<Key
- latin:keyLabel="&#x0686;"
+ latin:keySpec="&#x0686;"
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..ab99ec574 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
@@ -26,17 +26,17 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<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..54433964f 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
@@ -26,12 +26,12 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
- latin:keyLabel=";"
+ latin:keySpec=";"
latin:keyHintLabel=":"
latin:additionalMoreKeys=":"
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
- latin:keyLabel="\'"
+ latin:keySpec="\'"
latin:keyHintLabel="&quot;"
latin:additionalMoreKeys="&quot;"
latin:keyStyle="hasShiftedLetterHintStyle"
@@ -40,9 +40,9 @@
<!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<Key
- latin:keyLabel=":" />
+ latin:keySpec=":" />
<Key
- latin:keyLabel="&quot;"
+ latin:keySpec="&quot;"
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..c95ca2ee7 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
@@ -26,21 +26,21 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
- latin:keyLabel=","
+ latin:keySpec=","
latin:keyHintLabel="&lt;"
latin:additionalMoreKeys="&lt;"
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
- latin:keyLabel="."
+ latin:keySpec="."
latin:keyHintLabel="&gt;"
latin:additionalMoreKeys="&gt;"
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/more_keys_for_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="&lt;"
+ latin:keySpec="&lt;"
latin:moreKeys="!fixedColumnOrder!3,&#x2039;,&#x2264;,&#x00AB;" />
<Key
- latin:keyLabel="&gt;"
+ latin:keySpec="&gt;"
latin:moreKeys="!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;" />
<Key
- latin:keyLabel="\?"
- latin:moreKeys="!text/more_keys_for_symbols_question" />
+ latin:keySpec="\?"
+ latin:moreKeys="!text/more_keys_for_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/rowkeys_dvorak3.xml b/java/res/xml-sw600dp/rowkeys_dvorak3.xml
index 2148bb2c7..edc68a3af 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:keySpec="j"
latin:moreKeys="!text/more_keys_for_j" />
<Key
- latin:keyLabel="k"
+ latin:keySpec="k"
latin:moreKeys="!text/more_keys_for_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:keySpec="w"
latin:moreKeys="!text/more_keys_for_w" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
<Key
- latin:keyLabel="z"
+ latin:keySpec="z"
latin:moreKeys="!text/more_keys_for_z" />
</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
index 254d3fdba..5389e2201 100644
--- a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
+++ b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
@@ -22,66 +22,66 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel="`"
+ latin:keySpec="`"
latin:keyHintLabel="~"
latin:additionalMoreKeys="~"
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
- latin:keyLabel="1"
+ latin:keySpec="1"
latin:keyHintLabel="!"
latin:additionalMoreKeys="!"
latin:keyStyle="hasShiftedLetterHintStyle"
- latin:moreKeys="!text/more_keys_for_symbols_exclamation,!text/more_keys_for_symbols_1" />
+ latin:moreKeys="!text/more_keys_for_exclamation,!text/more_keys_for_symbols_1" />
<Key
- latin:keyLabel="2"
+ latin:keySpec="2"
latin:keyHintLabel="\@"
latin:additionalMoreKeys="\@"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_2" />
<Key
- latin:keyLabel="3"
+ latin:keySpec="3"
latin:keyHintLabel="\#"
latin:additionalMoreKeys="\#"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_3" />
<Key
- latin:keyLabel="4"
+ latin:keySpec="4"
latin:keyHintLabel="$"
latin:additionalMoreKeys="$"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_4" />
<Key
- latin:keyLabel="5"
+ latin:keySpec="5"
latin:keyHintLabel="%"
latin:additionalMoreKeys="\\%"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_5" />
<Key
- latin:keyLabel="6"
+ latin:keySpec="6"
latin:keyHintLabel="^"
latin:additionalMoreKeys="^"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_6" />
<Key
- latin:keyLabel="7"
+ latin:keySpec="7"
latin:keyHintLabel="&amp;"
latin:additionalMoreKeys="&amp;"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_7" />
<Key
- latin:keyLabel="8"
+ latin:keySpec="8"
latin:keyHintLabel="*"
latin:additionalMoreKeys="*"
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_8" />
<Key
- latin:keyLabel="9"
+ latin:keySpec="9"
latin:keyHintLabel="("
latin:additionalMoreKeys="("
latin:keyStyle="hasShiftedLetterHintStyle"
latin:moreKeys="!text/more_keys_for_symbols_9" />
<Key
- latin:keyLabel="0"
+ latin:keySpec="0"
latin:keyHintLabel=")"
latin:additionalMoreKeys=")"
latin:keyStyle="hasShiftedLetterHintStyle"
@@ -90,7 +90,7 @@
U+2014: "—" EM DASH
U+00B7: "·" MIDDLE DOT -->
<Key
- latin:keyLabel="-"
+ latin:keySpec="-"
latin:keyHintLabel="_"
latin:additionalMoreKeys="_"
latin:keyStyle="hasShiftedLetterHintStyle"
@@ -99,7 +99,7 @@
U+2260: "≠" NOT EQUAL TO
U+2248: "≈" ALMOST EQUAL TO -->
<Key
- latin:keyLabel="="
+ latin:keySpec="="
latin:keyHintLabel="+"
latin:additionalMoreKeys="+"
latin:keyStyle="hasShiftedLetterHintStyle"
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_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index 37bf2e808..15f4cde08 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,7 +67,7 @@
latin:mode="time|datetime"
>
<Key
- latin:keyLabel=","
+ latin:keySpec=","
latin:keyLabelFlags="hasPopupHint"
latin:moreKeys="!text/more_keys_for_am_pm"
latin:keyStyle="numKeyStyle"
@@ -76,21 +76,21 @@
</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_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="&#x00A1;" />
+ latin:keySpec="&#x00A1;" />
<!-- U+00BF: "¿" INVERTED QUESTION MARK -->
<Key
- latin:keyLabel="&#x00BF;" />
+ latin:keySpec="&#x00BF;" />
<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/key_devanagari_sign_anusvara.xml b/java/res/xml-v16/key_devanagari_sign_anusvara.xml
index 27c7bff5a..ee0f21dad 100644
--- a/java/res/xml-v16/key_devanagari_sign_anusvara.xml
+++ b/java/res/xml-v16/key_devanagari_sign_anusvara.xml
@@ -27,6 +27,6 @@
>
<!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x0902;"
+ latin:keySpec="&#x0902;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/key_devanagari_sign_candrabindu.xml b/java/res/xml-v16/key_devanagari_sign_candrabindu.xml
index 03017dd78..29f41d143 100644
--- a/java/res/xml-v16/key_devanagari_sign_candrabindu.xml
+++ b/java/res/xml-v16/key_devanagari_sign_candrabindu.xml
@@ -43,6 +43,6 @@
<!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU -->
<Key
latin:keyStyle="moreKeysDevanagariSignCandrabindu"
- latin:keyLabel="&#x0901;"
+ latin:keySpec="&#x0901;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/key_devanagari_sign_nukta.xml b/java/res/xml-v16/key_devanagari_sign_nukta.xml
index 09c347706..915779524 100644
--- a/java/res/xml-v16/key_devanagari_sign_nukta.xml
+++ b/java/res/xml-v16/key_devanagari_sign_nukta.xml
@@ -44,6 +44,6 @@
<!-- U+093C: "़" DEVANAGARI SIGN NUKTA -->
<Key
latin:keyStyle="moreKeysDevanagariSignNukta"
- latin:keyLabel="&#x093C;"
+ latin:keySpec="&#x093C;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml b/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml
index 0316a7bde..2f1739948 100644
--- a/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml
+++ b/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml
@@ -27,6 +27,6 @@
>
<!-- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O -->
<Key
- latin:keyLabel="&#x0949;"
+ latin:keySpec="&#x0949;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml b/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml
index 4dd3e85cc..dc7a0e090 100644
--- a/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml
+++ b/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml
@@ -50,6 +50,6 @@
<!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R -->
<Key
latin:keyStyle="moreKeysDevanagariVowelSignVocalicR"
- latin:keyLabel="&#x0943;"
+ latin:keySpec="&#x0943;"
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..764fb1fbb 100644
--- a/java/res/xml-v16/keystyle_devanagari_sign_virama.xml
+++ b/java/res/xml-v16/keystyle_devanagari_sign_virama.xml
@@ -28,6 +28,6 @@
<!-- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
<key-style
latin:styleName="baseKeyDevanagariSignVirama"
- latin:keyLabel="&#x094D;"
+ latin:keySpec="&#x094D;"
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="&#x0903;"
+ latin:keySpec="&#x0903;"
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..fe9264b78 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml
@@ -44,6 +44,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAa"
latin:parentStyle="moreKeysDevanagariVowelSignAa"
- latin:keyLabel="&#x093E;"
+ latin:keySpec="&#x093E;"
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..fdb53bb2c 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml
@@ -51,6 +51,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAi"
latin:parentStyle="moreKeysDevanagariVowelSignAi"
- latin:keyLabel="&#x0948;"
+ latin:keySpec="&#x0948;"
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..653e79e0f 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml
@@ -43,6 +43,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAu"
latin:parentStyle="moreKeysDevanagariVowelSignAu"
- latin:keyLabel="&#x094C;"
+ latin:keySpec="&#x094C;"
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..7240a2ca1 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml
@@ -52,6 +52,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignE"
latin:parentStyle="moreKeysDevanagariVowelSignE"
- latin:keyLabel="&#x0947;"
+ latin:keySpec="&#x0947;"
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..5a006f033 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml
@@ -43,6 +43,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignI"
latin:parentStyle="moreKeysDevanagariVowelSignI"
- latin:keyLabel="&#x093F;"
+ latin:keySpec="&#x093F;"
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..a2b07fe5a 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml
@@ -43,6 +43,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignIi"
latin:parentStyle="moreKeysDevanagariVowelSignIi"
- latin:keyLabel="&#x0940;"
+ latin:keySpec="&#x0940;"
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..4b764cdee 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml
@@ -45,6 +45,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignO"
latin:parentStyle="moreKeysDevanagariVowelSignO"
- latin:keyLabel="&#x094B;"
+ latin:keySpec="&#x094B;"
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..18d485afe 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml
@@ -44,6 +44,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignU"
latin:parentStyle="moreKeysDevanagariVowelSignU"
- latin:keyLabel="&#x0941;"
+ latin:keySpec="&#x0941;"
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..d770ee6c5 100644
--- a/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml
@@ -44,6 +44,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignUu"
latin:parentStyle="moreKeysDevanagariVowelSignUu"
- latin:keyLabel="&#x0942;"
+ latin:keySpec="&#x0942;"
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/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_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/layout/suggestion_info.xml b/java/res/xml/kbd_swiss.xml
index 0aa26000d..c64ad1103 100644
--- a/java/res/layout/suggestion_info.xml
+++ b/java/res/xml/kbd_swiss.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,9 @@
*/
-->
-<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" />
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <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="&#x0577;"
+ latin:keySpec="&#x0577;"
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="&#x056D;"
+ latin:keySpec="&#x056D;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/key_azerty3_right.xml b/java/res/xml/key_azerty3_right.xml
index 65789ea69..85a066613 100644
--- a/java/res/xml/key_azerty3_right.xml
+++ b/java/res/xml/key_azerty3_right.xml
@@ -26,11 +26,11 @@
latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
>
<Key
- latin:keyLabel="\?" />
+ latin:keySpec="\?" />
</case>
<default>
<Key
- latin:keyLabel="\'"
+ latin:keySpec="\'"
latin:moreKeys="!text/more_keys_for_single_quote" />
</default>
</switch>
diff --git a/java/res/xml/key_colemak_colon.xml b/java/res/xml/key_colemak_colon.xml
index 307b4ebca..9330be9a5 100644
--- a/java/res/xml/key_colemak_colon.xml
+++ b/java/res/xml/key_colemak_colon.xml
@@ -26,13 +26,13 @@
latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
>
<Key
- latin:keyLabel=";"
+ latin:keySpec=";"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
</case>
<default>
<Key
- latin:keyLabel=":"
+ latin:keySpec=":"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0"
latin:moreKeys=";" />
diff --git a/java/res/xml/key_devanagari_sign_anusvara.xml b/java/res/xml/key_devanagari_sign_anusvara.xml
index 0acd3bcd4..5d7c01890 100644
--- a/java/res/xml/key_devanagari_sign_anusvara.xml
+++ b/java/res/xml/key_devanagari_sign_anusvara.xml
@@ -28,7 +28,6 @@
<!-- U+25CC: "◌" DOTTED CIRCLE
U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x25CC;&#x0902;"
- latin:code="0x0902"
+ latin:keySpec="&#x25CC;&#x0902;|&#x0902;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_devanagari_sign_candrabindu.xml b/java/res/xml/key_devanagari_sign_candrabindu.xml
index df0c4e054..9e9c371a7 100644
--- a/java/res/xml/key_devanagari_sign_candrabindu.xml
+++ b/java/res/xml/key_devanagari_sign_candrabindu.xml
@@ -44,7 +44,6 @@
U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU -->
<Key
latin:keyStyle="moreKeysDevanagariSignCandrabindu"
- latin:keyLabel="&#x25CC;&#x0901;"
- latin:code="0x0901"
+ latin:keySpec="&#x25CC;&#x0901;|&#x0901;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_devanagari_sign_nukta.xml b/java/res/xml/key_devanagari_sign_nukta.xml
index f7a03ee90..b56eb0af3 100644
--- a/java/res/xml/key_devanagari_sign_nukta.xml
+++ b/java/res/xml/key_devanagari_sign_nukta.xml
@@ -46,7 +46,6 @@
U+093C: "़" DEVANAGARI SIGN NUKTA -->
<Key
latin:keyStyle="moreKeysDevanagariSignNukta"
- latin:keyLabel="&#x25CC;&#x093C;"
- latin:code="0x093C"
+ latin:keySpec="&#x25CC;&#x093C;|&#x093C;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_devanagari_vowel_sign_candra_o.xml b/java/res/xml/key_devanagari_vowel_sign_candra_o.xml
index 370fc5405..6d7d000b3 100644
--- a/java/res/xml/key_devanagari_vowel_sign_candra_o.xml
+++ b/java/res/xml/key_devanagari_vowel_sign_candra_o.xml
@@ -28,7 +28,6 @@
<!-- U+25CC: "◌" DOTTED CIRCLE
U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O -->
<Key
- latin:keyLabel="&#x25CC;&#x0949;"
- latin:code="0x0949"
+ latin:keySpec="&#x25CC;&#x0949;|&#x0949;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml b/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml
index f150d7ed9..badea3e2c 100644
--- a/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml
+++ b/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml
@@ -52,7 +52,6 @@
U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R -->
<Key
latin:keyStyle="moreKeysDevanagariVowelSignVocalicR"
- latin:keyLabel="&#x25CC;&#x0943;"
- latin:code="0x0943"
+ latin:keySpec="&#x25CC;&#x0943;|&#x0943;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_f1.xml b/java/res/xml/key_f1.xml
index 72e38cb1a..d3a753948 100644
--- a/java/res/xml/key_f1.xml
+++ b/java/res/xml/key_f1.xml
@@ -26,17 +26,27 @@
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/keylabel_for_comma"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:additionalMoreKeys="!text/more_keys_for_comma"
+ latin:keyStyle="f1MoreKeysStyle" />
+ </case>
+ <!-- latin:supportsSwitchingToShortcutIme="true" -->
+ <case
latin:hasShortcutKey="true"
>
<Key
@@ -45,7 +55,7 @@
<!-- latin:hasShortcutKey="false" -->
<default>
<Key
- latin:keyLabel="!text/keylabel_for_comma"
+ latin:keySpec="!text/keylabel_for_comma"
latin:keyLabelFlags="hasPopupHint"
latin:additionalMoreKeys="!text/more_keys_for_comma,!text/shortcut_as_more_key"
latin:keyStyle="f1MoreKeysStyle" />
diff --git a/java/res/xml/key_greek_semicolon.xml b/java/res/xml/key_greek_semicolon.xml
index ae73a59f6..9001e4dfb 100644
--- a/java/res/xml/key_greek_semicolon.xml
+++ b/java/res/xml/key_greek_semicolon.xml
@@ -26,14 +26,14 @@
latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
>
<Key
- latin:keyLabel=":"
+ latin:keySpec=":"
latin:keyHintLabel="1"
latin:moreKeys=";"
latin:additionalMoreKeys="1" />
</case>
<default>
<Key
- latin:keyLabel=";"
+ latin:keySpec=";"
latin:keyHintLabel="1"
latin:moreKeys=":"
latin:additionalMoreKeys="1" />
diff --git a/java/res/xml/key_nepali_traditional_period.xml b/java/res/xml/key_period.xml
index 1c389b009..edb4f9456 100644
--- a/java/res/xml/key_nepali_traditional_period.xml
+++ b/java/res/xml/key_period.xml
@@ -18,32 +18,31 @@
*/
-->
-<!-- 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="ne"
+ latin:keyboardLayoutSet="nepali_traditional"
>
- <Key
- latin:keyLabel=","
- latin:backgroundType="functional" />
- </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_virama" />
- <!-- U+002E: "." FULL STOP -->
<Key
latin:keyStyle="baseKeyDevanagariSignVirama"
latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!fixedColumnOrder!9,&#x002E;,!text/more_keys_for_punctuation"
+ latin:moreKeys="!text/more_keys_for_punctuation"
+ latin:backgroundType="functional" />
+ </case>
+ <default>
+ <Key
+ latin:keySpec="!text/keylabel_for_period"
+ latin:keyHintLabel="!text/keyhintlabel_for_period"
+ latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
+ latin:moreKeys="!text/more_keys_for_period"
latin:backgroundType="functional" />
</default>
</switch>
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..2330ecb7f 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|&#x200C;"
latin:moreKeys="!icon/zwj_key|&#x200D;"
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/label_to_symbol_key|!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/label_to_alpha_key|!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/label_to_more_symbol_key|!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/label_to_symbol_key|!code/key_shift"
+ latin:parentStyle="baseForLayoutSwitchKeyStyle" />
<key-style
latin:styleName="comKeyStyle"
- latin:keyLabel="!text/keylabel_for_popular_domain"
+ latin:keySpec="!text/keylabel_for_popular_domain"
latin:keyLabelFlags="autoXScale|fontNormal|hasPopupHint|preserveCase"
- latin:keyOutputText="!text/keylabel_for_popular_domain"
latin:moreKeys="!text/more_keys_for_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..ed40ebc58 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -113,21 +113,21 @@
U+00A2: "¢" CENT SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
- latin:keyLabel="!text/keylabel_for_currency"
+ latin:keySpec="!text/keylabel_for_currency"
latin:moreKeys="!text/more_keys_for_currency" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
- latin:keyLabel="&#x00A3;" />
+ latin:keySpec="&#x00A3;" />
<key-style
latin:styleName="moreCurrency2KeyStyle"
- latin:keyLabel="&#x20AC;" />
+ latin:keySpec="&#x20AC;" />
<key-style
latin:styleName="moreCurrency3KeyStyle"
- latin:keyLabel="$"
+ latin:keySpec="$"
latin:moreKeys="&#x00A2;" />
<key-style
latin:styleName="moreCurrency4KeyStyle"
- latin:keyLabel="&#x00A2;" />
+ latin:keySpec="&#x00A2;" />
</case>
<!-- GB: United Kingdom (Pound) -->
<case
@@ -140,21 +140,21 @@
U+20B1: "₱" PESO SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
- latin:keyLabel="&#x00A3;"
+ latin:keySpec="&#x00A3;"
latin:moreKeys="&#x00A2;,$,&#x20AC;,&#x00A5;,&#x20B1;" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
- latin:keyLabel="&#x20AC;" />
+ latin:keySpec="&#x20AC;" />
<key-style
latin:styleName="moreCurrency2KeyStyle"
- latin:keyLabel="&#x00A5;" />
+ latin:keySpec="&#x00A5;" />
<key-style
latin:styleName="moreCurrency3KeyStyle"
- latin:keyLabel="$"
+ latin:keySpec="$"
latin:moreKeys="&#x00A2;" />
<key-style
latin:styleName="moreCurrency4KeyStyle"
- latin:keyLabel="&#x00A2;" />
+ latin:keySpec="&#x00A2;" />
</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..a02c9bfa1 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:keySpec="$"
latin:moreKeys="!text/more_keys_for_currency_dollar" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
- latin:keyLabel="&#x00A3;" />
+ latin:keySpec="&#x00A3;" />
<key-style
latin:styleName="moreCurrency2KeyStyle"
- latin:keyLabel="&#x00A2;" />
+ latin:keySpec="&#x00A2;" />
<key-style
latin:styleName="moreCurrency3KeyStyle"
- latin:keyLabel="&#x20AC;" />
+ latin:keySpec="&#x20AC;" />
<key-style
latin:styleName="moreCurrency4KeyStyle"
- latin:keyLabel="&#x00A5;" />
+ latin:keySpec="&#x00A5;" />
</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="&#x20AC;"
+ latin:keySpec="&#x20AC;"
latin:moreKeys="&#x00A2;,&#x00A3;,$,&#x00A5;,&#x20B1;" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
- latin:keyLabel="&#x00A3;" />
+ latin:keySpec="&#x00A3;" />
<key-style
latin:styleName="moreCurrency2KeyStyle"
- latin:keyLabel="&#x00A5;" />
+ latin:keySpec="&#x00A5;" />
<key-style
latin:styleName="moreCurrency3KeyStyle"
- latin:keyLabel="$"
+ latin:keySpec="$"
latin:moreKeys="&#x00A2;" />
<key-style
latin:styleName="moreCurrency4KeyStyle"
- latin:keyLabel="&#x00A2;" />
+ latin:keySpec="&#x00A2;" />
</merge>
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 083e6a67d..64d09b107 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -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_number.xml b/java/res/xml/key_styles_number.xml
index 2e5a601b0..7136e1070 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="&#xFF0A;"
+ latin:keySpec="&#xFF0A;|*"
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/label_to_phone_symbols_key|!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/label_to_phone_numeric_key|!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,&#x2105;,&#x2122;,&#x00AE;,&#x00A9;,&#x00A7;,&#x00B6;,\\,,&#x2022;,&#x00B0;,&#x2032;,&#x2033;,&#x2191;,&#x2193;,&#x2190;,&#x2192;,&#x2026;,!text/more_keys_for_bullet,&#x0394;,&#x03A0;,&#x03C0;" />
-</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="&#x0E05;"
+ latin:keySpec="&#x0E05;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+0E03: "ฃ" THAI CHARACTER KHO KHUAT -->
<Key
- latin:keyLabel="&#x0E03;"
+ latin:keySpec="&#x0E03;"
latin:keyLabelFlags="fontNormal" />
</default>
</switch>
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="&#x0630;"
+ latin:keySpec="&#x0630;"
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="&#x055D;"
- latin:backgroundType="functional" />
- <!-- U+0589: "։" ARMENIAN FULL STOP -->
- <Key
- latin:keyLabel="&#x0589;"
- 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/keys_comma_period_symbols.xml b/java/res/xml/keys_comma_period_symbols.xml
new file mode 100644
index 000000000..5221d34e3
--- /dev/null
+++ b/java/res/xml/keys_comma_period_symbols.xml
@@ -0,0 +1,31 @@
+<?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"
+>
+ <Key
+ latin:keySpec="!text/keylabel_for_comma"
+ latin:moreKeys="!text/more_keys_for_comma" />
+ <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
+ <Key
+ latin:keySpec="."
+ latin:moreKeys="&#x2026;" />
+</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="&quot;"
+ latin:keySpec="&quot;"
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="!,&quot;" />
@@ -59,22 +59,22 @@
latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
>
<Key
- latin:keyLabel="&lt;"
+ latin:keySpec="&lt;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<Key
- latin:keyLabel="&gt;"
+ latin:keySpec="&gt;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
</case>
<default>
<Key
- latin:keyLabel=","
+ latin:keySpec=","
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="\?,&lt;" />
<Key
- latin:keyLabel="."
+ latin:keySpec="."
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&gt;" />
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="&#x0686;"
+ latin:keySpec="&#x0686;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml
index 56d0727dd..46f4e4b4c 100644
--- a/java/res/xml/keys_less_greater.xml
+++ b/java/res/xml/keys_less_greater.xml
@@ -25,28 +25,22 @@
<case
latin:languageCode="fa"
>
- <!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
- U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
<Key
- latin:keyLabel="&#x00AB;"
- latin:code="0x00BB"
+ latin:keySpec="!text/keyspec_left_double_angle_quote"
latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_less_than" />
<Key
- latin:keyLabel="&#x00BB;"
- latin:code="0x00AB"
+ latin:keySpec="!text/keyspec_right_double_angle_quote"
latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_greater_than" />
</case>
<default>
<Key
- latin:keyLabel="&lt;"
- latin:code="!code/key_less_than"
+ latin:keySpec="!text/keyspec_less_than"
latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_less_than" />
<Key
- latin:keyLabel="&gt;"
- latin:code="!code/key_greater_than"
+ latin:keySpec="!text/keyspec_greater_than"
latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_greater_than" />
</default>
diff --git a/java/res/xml/keys_parentheses.xml b/java/res/xml/keys_parentheses.xml
index 25e89c930..73105d837 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:keySpec="!text/keyspec_left_parenthesis"
latin:moreKeys="!text/more_keys_for_left_parenthesis" />
<Key
- latin:keyLabel=")"
- latin:code="!code/key_right_parenthesis"
+ latin:keySpec="!text/keyspec_right_parenthesis"
latin:moreKeys="!text/more_keys_for_right_parenthesis" />
</merge>
diff --git a/java/res/xml/keys_pcqwerty2_right3.xml b/java/res/xml/keys_pcqwerty2_right3.xml
index 6f86477da..9e62b09c2 100644
--- a/java/res/xml/keys_pcqwerty2_right3.xml
+++ b/java/res/xml/keys_pcqwerty2_right3.xml
@@ -26,23 +26,23 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<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..d889216c0 100644
--- a/java/res/xml/keys_pcqwerty3_right2.xml
+++ b/java/res/xml/keys_pcqwerty3_right2.xml
@@ -26,19 +26,19 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
- latin:keyLabel=";"
+ latin:keySpec=";"
latin:additionalMoreKeys=":" />
<Key
- latin:keyLabel="\'"
+ latin:keySpec="\'"
latin:additionalMoreKeys="&quot;"
latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,%,!text/single_quotes" />
</case>
<!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<Key
- latin:keyLabel=":" />
+ latin:keySpec=":" />
<Key
- latin:keyLabel="&quot;"
+ latin:keySpec="&quot;"
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..f32d80908 100644
--- a/java/res/xml/keys_pcqwerty4_right3.xml
+++ b/java/res/xml/keys_pcqwerty4_right3.xml
@@ -26,15 +26,15 @@
latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
- latin:keyLabel=","
+ latin:keySpec=","
latin:additionalMoreKeys="&lt;" />
<Key
- latin:keyLabel="."
+ latin:keySpec="."
latin:additionalMoreKeys="&gt;" />
<Key
- latin:keyLabel="/"
+ latin:keySpec="/"
latin:additionalMoreKeys="\?"
- latin:moreKeys="!text/more_keys_for_symbols_question" />
+ latin:moreKeys="!text/more_keys_for_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="&lt;"
+ latin:keySpec="&lt;"
latin:moreKeys="!fixedColumnOrder!3,&#x2039;,&#x2264;,&#x00AB;" />
<Key
- latin:keyLabel="&gt;"
+ latin:keySpec="&gt;"
latin:moreKeys="!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;" />
<Key
- latin:keyLabel="\?"
- latin:moreKeys="!text/more_keys_for_symbols_question" />
+ latin:keySpec="\?"
+ latin:moreKeys="!text/more_keys_for_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_virama.xml b/java/res/xml/keystyle_devanagari_sign_virama.xml
index b22fbe842..5e0e10823 100644
--- a/java/res/xml/keystyle_devanagari_sign_virama.xml
+++ b/java/res/xml/keystyle_devanagari_sign_virama.xml
@@ -29,7 +29,6 @@
U+094D: "्" DEVANAGARI SIGN VIRAMA -->
<key-style
latin:styleName="baseKeyDevanagariSignVirama"
- latin:keyLabel="&#x25CC;&#x094D;"
- latin:code="0x094D"
+ latin:keySpec="&#x25CC;&#x094D;|&#x094D;"
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="&#x25CC;&#x0903;"
- latin:code="0x0903"
+ latin:keySpec="&#x25CC;&#x0903;|&#x0903;"
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..97f98e328 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml
@@ -46,7 +46,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAa"
latin:parentStyle="moreKeysDevanagariVowelSignAa"
- latin:keyLabel="&#x25CC;&#x093E;"
- latin:code="0x093E"
+ latin:keySpec="&#x25CC;&#x093E;|&#x093E;"
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..4d1b2c514 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml
@@ -53,7 +53,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAi"
latin:parentStyle="moreKeysDevanagariVowelSignAi"
- latin:keyLabel="&#x25CC;&#x0948;"
- latin:code="0x0948"
+ latin:keySpec="&#x25CC;&#x0948;|&#x0948;"
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..66628b5ed 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_au.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_au.xml
@@ -44,7 +44,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignAu"
latin:parentStyle="moreKeysDevanagariVowelSignAu"
- latin:keyLabel="&#x25CC;&#x094C;"
- latin:code="0x094C"
+ latin:keySpec="&#x25CC;&#x094C;|&#x094C;"
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..de1d94974 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_e.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_e.xml
@@ -53,7 +53,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignE"
latin:parentStyle="moreKeysDevanagariVowelSignE"
- latin:keyLabel="&#x25CC;&#x0947;"
- latin:code="0x0947"
+ latin:keySpec="&#x25CC;&#x0947;|&#x0947;"
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..d1d56c185 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_i.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_i.xml
@@ -45,7 +45,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignI"
latin:parentStyle="moreKeysDevanagariVowelSignI"
- latin:keyLabel="&#x25CC;&#x093F;"
- latin:code="0x093F"
+ latin:keySpec="&#x25CC;&#x093F;|&#x093F;"
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..fd0ce77f8 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml
@@ -45,7 +45,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignIi"
latin:parentStyle="moreKeysDevanagariVowelSignIi"
- latin:keyLabel="&#x25CC;&#x0940;"
- latin:code="0x0940"
+ latin:keySpec="&#x25CC;&#x0940;|&#x0940;"
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..edc3bef0f 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_o.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_o.xml
@@ -47,7 +47,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignO"
latin:parentStyle="moreKeysDevanagariVowelSignO"
- latin:keyLabel="&#x25CC;&#x094B;"
- latin:code="0x094B"
+ latin:keySpec="&#x25CC;&#x094B;|&#x094B;"
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..c7de4fdd8 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_u.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_u.xml
@@ -46,7 +46,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignU"
latin:parentStyle="moreKeysDevanagariVowelSignU"
- latin:keyLabel="&#x25CC;&#x0941;"
- latin:code="0x0941"
+ latin:keySpec="&#x25CC;&#x0941;|&#x0941;"
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..6029d6d2b 100644
--- a/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml
@@ -46,7 +46,6 @@
<key-style
latin:styleName="baseKeyDevanagariVowelSignUu"
latin:parentStyle="moreKeysDevanagariVowelSignUu"
- latin:keyLabel="&#x25CC;&#x0942;"
- latin:code="0x0942"
+ latin:keySpec="&#x25CC;&#x0942;|&#x0942;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 0a27da93f..94327f9e9 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -24,52 +24,54 @@
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_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
+ es_US: Spanish (United States)/spanish
+ (es_419: Spanish (Latin America)/qwerty)
+ et_EE: Estonian (Estonia)/nordic
fa: Persian/arabic
fi: Finnish/nordic
fr: French/azerty
- fr_CA: French Canada/qwerty
+ fr_CA: French (Canada)/qwerty
+ fr_CH: French (Switzerland)/swiss
hi: Hindi/hindi
hr: Croatian/qwertz
hu: Hungarian/qwertz
- hy_AM: Armenian Phonetic/armenian_phonetic
+ hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic
in: Indonesian/qwerty # "id" is 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
+ 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
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 +90,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 +113,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 +121,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 +129,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 +153,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 +161,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 +169,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 +177,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 +185,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 +193,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 +209,7 @@
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"
@@ -194,6 +217,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 +225,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,6 +233,7 @@
android:imeSubtypeLocale="es_US"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
+ android:isAsciiCapable="true"
/>
<!--
<subtype android:icon="@drawable/ic_ime_switcher_dark"
@@ -216,6 +242,7 @@
android:imeSubtypeLocale="es_419"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
+ android:isAsciiCapable="true"
/>
-->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
@@ -224,6 +251,7 @@
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"
@@ -231,6 +259,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 +267,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 +275,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 +283,15 @@
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"
@@ -259,6 +299,7 @@
android:imeSubtypeLocale="hi"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi,EmojiCapable"
+ android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
@@ -266,6 +307,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 +315,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 +323,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 +332,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 +340,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 +348,7 @@
android:imeSubtypeLocale="it"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,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 +357,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 +365,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 +389,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 +397,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 +405,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 +413,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 +421,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 +429,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 +437,7 @@
android:imeSubtypeLocale="ms_MY"
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"
@@ -389,29 +445,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: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 +477,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 +485,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 +493,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 +501,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 +509,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 +517,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 +525,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 +533,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 +541,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 +550,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 +558,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 +567,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 +575,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 +583,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 +591,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 +599,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 +607,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 +615,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 +623,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 +631,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 +642,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..a39ce4ae8 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"
@@ -169,6 +175,7 @@
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" />
diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml
index 8d9508e38..81a5d98b9 100644
--- a/java/res/xml/prefs_for_debug.xml
+++ b/java/res/xml/prefs_for_debug.xml
@@ -14,51 +14,75 @@
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" />
-
+ 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="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" />
<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" />
+ <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 -->
<CheckBoxPreference
android:defaultValue="false"
android:key="use_only_personalization_dictionary_for_debug"
android:persistent="true"
android:title="@string/prefs_use_only_personalization_dictionary" />
-
<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..0658079b2 100644
--- a/java/res/xml/row_dvorak4.xml
+++ b/java/res/xml/row_dvorak4.xml
@@ -28,7 +28,7 @@
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:keyStyle="f1MoreKeysStyle" />
@@ -36,7 +36,7 @@
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" />
<Key
diff --git a/java/res/xml/row_pcqwerty5.xml b/java/res/xml/row_pcqwerty5.xml
index 4ec908ba1..a72f38880 100644
--- a/java/res/xml/row_pcqwerty5.xml
+++ b/java/res/xml/row_pcqwerty5.xml
@@ -28,7 +28,7 @@
latin:keyWidth="11.538%p" />
<switch>
<case
- latin:shortcutKeyEnabled="true"
+ latin:supportsSwitchingToShortcutIme="true"
>
<Key
latin:keyStyle="shortcutKeyStyle"
@@ -62,6 +62,7 @@
</switch>
<Key
latin:keyStyle="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
latin:keyWidth="15.384%p" />
<switch>
<case
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="&#x0589;"
- 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..d5f142178 100644
--- a/java/res/xml/rowkeys_arabic1.xml
+++ b/java/res/xml/rowkeys_arabic1.xml
@@ -24,21 +24,21 @@
<!-- U+0636: "ض" ARABIC LETTER DAD
U+0661: "١" ARABIC-INDIC DIGIT ONE -->
<Key
- latin:keyLabel="&#x0636;"
+ latin:keySpec="&#x0636;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1,&#x0661;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0635: "ص" ARABIC LETTER SAD
U+0662: "٢" ARABIC-INDIC DIGIT TWO -->
<Key
- latin:keyLabel="&#x0635;"
+ latin:keySpec="&#x0635;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2,&#x0662;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062B: "ث" ARABIC LETTER THEH
U+0663: "٣" ARABIC-INDIC DIGIT THREE -->
<Key
- latin:keyLabel="&#x062B;"
+ latin:keySpec="&#x062B;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3,&#x0663;"
latin:keyLabelFlags="fontNormal" />
@@ -47,7 +47,7 @@
U+0664: "٤" ARABIC-INDIC DIGIT FOUR -->
<!-- TODO: DroidSansArabic lacks the glyph of U+06A8 ARABIC LETTER QAF WITH THREE DOTS ABOVE -->
<Key
- latin:keyLabel="&#x0642;"
+ latin:keySpec="&#x0642;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4,&#x0664;"
latin:moreKeys="&#x06A8;"
@@ -60,7 +60,7 @@
<!-- 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="&#x0641;"
+ latin:keySpec="&#x0641;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5,&#x0665;"
latin:moreKeys="&#x06A4;,&#x06A2;,&#x06A5;"
@@ -68,14 +68,14 @@
<!-- U+063A: "غ" ARABIC LETTER GHAIN
U+0666: "٦" ARABIC-INDIC DIGIT SIX -->
<Key
- latin:keyLabel="&#x063A;"
+ latin:keySpec="&#x063A;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6,&#x0666;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0639: "ع" ARABIC LETTER AIN
U+0667: "٧" ARABIC-INDIC DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0639;"
+ latin:keySpec="&#x0639;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7,&#x0667;"
latin:keyLabelFlags="fontNormal" />
@@ -84,7 +84,7 @@
U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
U+0668: "٨" ARABIC-INDIC DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0647;"
+ latin:keySpec="&#x0647;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8,&#x0668;"
latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;"
@@ -92,21 +92,21 @@
<!-- U+062E: "خ" ARABIC LETTER KHAH
U+0669: "٩" ARABIC-INDIC DIGIT NINE -->
<Key
- latin:keyLabel="&#x062E;"
+ latin:keySpec="&#x062E;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9,&#x0669;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062D: "ح" ARABIC LETTER HAH
U+0660: "٠" ARABIC-INDIC DIGIT ZERO -->
<Key
- latin:keyLabel="&#x062D;"
+ latin:keySpec="&#x062D;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0,&#x0660;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062C: "ج" ARABIC LETTER JEEM
U+0686: "چ" ARABIC LETTER TCHEH -->
<Key
- latin:keyLabel="&#x062C;"
+ latin:keySpec="&#x062C;"
latin:moreKeys="&#x0686;"
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="&#x0634;"
+ latin:keySpec="&#x0634;"
latin:moreKeys="&#x069C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0633: "س" ARABIC LETTER SEEN -->
<Key
- latin:keyLabel="&#x0633;"
+ latin:keySpec="&#x0633;"
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="&#x064A;"
+ latin:keySpec="&#x064A;"
latin:moreKeys="&#x0626;,&#x0649;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0628: "ب" ARABIC LETTER BEH
U+067E: "پ" ARABIC LETTER PEH -->
<Key
- latin:keyLabel="&#x0628;"
+ latin:keySpec="&#x0628;"
latin:moreKeys="&#x067E;"
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="&#x0644;"
+ latin:keySpec="&#x0644;"
latin:moreKeys="&#xFEFB;|&#x0644;&#x0627;,&#xFEF7;|&#x0644;&#x0623;,&#xFEF9;|&#x0644;&#x0625;,&#xFEF5;|&#x0644;&#x0622;"
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="&#x0627;"
+ latin:keySpec="&#x0627;"
latin:moreKeys="!fixedColumnOrder!5,&#x0622;,&#x0621;,&#x0623;,&#x0625;,&#x0671;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062A: "ت" ARABIC LETTER TEH -->
<Key
- latin:keyLabel="&#x062A;"
+ latin:keySpec="&#x062A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0646: "ن" ARABIC LETTER NOON -->
<Key
- latin:keyLabel="&#x0646;"
+ latin:keySpec="&#x0646;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0645: "م" ARABIC LETTER MEEM -->
<Key
- latin:keyLabel="&#x0645;"
+ latin:keySpec="&#x0645;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0643: "ك" ARABIC LETTER KAF
U+06AF: "گ" ARABIC LETTER GAF
U+06A9: "ک" ARABIC LETTER KEHEH -->
<Key
- latin:keyLabel="&#x0643;"
+ latin:keySpec="&#x0643;"
latin:moreKeys="&#x06AF;,&#x06A9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0637: "ط" ARABIC LETTER TAH -->
<Key
- latin:keyLabel="&#x0637;"
+ latin:keySpec="&#x0637;"
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="&#x0621;"
+ latin:keySpec="&#x0621;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x0624;"
+ latin:keySpec="&#x0624;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0631: "ر" ARABIC LETTER REH -->
<Key
- latin:keyLabel="&#x0631;"
+ latin:keySpec="&#x0631;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0649: "ى" ARABIC LETTER ALEF MAKSURA
U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x0649;"
+ latin:keySpec="&#x0649;"
latin:moreKeys="&#x0626;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
<Key
- latin:keyLabel="&#x0629;"
+ latin:keySpec="&#x0629;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0648: "و" ARABIC LETTER WAW -->
<Key
- latin:keyLabel="&#x0648;"
+ latin:keySpec="&#x0648;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0632: "ز" ARABIC LETTER ZAIN
U+0698: "ژ" ARABIC LETTER JEH -->
<Key
- latin:keyLabel="&#x0632;"
+ latin:keySpec="&#x0632;"
latin:moreKeys="&#x0698;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0638: "ظ" ARABIC LETTER ZAH -->
<Key
- latin:keyLabel="&#x0638;"
+ latin:keySpec="&#x0638;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062F: "د" ARABIC LETTER DAL -->
<Key
- latin:keyLabel="&#x062F;"
+ latin:keySpec="&#x062F;"
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="&#x0567;"
+ latin:keySpec="&#x0567;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:keyLabelFlags="fontNormal" />
<!-- U+0569: "թ" ARMENIAN SMALL LETTER TO -->
<Key
- latin:keyLabel="&#x0569;"
+ latin:keySpec="&#x0569;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:keyLabelFlags="fontNormal" />
<!-- U+0583: "փ" ARMENIAN SMALL LETTER PIWR -->
<Key
- latin:keyLabel="&#x0583;"
+ latin:keySpec="&#x0583;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:keyLabelFlags="fontNormal" />
<!-- U+0571: "ձ" ARMENIAN SMALL LETTER JA -->
<Key
- latin:keyLabel="&#x0571;"
+ latin:keySpec="&#x0571;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:keyLabelFlags="fontNormal" />
<!-- U+057B: "ջ" ARMENIAN SMALL LETTER JHEH -->
<Key
- latin:keyLabel="&#x057B;"
+ latin:keySpec="&#x057B;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:keyLabelFlags="fontNormal" />
<!-- U+0580: "ր" ARMENIAN SMALL LETTER REH -->
<Key
- latin:keyLabel="&#x0580;"
+ latin:keySpec="&#x0580;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:keyLabelFlags="fontNormal" />
<!-- U+0579: "չ" ARMENIAN SMALL LETTER CHA -->
<Key
- latin:keyLabel="&#x0579;"
+ latin:keySpec="&#x0579;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:keyLabelFlags="fontNormal" />
<!-- U+0573: "ճ" ARMENIAN SMALL LETTER CHEH -->
<Key
- latin:keyLabel="&#x0573;"
+ latin:keySpec="&#x0573;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:keyLabelFlags="fontNormal" />
<!-- U+056A: "ժ" ARMENIAN SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x056A;"
+ latin:keySpec="&#x056A;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:keyLabelFlags="fontNormal" />
<!-- U+056E: "ծ" ARMENIAN SMALL LETTER CA -->
<Key
- latin:keyLabel="&#x056E;"
+ latin:keySpec="&#x056E;"
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="&#x0584;"
+ latin:keySpec="&#x0584;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0578: "ո" ARMENIAN SMALL LETTER VO -->
<Key
- latin:keyLabel="&#x0578;"
+ latin:keySpec="&#x0578;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0565: "ե" ARMENIAN SMALL LETTER ECH
U+0587: "և" ARMENIAN SMALL LIGATURE ECH YIWN -->
<Key
- latin:keyLabel="&#x0565;"
+ latin:keySpec="&#x0565;"
latin:moreKeys="&#x0587;"
+ latin:keyHintLabel="&#x0587;"
latin:keyLabelFlags="fontNormal" />
<!-- U+057C: "ռ" ARMENIAN SMALL LETTER RA -->
<Key
- latin:keyLabel="&#x057C;"
+ latin:keySpec="&#x057C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+057F: "տ" ARMENIAN SMALL LETTER TIWN -->
<Key
- latin:keyLabel="&#x057F;"
+ latin:keySpec="&#x057F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0568: "ը" ARMENIAN SMALL LETTER ET -->
<Key
- latin:keyLabel="&#x0568;"
+ latin:keySpec="&#x0568;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0582: "ւ" ARMENIAN SMALL LETTER YIWN -->
<Key
- latin:keyLabel="&#x0582;"
+ latin:keySpec="&#x0582;"
latin:keyLabelFlags="fontNormal" />
<!-- U+056B: "ի" ARMENIAN SMALL LETTER INI -->
<Key
- latin:keyLabel="&#x056B;"
+ latin:keySpec="&#x056B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0585: "օ" ARMENIAN SMALL LETTER OH -->
<Key
- latin:keyLabel="&#x0585;"
+ latin:keySpec="&#x0585;"
latin:keyLabelFlags="fontNormal" />
<!-- U+057A: "պ" ARMENIAN SMALL LETTER PEH -->
<Key
- latin:keyLabel="&#x057A;"
+ latin:keySpec="&#x057A;"
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="&#x0561;"
+ latin:keySpec="&#x0561;"
latin:keyLabelFlags="fontNormal" />
<!-- U+057D: "ս" ARMENIAN SMALL LETTER SEH -->
<Key
- latin:keyLabel="&#x057D;"
+ latin:keySpec="&#x057D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0564: "դ" ARMENIAN SMALL LETTER DA -->
<Key
- latin:keyLabel="&#x0564;"
+ latin:keySpec="&#x0564;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0586: "ֆ" ARMENIAN SMALL LETTER FEH -->
<Key
- latin:keyLabel="&#x0586;"
+ latin:keySpec="&#x0586;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0563: "գ" ARMENIAN SMALL LETTER GIM -->
<Key
- latin:keyLabel="&#x0563;"
+ latin:keySpec="&#x0563;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0570: "հ" ARMENIAN SMALL LETTER HO -->
<Key
- latin:keyLabel="&#x0570;"
+ latin:keySpec="&#x0570;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0575: "յ" ARMENIAN SMALL LETTER YI -->
<Key
- latin:keyLabel="&#x0575;"
+ latin:keySpec="&#x0575;"
latin:keyLabelFlags="fontNormal" />
<!-- U+056F: "կ" ARMENIAN SMALL LETTER KEN -->
<Key
- latin:keyLabel="&#x056F;"
+ latin:keySpec="&#x056F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+056C: "լ" ARMENIAN SMALL LETTER LIWN -->
<Key
- latin:keyLabel="&#x056C;"
+ latin:keySpec="&#x056C;"
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="&#x0566;"
+ latin:keySpec="&#x0566;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0572: "ղ" ARMENIAN SMALL LETTER GHAD -->
<Key
- latin:keyLabel="&#x0572;"
+ latin:keySpec="&#x0572;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0581: "ց" ARMENIAN SMALL LETTER CO -->
<Key
- latin:keyLabel="&#x0581;"
+ latin:keySpec="&#x0581;"
latin:keyLabelFlags="fontNormal" />
<!-- U+057E: "վ" ARMENIAN SMALL LETTER VEW -->
<Key
- latin:keyLabel="&#x057E;"
+ latin:keySpec="&#x057E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0562: "բ" ARMENIAN SMALL LETTER BEN -->
<Key
- latin:keyLabel="&#x0562;"
+ latin:keySpec="&#x0562;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0576: "ն" ARMENIAN SMALL LETTER NOW -->
<Key
- latin:keyLabel="&#x0576;"
+ latin:keySpec="&#x0576;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0574: "մ" ARMENIAN SMALL LETTER MEN -->
<Key
- latin:keyLabel="&#x0574;"
+ latin:keySpec="&#x0574;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_azerty1.xml b/java/res/xml/rowkeys_azerty1.xml
index 42b27463f..adb66b70f 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" />
<Key
- latin:keyLabel="z"
+ latin:keySpec="z"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="!text/more_keys_for_z" />
<Key
- latin:keyLabel="e"
+ latin:keySpec="e"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_e" />
<Key
- latin:keyLabel="r"
+ latin:keySpec="r"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="!text/more_keys_for_r" />
<Key
- latin:keyLabel="t"
+ latin:keySpec="t"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="!text/more_keys_for_t" />
<Key
- latin:keyLabel="y"
+ latin:keySpec="y"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_y" />
<Key
- latin:keyLabel="u"
+ latin:keySpec="u"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_u" />
<Key
- latin:keyLabel="i"
+ latin:keySpec="i"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_i" />
<Key
- latin:keyLabel="o"
+ latin:keySpec="o"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="!text/more_keys_for_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..db0686721 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:keySpec="s"
latin:moreKeys="!text/more_keys_for_s" />
<Key
- latin:keyLabel="d"
+ latin:keySpec="d"
latin:moreKeys="!text/more_keys_for_d" />
<Key
- latin:keyLabel="f" />
+ latin:keySpec="f" />
<Key
- latin:keyLabel="g"
+ latin:keySpec="g"
latin:moreKeys="!text/more_keys_for_g" />
<Key
- latin:keyLabel="h"
+ latin:keySpec="h"
latin:moreKeys="!text/more_keys_for_h" />
<Key
- latin:keyLabel="j"
+ latin:keySpec="j"
latin:moreKeys="!text/more_keys_for_j" />
<Key
- latin:keyLabel="k"
+ latin:keySpec="k"
latin:moreKeys="!text/more_keys_for_k" />
<Key
- latin:keyLabel="l"
+ latin:keySpec="l"
latin:moreKeys="!text/more_keys_for_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..0aa215305 100644
--- a/java/res/xml/rowkeys_azerty3.xml
+++ b/java/res/xml/rowkeys_azerty3.xml
@@ -22,20 +22,20 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel="w"
+ latin:keySpec="w"
latin:moreKeys="!text/more_keys_for_w" />
<Key
- latin:keyLabel="x" />
+ latin:keySpec="x" />
<Key
- latin:keyLabel="c"
+ latin:keySpec="c"
latin:moreKeys="!text/more_keys_for_c" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
<Key
- latin:keyLabel="b" />
+ latin:keySpec="b" />
<Key
- latin:keyLabel="n"
+ latin:keySpec="n"
latin:moreKeys="!text/more_keys_for_n" />
<include
latin:keyboardLayout="@xml/key_azerty3_right" />
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="&#x044F;"
+ latin:keySpec="&#x044F;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
<Key
- latin:keyLabel="&#x0432;"
+ latin:keySpec="&#x0432;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
- latin:keyLabel="&#x0435;"
+ latin:keySpec="&#x0435;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
<!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
<Key
- latin:keyLabel="&#x0440;"
+ latin:keySpec="&#x0440;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
<Key
- latin:keyLabel="&#x0442;"
+ latin:keySpec="&#x0442;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
<Key
- latin:keyLabel="&#x044A;"
+ latin:keySpec="&#x044A;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6" />
<!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
<Key
- latin:keyLabel="&#x0443;"
+ latin:keySpec="&#x0443;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+0438: "и" CYRILLIC SMALL LETTER I
U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE -->
<Key
- latin:keyLabel="&#x0438;"
+ latin:keySpec="&#x0438;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x045D;" />
<!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
<Key
- latin:keyLabel="&#x043E;"
+ latin:keySpec="&#x043E;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
- latin:keyLabel="&#x043F;"
+ latin:keySpec="&#x043F;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
<!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
<Key
- latin:keyLabel="&#x0447;" />
+ latin:keySpec="&#x0447;" />
</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="&#x0430;" />
+ latin:keySpec="&#x0430;" />
<!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
<Key
- latin:keyLabel="&#x0441;" />
+ latin:keySpec="&#x0441;" />
<!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
<Key
- latin:keyLabel="&#x0434;" />
+ latin:keySpec="&#x0434;" />
<!-- U+0444: "ф" CYRILLIC SMALL LETTER EF -->
<Key
- latin:keyLabel="&#x0444;" />
+ latin:keySpec="&#x0444;" />
<!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
<Key
- latin:keyLabel="&#x0433;" />
+ latin:keySpec="&#x0433;" />
<!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
<Key
- latin:keyLabel="&#x0445;" />
+ latin:keySpec="&#x0445;" />
<!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I -->
<Key
- latin:keyLabel="&#x0439;" />
+ latin:keySpec="&#x0439;" />
<!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
<Key
- latin:keyLabel="&#x043A;" />
+ latin:keySpec="&#x043A;" />
<!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
<Key
- latin:keyLabel="&#x043B;" />
+ latin:keySpec="&#x043B;" />
<!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA -->
<Key
- latin:keyLabel="&#x0448;" />
+ latin:keySpec="&#x0448;" />
<!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
<Key
- latin:keyLabel="&#x0449;" />
+ latin:keySpec="&#x0449;" />
</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="&#x0437;" />
+ latin:keySpec="&#x0437;" />
<!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN -->
<Key
- latin:keyLabel="&#x044C;" />
+ latin:keySpec="&#x044C;" />
<!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
<Key
- latin:keyLabel="&#x0446;" />
+ latin:keySpec="&#x0446;" />
<!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x0436;" />
+ latin:keySpec="&#x0436;" />
<!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
<Key
- latin:keyLabel="&#x0431;" />
+ latin:keySpec="&#x0431;" />
<!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
<Key
- latin:keyLabel="&#x043D;" />
+ latin:keySpec="&#x043D;" />
<!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
<Key
- latin:keyLabel="&#x043C;" />
+ latin:keySpec="&#x043C;" />
<!-- U+044E: "ю" CYRILLIC SMALL LETTER YU -->
<Key
- latin:keyLabel="&#x044E;" />
+ latin:keySpec="&#x044E;" />
</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="&#x0443;"
+ latin:keySpec="&#x0443;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
- latin:keyLabel="&#x0435;"
+ latin:keySpec="&#x0435;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+0438: "и" CYRILLIC SMALL LETTER I
U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE -->
<Key
- latin:keyLabel="&#x0438;"
+ latin:keySpec="&#x0438;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&#x045D;" />
<!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA -->
<Key
- latin:keyLabel="&#x0448;"
+ latin:keySpec="&#x0448;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
<Key
- latin:keyLabel="&#x0449;"
+ latin:keySpec="&#x0449;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
<Key
- latin:keyLabel="&#x043A;"
+ latin:keySpec="&#x043A;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6" />
<!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
<Key
- latin:keyLabel="&#x0441;"
+ latin:keySpec="&#x0441;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
<Key
- latin:keyLabel="&#x0434;"
+ latin:keySpec="&#x0434;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8" />
<!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
<Key
- latin:keyLabel="&#x0437;"
+ latin:keySpec="&#x0437;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
<Key
- latin:keyLabel="&#x0446;"
+ latin:keySpec="&#x0446;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
<!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
<Key
- latin:keyLabel="&#x0431;" />
+ latin:keySpec="&#x0431;" />
</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="&#x044C;" />
+ latin:keySpec="&#x044C;" />
<!-- U+044F: "я" CYRILLIC SMALL LETTER YA -->
<Key
- latin:keyLabel="&#x044F;" />
+ latin:keySpec="&#x044F;" />
<!-- U+0430: "а" CYRILLIC SMALL LETTER A -->
<Key
- latin:keyLabel="&#x0430;" />
+ latin:keySpec="&#x0430;" />
<!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
<Key
- latin:keyLabel="&#x043E;" />
+ latin:keySpec="&#x043E;" />
<!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x0436;" />
+ latin:keySpec="&#x0436;" />
<!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
<Key
- latin:keyLabel="&#x0433;" />
+ latin:keySpec="&#x0433;" />
<!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
<Key
- latin:keyLabel="&#x0442;" />
+ latin:keySpec="&#x0442;" />
<!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
<Key
- latin:keyLabel="&#x043D;" />
+ latin:keySpec="&#x043D;" />
<!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
<Key
- latin:keyLabel="&#x0432;" />
+ latin:keySpec="&#x0432;" />
<!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
<Key
- latin:keyLabel="&#x043C;" />
+ latin:keySpec="&#x043C;" />
<!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
<Key
- latin:keyLabel="&#x0447;" />
+ latin:keySpec="&#x0447;" />
</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="&#x044E;" />
+ latin:keySpec="&#x044E;" />
<!-- U+0439: "й" CYRILLIC SMALL LETTER SHORT I -->
<Key
- latin:keyLabel="&#x0439;" />
+ latin:keySpec="&#x0439;" />
<!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
<Key
- latin:keyLabel="&#x044A;" />
+ latin:keySpec="&#x044A;" />
<!-- U+044D: "э" CYRILLIC SMALL LETTER E -->
<Key
- latin:keyLabel="&#x044D;" />
+ latin:keySpec="&#x044D;" />
<!-- U+0444: "ф" CYRILLIC SMALL LETTER EF -->
<Key
- latin:keyLabel="&#x0444;" />
+ latin:keySpec="&#x0444;" />
<!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
<Key
- latin:keyLabel="&#x0445;" />
+ latin:keySpec="&#x0445;" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
- latin:keyLabel="&#x043F;" />
+ latin:keySpec="&#x043F;" />
<!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
<Key
- latin:keyLabel="&#x0440;" />
+ latin:keySpec="&#x0440;" />
<!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
<Key
- latin:keyLabel="&#x043B;" />
+ latin:keySpec="&#x043B;" />
</merge>
diff --git a/java/res/xml/rowkeys_colemak1.xml b/java/res/xml/rowkeys_colemak1.xml
index f1c30756b..819a69d2b 100644
--- a/java/res/xml/rowkeys_colemak1.xml
+++ b/java/res/xml/rowkeys_colemak1.xml
@@ -22,44 +22,44 @@
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" />
<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" />
<Key
- latin:keyLabel="j"
+ latin:keySpec="j"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_j" />
<Key
- latin:keyLabel="l"
+ latin:keySpec="l"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_l" />
<Key
- latin:keyLabel="u"
+ latin:keySpec="u"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_u" />
<Key
- latin:keyLabel="y"
+ latin:keySpec="y"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="!text/more_keys_for_y" />
diff --git a/java/res/xml/rowkeys_colemak2.xml b/java/res/xml/rowkeys_colemak2.xml
index f73d7e95f..644d845bf 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:keySpec="a"
latin:moreKeys="!text/more_keys_for_a" />
<Key
- latin:keyLabel="r"
+ latin:keySpec="r"
latin:moreKeys="!text/more_keys_for_r" />
<Key
- latin:keyLabel="s"
+ latin:keySpec="s"
latin:moreKeys="!text/more_keys_for_s" />
<Key
- latin:keyLabel="t"
+ latin:keySpec="t"
latin:moreKeys="!text/more_keys_for_t" />
<Key
- latin:keyLabel="d"
+ latin:keySpec="d"
latin:moreKeys="!text/more_keys_for_d" />
<Key
- latin:keyLabel="h"
+ latin:keySpec="h"
latin:moreKeys="!text/more_keys_for_h" />
<Key
- latin:keyLabel="n"
+ latin:keySpec="n"
latin:moreKeys="!text/more_keys_for_n" />
<Key
- latin:keyLabel="e"
+ latin:keySpec="e"
latin:moreKeys="!text/more_keys_for_e" />
<Key
- latin:keyLabel="i"
+ latin:keySpec="i"
latin:moreKeys="!text/more_keys_for_i" />
<Key
- latin:keyLabel="o"
+ latin:keySpec="o"
latin:moreKeys="!text/more_keys_for_o" />
</merge>
diff --git a/java/res/xml/rowkeys_colemak3.xml b/java/res/xml/rowkeys_colemak3.xml
index f0f915142..946910cb5 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:keySpec="z"
latin:moreKeys="!text/more_keys_for_z" />
<Key
- latin:keyLabel="x" />
+ latin:keySpec="x" />
<Key
- latin:keyLabel="c"
+ latin:keySpec="c"
latin:moreKeys="!text/more_keys_for_c" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
<Key
- latin:keyLabel="b" />
+ latin:keySpec="b" />
<Key
- latin:keyLabel="k"
+ latin:keySpec="k"
latin:moreKeys="!text/more_keys_for_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..831bfafff 100644
--- a/java/res/xml/rowkeys_dvorak1.xml
+++ b/java/res/xml/rowkeys_dvorak1.xml
@@ -24,35 +24,35 @@
<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" />
<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" />
<Key
- latin:keyLabel="c"
+ latin:keySpec="c"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_c" />
<Key
- latin:keyLabel="r"
+ latin:keySpec="r"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="!text/more_keys_for_r" />
<Key
- latin:keyLabel="l"
+ latin:keySpec="l"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0"
latin:moreKeys="!text/more_keys_for_l" />
diff --git a/java/res/xml/rowkeys_dvorak2.xml b/java/res/xml/rowkeys_dvorak2.xml
index 943e3f549..7c734730a 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:keySpec="a"
latin:moreKeys="!text/more_keys_for_a" />
<Key
- latin:keyLabel="o"
+ latin:keySpec="o"
latin:moreKeys="!text/more_keys_for_o" />
<Key
- latin:keyLabel="e"
+ latin:keySpec="e"
latin:moreKeys="!text/more_keys_for_e" />
<Key
- latin:keyLabel="u"
+ latin:keySpec="u"
latin:moreKeys="!text/more_keys_for_u" />
<Key
- latin:keyLabel="i"
+ latin:keySpec="i"
latin:moreKeys="!text/more_keys_for_i" />
<Key
- latin:keyLabel="d"
+ latin:keySpec="d"
latin:moreKeys="!text/more_keys_for_d" />
<Key
- latin:keyLabel="h"
+ latin:keySpec="h"
latin:moreKeys="!text/more_keys_for_h" />
<Key
- latin:keyLabel="t"
+ latin:keySpec="t"
latin:moreKeys="!text/more_keys_for_t" />
<Key
- latin:keyLabel="n"
+ latin:keySpec="n"
latin:moreKeys="!text/more_keys_for_n" />
<Key
- latin:keyLabel="s"
+ latin:keySpec="s"
latin:moreKeys="!text/more_keys_for_s" />
</merge>
diff --git a/java/res/xml/rowkeys_dvorak3.xml b/java/res/xml/rowkeys_dvorak3.xml
index b035f41cd..a9da6b950 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:keySpec="j"
latin:moreKeys="!text/more_keys_for_j" />
<Key
- latin:keyLabel="k"
+ latin:keySpec="k"
latin:moreKeys="!text/more_keys_for_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:keySpec="w"
latin:moreKeys="!text/more_keys_for_w" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
</merge>
diff --git a/java/res/xml/rowkeys_east_slavic1.xml b/java/res/xml/rowkeys_east_slavic1.xml
index 5b3b4b48d..7e95a8b35 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="&#x0439;"
+ latin:keySpec="&#x0439;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
<Key
- latin:keyLabel="&#x0446;"
+ latin:keySpec="&#x0446;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
<Key
- latin:keyLabel="&#x0443;"
+ latin:keySpec="&#x0443;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_cyrillic_u" />
<!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
<Key
- latin:keyLabel="&#x043A;"
+ latin:keySpec="&#x043A;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="!text/more_keys_for_cyrillic_ka" />
<!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
- latin:keyLabel="&#x0435;"
+ latin:keySpec="&#x0435;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="!text/more_keys_for_cyrillic_ie" />
<!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
<Key
- latin:keyLabel="&#x043D;"
+ latin:keySpec="&#x043D;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_cyrillic_en" />
<!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
<Key
- latin:keyLabel="&#x0433;"
+ latin:keySpec="&#x0433;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_cyrillic_ghe" />
<!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA -->
<Key
- latin:keyLabel="&#x0448;"
+ latin:keySpec="&#x0448;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8" />
<Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row1_9"
+ latin:keySpec="!text/keylabel_for_east_slavic_row1_9"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
<Key
- latin:keyLabel="&#x0437;"
+ latin:keySpec="&#x0437;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
<!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
<Key
- latin:keyLabel="&#x0445;" />
+ latin:keySpec="&#x0445;" />
</merge>
diff --git a/java/res/xml/rowkeys_east_slavic2.xml b/java/res/xml/rowkeys_east_slavic2.xml
index 2e412f08c..20d963cb3 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="&#x0444;" />
+ latin:keySpec="&#x0444;" />
<Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row2_1"
+ latin:keySpec="!text/keylabel_for_east_slavic_row2_1"
latin:moreKeys="!text/more_keys_for_east_slavic_row2_1" />
<!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
<Key
- latin:keyLabel="&#x0432;" />
+ latin:keySpec="&#x0432;" />
<!-- U+0430: "а" CYRILLIC SMALL LETTER A -->
<Key
- latin:keyLabel="&#x0430;"
+ latin:keySpec="&#x0430;"
latin:moreKeys="!text/more_keys_for_cyrillic_a" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
- latin:keyLabel="&#x043F;" />
+ latin:keySpec="&#x043F;" />
<!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
<Key
- latin:keyLabel="&#x0440;" />
+ latin:keySpec="&#x0440;" />
<!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
<Key
- latin:keyLabel="&#x043E;"
+ latin:keySpec="&#x043E;"
latin:moreKeys="!text/more_keys_for_cyrillic_o" />
<!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
<Key
- latin:keyLabel="&#x043B;" />
+ latin:keySpec="&#x043B;" />
<!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
<Key
- latin:keyLabel="&#x0434;" />
+ latin:keySpec="&#x0434;" />
<!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x0436;" />
+ latin:keySpec="&#x0436;" />
<Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row2_11"
+ latin:keySpec="!text/keylabel_for_east_slavic_row2_11"
latin:moreKeys="!text/more_keys_for_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..b7d19b223 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="&#x044F;" />
+ latin:keySpec="&#x044F;" />
<!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
<Key
- latin:keyLabel="&#x0447;" />
+ latin:keySpec="&#x0447;" />
<!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
<Key
- latin:keyLabel="&#x0441;" />
+ latin:keySpec="&#x0441;" />
<!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
<Key
- latin:keyLabel="&#x043C;" />
+ latin:keySpec="&#x043C;" />
<Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row3_5" />
+ latin:keySpec="!text/keylabel_for_east_slavic_row3_5" />
<!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
<Key
- latin:keyLabel="&#x0442;" />
+ latin:keySpec="&#x0442;" />
<!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN -->
<Key
- latin:keyLabel="&#x044C;"
+ latin:keySpec="&#x044C;"
latin:moreKeys="!text/more_keys_for_cyrillic_soft_sign" />
<!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
<Key
- latin:keyLabel="&#x0431;" />
+ latin:keySpec="&#x0431;" />
<!-- U+044E: "ю" CYRILLIC SMALL LETTER YU -->
<Key
- latin:keyLabel="&#x044E;" />
+ latin:keySpec="&#x044E;" />
</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="&#x0636;"
+ latin:keySpec="&#x0636;"
latin:keyHintLabel="&#x06F1;"
latin:additionalMoreKeys="&#x06F1;,1"
latin:keyLabelFlags="fontNormal" />
<!-- U+0635: "ص" ARABIC LETTER SAD
U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO -->
<Key
- latin:keyLabel="&#x0635;"
+ latin:keySpec="&#x0635;"
latin:keyHintLabel="&#x06F2;"
latin:additionalMoreKeys="&#x06F2;,2"
latin:keyLabelFlags="fontNormal" />
<!-- U+062B: "ث" ARABIC LETTER THEH
U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE -->
<Key
- latin:keyLabel="&#x062B;"
+ latin:keySpec="&#x062B;"
latin:keyHintLabel="&#x06F3;"
latin:additionalMoreKeys="&#x06F3;,3"
latin:keyLabelFlags="fontNormal" />
<!-- U+0642: "ق" ARABIC LETTER QAF
U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0642;"
+ latin:keySpec="&#x0642;"
latin:keyHintLabel="&#x06F4;"
latin:additionalMoreKeys="&#x06F4;,4"
latin:keyLabelFlags="fontNormal" />
<!-- U+0641: "ف" ARABIC LETTER FEH
U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0641;"
+ latin:keySpec="&#x0641;"
latin:keyHintLabel="&#x06F5;"
latin:additionalMoreKeys="&#x06F5;,5"
latin:keyLabelFlags="fontNormal" />
<!-- U+063A: "غ" ARABIC LETTER GHAIN
U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX -->
<Key
- latin:keyLabel="&#x063A;"
+ latin:keySpec="&#x063A;"
latin:keyHintLabel="&#x06F6;"
latin:additionalMoreKeys="&#x06F6;,6"
latin:keyLabelFlags="fontNormal" />
<!-- U+0639: "ع" ARABIC LETTER AIN
U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0639;"
+ latin:keySpec="&#x0639;"
latin:keyHintLabel="&#x06F7;"
latin:additionalMoreKeys="&#x06F7;,7"
latin:keyLabelFlags="fontNormal" />
@@ -77,7 +77,7 @@
U+0629: "ة" ARABIC LETTER TEH MARBUTA
U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0647;"
+ latin:keySpec="&#x0647;"
latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
latin:keyHintLabel="&#x06F8;"
latin:additionalMoreKeys="&#x06F8;,8"
@@ -85,19 +85,19 @@
<!-- U+062E: "خ" ARABIC LETTER KHAH
U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE -->
<Key
- latin:keyLabel="&#x062E;"
+ latin:keySpec="&#x062E;"
latin:keyHintLabel="&#x06F9;"
latin:additionalMoreKeys="&#x06F9;,9"
latin:keyLabelFlags="fontNormal" />
<!-- U+062D: "ح" ARABIC LETTER HAH
U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO -->
<Key
- latin:keyLabel="&#x062D;"
+ latin:keySpec="&#x062D;"
latin:keyHintLabel="&#x06F0;"
latin:additionalMoreKeys="&#x06F0;,0"
latin:keyLabelFlags="fontNormal" />
<!-- U+062C: "ج" ARABIC LETTER JEEM -->
<Key
- latin:keyLabel="&#x062C;"
+ latin:keySpec="&#x062C;"
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="&#x0634;"
+ latin:keySpec="&#x0634;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0633: "س" ARABIC LETTER SEEN -->
<Key
- latin:keyLabel="&#x0633;"
+ latin:keySpec="&#x0633;"
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="&#x06CC;"
+ latin:keySpec="&#x06CC;"
latin:moreKeys="&#x0626;,&#x064A;,&#xFBE8;|&#x0649;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0628: "ب" ARABIC LETTER BEH -->
<Key
- latin:keyLabel="&#x0628;"
+ latin:keySpec="&#x0628;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0644: "ل" ARABIC LETTER LAM -->
<Key
- latin:keyLabel="&#x0644;"
+ latin:keySpec="&#x0644;"
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="&#x0627;"
+ latin:keySpec="&#x0627;"
latin:moreKeys="!fixedColumnOrder!5,&#x0671;,&#x0621;,&#x0622;,&#x0623;,&#x0625;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062A: "ت" ARABIC LETTER TEH
U+0629: "ة": ARABIC LETTER TEH MARBUTA -->
<Key
- latin:keyLabel="&#x062A;"
+ latin:keySpec="&#x062A;"
latin:moreKeys="&#x0629;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0646: "ن" ARABIC LETTER NOON -->
<Key
- latin:keyLabel="&#x0646;"
+ latin:keySpec="&#x0646;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0645: "م" ARABIC LETTER MEEM -->
<Key
- latin:keyLabel="&#x0645;"
+ latin:keySpec="&#x0645;"
latin:keyLabelFlags="fontNormal" />
<!-- U+06A9: "ک" ARABIC LETTER KEHEH
U+0643: "ك" ARABIC LETTER KAF -->
<Key
- latin:keyLabel="&#x06A9;"
+ latin:keySpec="&#x06A9;"
latin:moreKeys="&#x0643;"
latin:keyLabelFlags="fontNormal" />
<!-- U+06AF: "گ" ARABIC LETTER GAF -->
<Key
- latin:keyLabel="&#x06AF;"
+ latin:keySpec="&#x06AF;"
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="&#x0638;"
+ latin:keySpec="&#x0638;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0637: "ط" ARABIC LETTER TAH -->
<Key
- latin:keyLabel="&#x0637;"
+ latin:keySpec="&#x0637;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0698: "ژ" ARABIC LETTER JEH -->
<Key
- latin:keyLabel="&#x0698;"
+ latin:keySpec="&#x0698;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0632: "ز" ARABIC LETTER ZAIN -->
<Key
- latin:keyLabel="&#x0632;"
+ latin:keySpec="&#x0632;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0631: "ر" ARABIC LETTER REH -->
<Key
- latin:keyLabel="&#x0631;"
+ latin:keySpec="&#x0631;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0630: "ذ" ARABIC LETTER THAL -->
<Key
- latin:keyLabel="&#x0630;"
+ latin:keySpec="&#x0630;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062F: "د" ARABIC LETTER DAL -->
<Key
- latin:keyLabel="&#x062F;"
+ latin:keySpec="&#x062F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+067E: "پ" ARABIC LETTER PEH -->
<Key
- latin:keyLabel="&#x067E;"
+ latin:keySpec="&#x067E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0648: "و" ARABIC LETTER WAW
U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x0648;"
+ latin:keySpec="&#x0648;"
latin:moreKeys="&#x0624;"
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="&#x10ED;"
+ latin:keySpec="&#x10ED;"
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="&#x10E6;"
+ latin:keySpec="&#x10E6;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+10D7: "თ" GEORGIAN LETTER TAN -->
<Key
- latin:keyLabel="&#x10D7;"
+ latin:keySpec="&#x10D7;"
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="&#x10E5;"
+ latin:keySpec="&#x10E5;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+10EC: "წ" GEORGIAN LETTER CIL -->
<Key
- latin:keyLabel="&#x10EC;"
+ latin:keySpec="&#x10EC;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+10D4: "ე" GEORGIAN LETTER EN
U+10F1: "ჱ" GEORGIAN LETTER HE -->
<Key
- latin:keyLabel="&#x10D4;"
+ latin:keySpec="&#x10D4;"
latin:moreKeys="&#x10F1;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
<!-- U+10E0: "რ" GEORGIAN LETTER RAE -->
<Key
- latin:keyLabel="&#x10E0;"
+ latin:keySpec="&#x10E0;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+10E2: "ტ" GEORGIAN LETTER TAR -->
<Key
- latin:keyLabel="&#x10E2;"
+ latin:keySpec="&#x10E2;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+10E7: "ყ" GEORGIAN LETTER QAR
U+10F8: "ჸ" GEORGIAN LETTER ELIFI -->
<Key
- latin:keyLabel="&#x10E7;"
+ latin:keySpec="&#x10E7;"
latin:moreKeys="&#x10F8;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6" />
<!-- U+10E3: "უ" GEORGIAN LETTER UN -->
<Key
- latin:keyLabel="&#x10E3;"
+ latin:keySpec="&#x10E3;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+10D8: "ი" GEORGIAN LETTER IN
U+10F2: "ჲ" GEORGIAN LETTER HIE -->
<Key
- latin:keyLabel="&#x10D8;"
+ latin:keySpec="&#x10D8;"
latin:moreKeys="&#x10F2;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8" />
<!-- U+10DD: "ო" GEORGIAN LETTER ON -->
<Key
- latin:keyLabel="&#x10DD;"
+ latin:keySpec="&#x10DD;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+10DE: "პ" GEORGIAN LETTER PAR -->
<Key
- latin:keyLabel="&#x10DE;"
+ latin:keySpec="&#x10DE;"
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="&#x10E8;" />
+ latin:keySpec="&#x10E8;" />
<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="&#x10DF;" />
+ latin:keySpec="&#x10DF;" />
<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="&#x10D0;"
+ latin:keySpec="&#x10D0;"
latin:moreKeys="&#x10FA;" />
<!-- U+10E1: "ს" GEORGIAN LETTER SAN -->
<Key
- latin:keyLabel="&#x10E1;" />
+ latin:keySpec="&#x10E1;" />
<!-- U+10D3: "დ" GEORGIAN LETTER DON -->
<Key
- latin:keyLabel="&#x10D3;" />
+ latin:keySpec="&#x10D3;" />
<!-- U+10E4: "ფ" GEORGIAN LETTER PHAR
U+10F6: "ჶ" GEORGIAN LETTER FI -->
<Key
- latin:keyLabel="&#x10E4;"
+ latin:keySpec="&#x10E4;"
latin:moreKeys="&#x10F6;" />
<!-- U+10D2: "გ" GEORGIAN LETTER GAN
U+10F9: "ჹ" GEORGIAN LETTER TURNED GAN -->
<Key
- latin:keyLabel="&#x10D2;"
+ latin:keySpec="&#x10D2;"
latin:moreKeys="&#x10F9;" />
<!-- U+10F0: "ჰ" GEORGIAN LETTER HAE
U+10F5: "ჵ" GEORGIAN LETTER HOE -->
<Key
- latin:keyLabel="&#x10F0;"
+ latin:keySpec="&#x10F0;"
latin:moreKeys="&#x10F5;" />
<!-- U+10EF: "ჯ" GEORGIAN LETTER JHAN
U+10F7: "ჷ" GEORGIAN LETTER YN -->
<Key
- latin:keyLabel="&#x10EF;"
+ latin:keySpec="&#x10EF;"
latin:moreKeys="&#x10F7;" />
<!-- U+10D9: "კ" GEORGIAN LETTER KAN -->
<Key
- latin:keyLabel="&#x10D9;" />
+ latin:keySpec="&#x10D9;" />
<!-- U+10DA: "ლ" GEORGIAN LETTER LAS -->
<Key
- latin:keyLabel="&#x10DA;" />
+ latin:keySpec="&#x10DA;" />
</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="&#x10EB;" />
+ latin:keySpec="&#x10EB;" />
<Key
- latin:keyLabel="X" />
+ latin:keySpec="X" />
<!-- U+10E9: "ჩ" GEORGIAN LETTER CHIN -->
<Key
- latin:keyLabel="&#x10E9;" />
+ latin:keySpec="&#x10E9;" />
<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="&#x10D6;" />
+ latin:keySpec="&#x10D6;" />
<!-- U+10EE: "ხ" GEORGIAN LETTER XAN
U+10F4: "ჴ" GEORGIAN LETTER HAR -->
<Key
- latin:keyLabel="&#x10EE;"
+ latin:keySpec="&#x10EE;"
latin:moreKeys="&#x10F4;" />
<!-- U+10EA: "ც" GEORGIAN LETTER CAN -->
<Key
- latin:keyLabel="&#x10EA;" />
+ latin:keySpec="&#x10EA;" />
<!-- U+10D5: "ვ" GEORGIAN LETTER VIN
U+10F3: "ჳ" GEORGIAN LETTER WE -->
<Key
- latin:keyLabel="&#x10D5;"
+ latin:keySpec="&#x10D5;"
latin:moreKeys="&#x10F3;" />
<!-- U+10D1: "ბ" GEORGIAN LETTER BAN -->
<Key
- latin:keyLabel="&#x10D1;" />
+ latin:keySpec="&#x10D1;" />
<!-- U+10DC: "ნ" GEORGIAN LETTER NAR
U+10FC: "ჼ" MODIFIER LETTER GEORGIAN NAR -->
<Key
- latin:keyLabel="&#x10DC;"
+ latin:keySpec="&#x10DC;"
latin:moreKeys="&#x10FC;" />
<!-- U+10DB: "მ" GEORGIAN LETTER MAN -->
<Key
- latin:keyLabel="&#x10DB;" />
+ latin:keySpec="&#x10DB;" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/rowkeys_greek1.xml b/java/res/xml/rowkeys_greek1.xml
index 5777d3b85..5080dc843 100644
--- a/java/res/xml/rowkeys_greek1.xml
+++ b/java/res/xml/rowkeys_greek1.xml
@@ -29,7 +29,7 @@
>
U+0385: "΅" GREEK DIALYTIKA TONOS
<Key
- latin:keyLabel="&#x0385;"
+ latin:keySpec="&#x0385;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
</case>
@@ -37,7 +37,7 @@
-->
<!-- U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA -->
<Key
- latin:keyLabel="&#x03C2;"
+ latin:keySpec="&#x03C2;"
latin:keyLabelFlags="preserveCase"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
@@ -48,18 +48,18 @@
<!-- U+03B5: "ε" GREEK SMALL LETTER EPSILON
U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS -->
<Key
- latin:keyLabel="&#x03B5;"
+ latin:keySpec="&#x03B5;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&#x03AD;" />
<!-- U+03C1: "ρ" GREEK SMALL LETTER RHO -->
<Key
- latin:keyLabel="&#x03C1;"
+ latin:keySpec="&#x03C1;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+03C4: "τ" GREEK SMALL LETTER TAU -->
<Key
- latin:keyLabel="&#x03C4;"
+ latin:keySpec="&#x03C4;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+03C5: "υ" GREEK SMALL LETTER UPSILON
@@ -67,13 +67,13 @@
U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA
U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -->
<Key
- latin:keyLabel="&#x03C5;"
+ latin:keySpec="&#x03C5;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="&#x03CD;,&#x03CB;,&#x03B0;" />
<!-- U+03B8: "θ" GREEK SMALL LETTER THETA -->
<Key
- latin:keyLabel="&#x03B8;"
+ latin:keySpec="&#x03B8;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+03B9: "ι" GREEK SMALL LETTER IOTA
@@ -81,20 +81,20 @@
U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -->
<Key
- latin:keyLabel="&#x03B9;"
+ latin:keySpec="&#x03B9;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x03AF;,&#x03CA;,&#x0390;" />
<!-- U+03BF: "ο" GREEK SMALL LETTER OMICRON
U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS -->
<Key
- latin:keyLabel="&#x03BF;"
+ latin:keySpec="&#x03BF;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="&#x03CC;" />
<!-- U+03C0: "π" GREEK SMALL LETTER PI -->
<Key
- latin:keyLabel="&#x03C0;"
+ latin:keySpec="&#x03C0;"
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="&#x03B1;"
+ latin:keySpec="&#x03B1;"
latin:moreKeys="&#x03AC;" />
<!-- U+03C3: "σ" GREEK SMALL LETTER SIGMA -->
<Key
- latin:keyLabel="&#x03C3;" />
+ latin:keySpec="&#x03C3;" />
<!-- U+03B4: "δ" GREEK SMALL LETTER DELTA -->
<Key
- latin:keyLabel="&#x03B4;" />
+ latin:keySpec="&#x03B4;" />
<!-- U+03C6: "φ" GREEK SMALL LETTER PHI -->
<Key
- latin:keyLabel="&#x03C6;" />
+ latin:keySpec="&#x03C6;" />
<!-- U+03B3: "γ" GREEK SMALL LETTER GAMMA -->
<Key
- latin:keyLabel="&#x03B3;" />
+ latin:keySpec="&#x03B3;" />
<!-- U+03B7: "η" GREEK SMALL LETTER ETA
U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS -->
<Key
- latin:keyLabel="&#x03B7;"
+ latin:keySpec="&#x03B7;"
latin:moreKeys="&#x03AE;" />
<!-- U+03BE: "ξ" GREEK SMALL LETTER XI -->
<Key
- latin:keyLabel="&#x03BE;" />
+ latin:keySpec="&#x03BE;" />
<!-- U+03BA: "κ" GREEK SMALL LETTER KAPPA -->
<Key
- latin:keyLabel="&#x03BA;" />
+ latin:keySpec="&#x03BA;" />
<!-- U+03BB: "λ" GREEK SMALL LETTER LAMDA -->
<Key
- latin:keyLabel="&#x03BB;" />
+ latin:keySpec="&#x03BB;" />
</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="&#x03B6;" />
+ latin:keySpec="&#x03B6;" />
<!-- U+03C7: "χ" GREEK SMALL LETTER CHI -->
<Key
- latin:keyLabel="&#x03C7;" />
+ latin:keySpec="&#x03C7;" />
<!-- U+03C8: "ψ" GREEK SMALL LETTER PSI -->
<Key
- latin:keyLabel="&#x03C8;" />
+ latin:keySpec="&#x03C8;" />
<!-- U+03C9: "ω" GREEK SMALL LETTER OMEGA
U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS -->
<Key
- latin:keyLabel="&#x03C9;"
+ latin:keySpec="&#x03C9;"
latin:moreKeys="&#x03CE;" />
<!-- U+03B2: "β" GREEK SMALL LETTER BETA -->
<Key
- latin:keyLabel="&#x03B2;" />
+ latin:keySpec="&#x03B2;" />
<!-- U+03BD: "ν" GREEK SMALL LETTER NU -->
<Key
- latin:keyLabel="&#x03BD;" />
+ latin:keySpec="&#x03BD;" />
<!-- U+03BC: "μ" GREEK SMALL LETTER MU -->
<Key
- latin:keyLabel="&#x03BC;" />
+ latin:keySpec="&#x03BC;" />
</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="&quot;" />
<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="&#x05E7;"
+ latin:keySpec="&#x05E7;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
<!-- U+05E8: "ר" HEBREW LETTER RESH -->
<Key
- latin:keyLabel="&#x05E8;"
+ latin:keySpec="&#x05E8;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+05D0: "א" HEBREW LETTER ALEF -->
<Key
- latin:keyLabel="&#x05D0;"
+ latin:keySpec="&#x05D0;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+05D8: "ט" HEBREW LETTER TET -->
<Key
- latin:keyLabel="&#x05D8;"
+ latin:keySpec="&#x05D8;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6" />
<!-- U+05D5: "ו" HEBREW LETTER VAV -->
<Key
- latin:keyLabel="&#x05D5;"
+ latin:keySpec="&#x05D5;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+05DF: "ן" HEBREW LETTER FINAL NUN -->
<Key
- latin:keyLabel="&#x05DF;"
+ latin:keySpec="&#x05DF;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8" />
<!-- U+05DD: "ם" HEBREW LETTER FINAL MEM -->
<Key
- latin:keyLabel="&#x05DD;"
+ latin:keySpec="&#x05DD;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+05E4: "פ" HEBREW LETTER PE -->
<Key
- latin:keyLabel="&#x05E4;"
+ latin:keySpec="&#x05E4;"
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="&#x05E9;" />
+ latin:keySpec="&#x05E9;" />
<!-- U+05D3: "ד" HEBREW LETTER DALET -->
<Key
- latin:keyLabel="&#x05D3;" />
+ latin:keySpec="&#x05D3;" />
<!-- U+05D2: "ג" HEBREW LETTER GIMEL
U+05D2 U+05F3: "ג׳" HEBREW LETTER GIMEL + HEBREW PUNCTUATION GERESH -->
<Key
- latin:keyLabel="&#x05D2;"
+ latin:keySpec="&#x05D2;"
latin:moreKeys="&#x05D2;&#x05F3;" />
<!-- U+05DB: "כ" HEBREW LETTER KAF -->
<Key
- latin:keyLabel="&#x05DB;" />
+ latin:keySpec="&#x05DB;" />
<!-- U+05E2: "ע" HEBREW LETTER AYIN -->
<Key
- latin:keyLabel="&#x05E2;" />
+ latin:keySpec="&#x05E2;" />
<!-- U+05D9: "י" HEBREW LETTER YOD
U+05F2 U+05B7: "ײַ" HEBREW LIGATURE YIDDISH DOUBLE YOD + HEBREW POINT PATAH -->
<Key
- latin:keyLabel="&#x05D9;"
+ latin:keySpec="&#x05D9;"
latin:moreKeys="&#x05F2;&#x05B7;" />
<!-- U+05D7: "ח" HEBREW LETTER HET
U+05D7 U+05F3: "ח׳" HEBREW LETTER HET + HEBREW PUNCTUATION GERESH -->
<Key
- latin:keyLabel="&#x05D7;"
+ latin:keySpec="&#x05D7;"
latin:moreKeys="&#x05D7;&#x05F3;" />
<!-- U+05DC: "ל" HEBREW LETTER LAMED -->
<Key
- latin:keyLabel="&#x05DC;" />
+ latin:keySpec="&#x05DC;" />
<!-- U+05DA: "ך" HEBREW LETTER FINAL KAF -->
<Key
- latin:keyLabel="&#x05DA;" />
+ latin:keySpec="&#x05DA;" />
<!-- U+05E3: "ף" HEBREW LETTER FINAL PE -->
<Key
- latin:keyLabel="&#x05E3;" />
+ latin:keySpec="&#x05E3;" />
</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="&#x05D6;"
+ latin:keySpec="&#x05D6;"
latin:moreKeys="&#x05D6;&#x05F3;" />
<!-- U+05E1: "ס" HEBREW LETTER SAMEKH -->
<Key
- latin:keyLabel="&#x05E1;" />
+ latin:keySpec="&#x05E1;" />
<!-- U+05D1: "ב" HEBREW LETTER BET -->
<Key
- latin:keyLabel="&#x05D1;" />
+ latin:keySpec="&#x05D1;" />
<!-- U+05D4: "ה" HEBREW LETTER HE -->
<Key
- latin:keyLabel="&#x05D4;" />
+ latin:keySpec="&#x05D4;" />
<!-- U+05E0: "נ" HEBREW LETTER NUN -->
<Key
- latin:keyLabel="&#x05E0;" />
+ latin:keySpec="&#x05E0;" />
<!-- U+05DE: "מ" HEBREW LETTER MEM -->
<Key
- latin:keyLabel="&#x05DE;" />
+ latin:keySpec="&#x05DE;" />
<!-- U+05E6: "צ" HEBREW LETTER TSADI
U+05E6 U+05F3: "צ׳" HEBREW LETTER TSADI + HEBREW PUNCTUATION GERESH -->
<Key
- latin:keyLabel="&#x05E6;"
+ latin:keySpec="&#x05E6;"
latin:moreKeys="&#x05E6;&#x05F3;" />
<!-- U+05EA: "ת" HEBREW LETTER TAV
U+05EA U+05F3: "ת׳" HEBREW LETTER TAV + HEBREW PUNCTUATION GERESH -->
<Key
- latin:keyLabel="&#x05EA;"
+ latin:keySpec="&#x05EA;"
latin:moreKeys="&#x05EA;&#x05F3;" />
<!-- U+05E5: "ץ" HEBREW LETTER FINAL TSADI
U+05E5 U+05F3: "ץ׳" HEBREW LETTER FINAL TSADI + HEBREW PUNCTUATION GERESH -->
<Key
- latin:keyLabel="&#x05E5;"
+ latin:keySpec="&#x05E5;"
latin:moreKeys="&#x05E5;&#x05F3;" />
</merge>
diff --git a/java/res/xml/rowkeys_hindi1.xml b/java/res/xml/rowkeys_hindi1.xml
index c0b3cb913..914618a76 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="&#x0914;"
+ latin:keySpec="&#x0914;"
latin:moreKeys="&#x0912;&#x0902;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0910: "ऐ" DEVANAGARI LETTER AI
U+0910/U+0902: "ऐं" DEVANAGARI LETTER AI/DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x0910;"
+ latin:keySpec="&#x0910;"
latin:moreKeys="&#x0910;&#x0902;"
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="&#x0906;"
+ latin:keySpec="&#x0906;"
latin:moreKeys="&#x0906;&#x0902;,&#x0906;&#x0901;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0908: "ई" DEVANAGARI LETTER II
U+0908/U+0902: "ईं" DEVANAGARI LETTER II/DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x0908;"
+ latin:keySpec="&#x0908;"
latin:moreKeys="&#x0908;&#x0902;"
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="&#x090A;"
+ latin:keySpec="&#x090A;"
latin:moreKeys="&#x090A;&#x0902;,&#x090A;&#x0901;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092D: "भ" DEVANAGARI LETTER BHA -->
<Key
- latin:keyLabel="&#x092D;"
+ latin:keySpec="&#x092D;"
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,22 +70,22 @@
latin:keyStyle="baseKeyDevanagariSignVisarga" />
<!-- U+0918: "घ" DEVANAGARI LETTER GHA -->
<Key
- latin:keyLabel="&#x0918;"
+ latin:keySpec="&#x0918;"
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="&#x0927;"
+ latin:keySpec="&#x0927;"
latin:moreKeys="&#x0915;&#x094D;&#x0937;,&#x0936;&#x094D;&#x0930;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091D: "झ" DEVANAGARI LETTER JHA -->
<Key
- latin:keyLabel="&#x091D;"
+ latin:keySpec="&#x091D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0922: "ढ" DEVANAGARI LETTER DDHA -->
<Key
- latin:keyLabel="&#x0922;"
+ latin:keySpec="&#x0922;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
@@ -143,7 +143,7 @@
U+096C: "६" DEVANAGARI DIGIT SIX
U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA -->
<Key
- latin:keyLabel="&#x092C;"
+ latin:keySpec="&#x092C;"
latin:moreKeys="&#x092C;&#x0952;,%"
latin:keyHintLabel="6"
latin:additionalMoreKeys="&#x096C;,6"
@@ -151,7 +151,7 @@
<!-- U+0939: "ह" DEVANAGARI LETTER HA
U+096D: "७" DEVANAGARI DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0939;"
+ latin:keySpec="&#x0939;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="&#x096D;,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="&#x0917;"
+ latin:keySpec="&#x0917;"
latin:moreKeys="&#x091C;&#x094D;&#x091E;,&#x0917;&#x093C;,&#x0917;&#x0952;,%"
latin:keyHintLabel="8"
latin:additionalMoreKeys="&#x096E;,8"
@@ -169,7 +169,7 @@
<!-- U+0926: "द" DEVANAGARI LETTER DA
U+096F: "९" DEVANAGARI DIGIT NINE -->
<Key
- latin:keyLabel="&#x0926;"
+ latin:keySpec="&#x0926;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="&#x096F;,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="&#x091C;"
+ latin:keySpec="&#x091C;"
latin:moreKeys="&#x091C;&#x0952;,&#x091C;&#x094D;&#x091E;,&#x091C;&#x093C;,%"
latin:keyHintLabel="0"
latin:additionalMoreKeys="&#x0966;,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="&#x0921;"
+ latin:keySpec="&#x0921;"
latin:moreKeys="&#x0921;&#x0952;,&#x0921;&#x093C;"
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="&#x0913;"
+ latin:keySpec="&#x0913;"
latin:moreKeys="&#x0913;&#x0902;,&#x0911;,&#x0912;"
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="&#x090F;"
+ latin:keySpec="&#x090F;"
latin:moreKeys="&#x090F;&#x0902;,&#x090F;&#x0901;,&#x090D;,&#x090E;"
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="&#x0905;"
+ latin:keySpec="&#x0905;"
latin:moreKeys="&#x0905;&#x0902;,&#x0905;&#x0901;"
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="&#x0907;"
+ latin:keySpec="&#x0907;"
latin:moreKeys="&#x0907;&#x0902;,&#x0907;&#x0901;"
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="&#x0909;"
+ latin:keySpec="&#x0909;"
latin:moreKeys="&#x0909;&#x0902;,&#x0909;&#x0901;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092B: "फ" DEVANAGARI LETTER PHA
U+092B/U+093C: "फ़" DEVANAGARI LETTER PHA/DEVANAGARI SIGN NUKTA -->
<Key
- latin:keyLabel="&#x092B;"
+ latin:keySpec="&#x092B;"
latin:moreKeys="&#x092B;&#x093C;"
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="&#x0931;"
+ latin:keySpec="&#x0931;"
latin:moreKeys="&#x094D;&#x0930;,&#x0930;&#x094D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0916: "ख" DEVANAGARI LETTER KHA
U+0916/U+093C: "ख़" DEVANAGARI LETTER KHA/DEVANAGARI SIGN NUKTA -->
<Key
- latin:keyLabel="&#x0916;"
+ latin:keySpec="&#x0916;"
latin:moreKeys="&#x0916;&#x093C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0925: "थ" DEVANAGARI LETTER THA -->
<Key
- latin:keyLabel="&#x0925;"
+ latin:keySpec="&#x0925;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091B: "छ" DEVANAGARI LETTER CHA -->
<Key
- latin:keyLabel="&#x091B;"
+ latin:keySpec="&#x091B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0920: "ठ" DEVANAGARI LETTER TTHA -->
<Key
- latin:keyLabel="&#x0920;"
+ latin:keySpec="&#x0920;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
@@ -133,35 +133,35 @@
latin:keyStyle="baseKeyDevanagariVowelSignU" />
<!-- U+092A: "प" DEVANAGARI LETTER PA -->
<Key
- latin:keyLabel="&#x092A;"
+ latin:keySpec="&#x092A;"
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="&#x0930;"
+ latin:keySpec="&#x0930;"
latin:moreKeys="&#x090B;,&#x0930;&#x093C;,&#x0960;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0915: "क" DEVANAGARI LETTER KA
U+0915/U+093C: "क़" DEVANAGARI LETTER KA/DEVANAGARI SIGN NUKTA -->
<Key
- latin:keyLabel="&#x0915;"
+ latin:keySpec="&#x0915;"
latin:moreKeys="&#x0915;&#x093C;"
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="&#x0924;"
+ latin:keySpec="&#x0924;"
latin:moreKeys="&#x0924;&#x094D;&#x0930;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091A: "च" DEVANAGARI LETTER CA -->
<Key
- latin:keyLabel="&#x091A;"
+ latin:keySpec="&#x091A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091F: "ट" DEVANAGARI LETTER TTA -->
<Key
- latin:keyLabel="&#x091F;"
+ latin:keySpec="&#x091F;"
latin:keyLabelFlags="fontNormal" />
</default>
</switch>
diff --git a/java/res/xml/rowkeys_hindi3.xml b/java/res/xml/rowkeys_hindi3.xml
index 136bc5f22..a9be47266 100644
--- a/java/res/xml/rowkeys_hindi3.xml
+++ b/java/res/xml/rowkeys_hindi3.xml
@@ -27,7 +27,7 @@
>
<!-- U+0911: "ऑ" DEVANAGARI LETTER CANDRA O -->
<Key
- latin:keyLabel="&#x0911;"
+ latin:keySpec="&#x0911;"
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
@@ -36,24 +36,24 @@
latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
<!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
- latin:keyLabel="&#x0923;"
+ latin:keySpec="&#x0923;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0929: "ऩ" DEVANAGARI LETTER NNNA -->
<Key
- latin:keyLabel="&#x0929;" />
+ latin:keySpec="&#x0929;" />
<!-- U+0933: "ळ" DEVANAGARI LETTER LLA
U+0934: "ऴ" DEVANAGARI LETTER LLLA -->
<Key
- latin:keyLabel="&#x0933;"
+ latin:keySpec="&#x0933;"
latin:moreKeys="&#x0934;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0936: "श" DEVANAGARI LETTER SHA -->
<Key
- latin:keyLabel="&#x0936;"
+ latin:keySpec="&#x0936;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0937: "ष" DEVANAGARI LETTER SSA -->
<Key
- latin:keyLabel="&#x0937;"
+ latin:keySpec="&#x0937;"
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
@@ -62,7 +62,7 @@
latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" />
<!-- U+091E: "ञ" DEVANAGARI LETTER NYA -->
<Key
- latin:keyLabel="&#x091E;"
+ latin:keySpec="&#x091E;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
@@ -76,7 +76,7 @@
<!-- U+092E: "म" DEVANAGARI LETTER MA
U+0950: "ॐ" DEVANAGARI OM -->
<Key
- latin:keyLabel="&#x092E;"
+ latin:keySpec="&#x092E;"
latin:moreKeys="&#x0950;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0928: "न" DEVANAGARI LETTER NA
@@ -84,28 +84,28 @@
U+0919: "ङ" DEVANAGARI LETTER NGA
U+0928/U+093C: "ऩ" DEVANAGARI LETTER NA/DEVANAGARI SIGN NUKTA -->
<Key
- latin:keyLabel="&#x0928;"
+ latin:keySpec="&#x0928;"
latin:moreKeys="&#x091E;,&#x0919;,&#x0928;&#x093C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0935: "व" DEVANAGARI LETTER VA -->
<Key
- latin:keyLabel="&#x0935;"
+ latin:keySpec="&#x0935;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0932: "ल" DEVANAGARI LETTER LA
U+090C: "ऌ" DEVANAGARI LETTER VOCALIC L
U+0961: "ॡ" DEVANAGARI LETTER VOCALIC LL -->
<Key
- latin:keyLabel="&#x0932;"
+ latin:keySpec="&#x0932;"
latin:moreKeys="&#x090C;,&#x0961;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0938: "स" DEVANAGARI LETTER SA -->
<Key
- latin:keyLabel="&#x0938;"
+ latin:keySpec="&#x0938;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092F: "य" DEVANAGARI LETTER YA
U+095F: "य़" DEVANAGARI LETTER YYA -->
<Key
- latin:keyLabel="&#x092F;"
+ latin:keySpec="&#x092F;"
latin:moreKeys="&#x095F;"
latin:keyLabelFlags="fontNormal" />
<!-- Because the font rendering system prior to API version 16 can't automatically
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|&#x200D;" />
<!-- U+17D7: "ៗ" KHMER SIGN LEK TOO
U+200C: ZERO WIDTH NON-JOINER -->
<Key
- latin:keyLabel="&#x17D7;"
+ latin:keySpec="&#x17D7;"
latin:moreKeys="!icon/zwnj_key|&#x200C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17D1: "៑" KHMER SIGN VIRIAM -->
<Key
- latin:keyLabel="&quot;"
+ latin:keySpec="&quot;"
latin:keyHintLabel="&#x17D1;"
latin:moreKeys="&#x17D1;" />
<!-- U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
U+20AC: "€" EURO SIGN -->
<Key
- latin:keyLabel="&#x17DB;"
+ latin:keySpec="&#x17DB;"
latin:keyHintLabel="$"
latin:moreKeys="$,&#x20AC;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17D6: "៖" KHMER SIGN CAMNUC PII KUUH -->
<Key
- latin:keyLabel="%"
+ latin:keySpec="%"
latin:keyHintLabel="&#x17D6;"
latin:moreKeys="&#x17D6;" />
<!-- U+17CD: "៍" KHMER SIGN TOANDAKHIAT
U+17D9: "៙" KHMER SIGN PHNAEK MUAN -->
<Key
- latin:keyLabel="&#x17CD;"
+ latin:keySpec="&#x17CD;"
latin:keyHintLabel="&#x17D9;"
latin:moreKeys="&#x17D9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17D0: "័" KHMER SIGN SAMYOK SANNYA
U+17DA: "៚" KHMER SIGN KOOMUUT -->
<Key
- latin:keyLabel="&#x17D0;"
+ latin:keySpec="&#x17D0;"
latin:keyHintLabel="&#x17DA;"
+ latin:keyHintLabelVerticalAdjustment="-30%"
latin:moreKeys="&#x17DA;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17CF: "៏" KHMER SIGN AHSDA -->
<Key
- latin:keyLabel="&#x17CF;"
+ latin:keySpec="&#x17CF;"
latin:keyHintLabel="*"
latin:moreKeys="*"
latin:keyLabelFlags="fontNormal" />
<!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
<Key
- latin:keyLabel="("
+ latin:keySpec="("
latin:keyHintLabel="{"
latin:moreKeys="{,&#x00AB;" />
<!-- U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
<Key
- latin:keyLabel=")"
+ latin:keySpec=")"
latin:keyHintLabel="}"
latin:moreKeys="},&#x00BB;" />
<!-- U+17CC: "៌" KHMER SIGN ROBAT
U+00D7: "×" MULTIPLICATION SIGN -->
<Key
- latin:keyLabel="&#x17CC;"
+ latin:keySpec="&#x17CC;"
latin:keyHintLabel="&#x00D7;"
latin:moreKeys="&#x00D7;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17CE: "៎" KHMER SIGN KAKABAT -->
<Key
- latin:keyLabel="&#x17CE;"
+ latin:keySpec="&#x17CE;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+17E1: "១" KHMER DIGIT ONE
U+17F1: "៱" KHMER SYMBOL LEK ATTAK MUOY -->
<Key
- latin:keyLabel="&#x17E1;"
+ latin:keySpec="&#x17E1;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:moreKeys="&#x17F1;"
@@ -106,7 +107,7 @@
<!-- U+17E2: "២" KHMER DIGIT TWO
U+17F2: "៲" KHMER SYMBOL LEK ATTAK PII -->
<Key
- latin:keyLabel="&#x17E2;"
+ latin:keySpec="&#x17E2;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="&#x17F2;"
@@ -114,7 +115,7 @@
<!-- U+17E3: "៣" KHMER DIGIT THREE
U+17F3: "៳" KHMER SYMBOL LEK ATTAK BEI -->
<Key
- latin:keyLabel="&#x17E3;"
+ latin:keySpec="&#x17E3;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&#x17F3;"
@@ -122,7 +123,7 @@
<!-- U+17E4: "៤" KHMER DIGIT FOUR
U+17F4: "៴" KHMER SYMBOL LEK ATTAK BUON -->
<Key
- latin:keyLabel="&#x17E4;"
+ latin:keySpec="&#x17E4;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="&#x17F4;"
@@ -130,7 +131,7 @@
<!-- U+17E5: "៥" KHMER DIGIT FIVE
U+17F5: "៵" KHMER SYMBOL LEK ATTAK PRAM -->
<Key
- latin:keyLabel="&#x17E5;"
+ latin:keySpec="&#x17E5;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="&#x17F5;"
@@ -138,7 +139,7 @@
<!-- U+17E6: "៦" KHMER DIGIT SIX
U+17F6: "៶" KHMER SYMBOL LEK ATTAK PRAM-MUOY -->
<Key
- latin:keyLabel="&#x17E6;"
+ latin:keySpec="&#x17E6;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="&#x17F6;"
@@ -146,7 +147,7 @@
<!-- U+17E7: "៧" KHMER DIGIT SEVEN
U+17F7: "៷" KHMER SYMBOL LEK ATTAK PRAM-PII -->
<Key
- latin:keyLabel="&#x17E7;"
+ latin:keySpec="&#x17E7;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="&#x17F7;"
@@ -154,7 +155,7 @@
<!-- U+17E8: "៨" KHMER DIGIT EIGHT
U+17F8: "៸" KHMER SYMBOL LEK ATTAK PRAM-BEI -->
<Key
- latin:keyLabel="&#x17E8;"
+ latin:keySpec="&#x17E8;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x17F8;"
@@ -162,7 +163,7 @@
<!-- U+17E9: "៩" KHMER DIGIT NINE
U+17F9: "៹" KHMER SYMBOL LEK ATTAK PRAM-BUON -->
<Key
- latin:keyLabel="&#x17E9;"
+ latin:keySpec="&#x17E9;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="&#x17F9;"
@@ -170,7 +171,7 @@
<!-- U+17E0: "០" KHMER DIGIT ZERO
U+17F0: "៰" KHMER SYMBOL LEK ATTAK SON -->
<Key
- latin:keyLabel="&#x17E0;"
+ latin:keySpec="&#x17E0;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0"
latin:moreKeys="&#x17F0;"
@@ -178,14 +179,14 @@
<!-- U+17A5: "ឥ" KHMER INDEPENDENT VOWEL QI
U+17A6: "ឦ" KHMER INDEPENDENT VOWEL QII -->
<Key
- latin:keyLabel="&#x17A5;"
+ latin:keySpec="&#x17A5;"
latin:keyHintLabel="&#x17A6;"
latin:moreKeys=",&#x17A6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17B2: "ឲ" KHMER INDEPENDENT VOWEL QOO TYPE TWO
U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE -->
<Key
- latin:keyLabel="&#x17B2;"
+ latin:keySpec="&#x17B2;"
latin:keyHintLabel="&#x17B1;"
latin:moreKeys="&#x17B1;"
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="&#x1788;"
+ latin:keySpec="&#x1788;"
latin:keyHintLabel="&#x17DC;"
latin:moreKeys="&#x17DC;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keyLabelFlags="fontNormal|autoScale" />
<!-- U+17BA: "ឺ" KHMER VOWEL SIGN YY
U+17DD: "៝" KHMER SIGN ATTHACAN -->
<Key
- latin:keyLabel="&#x17BA;"
+ latin:keySpec="&#x17BA;"
latin:keyHintLabel="&#x17DD;"
+ latin:keyHintLabelVerticalAdjustment="40%"
latin:moreKeys="&#x17DD;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C2: "ែ" KHMER VOWEL SIGN AE -->
<Key
- latin:keyLabel="&#x17C2;"
+ latin:keySpec="&#x17C2;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17AC: "ឬ" KHMER INDEPENDENT VOWEL RYY
U+17AB: "ឫ" KHMER INDEPENDENT VOWEL RY -->
<Key
- latin:keyLabel="&#x17AC;"
+ latin:keySpec="&#x17AC;"
latin:keyHintLabel="&#x17AB;"
latin:moreKeys="&#x17AB;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1791: "ទ" KHMER LETTER TO -->
<Key
- latin:keyLabel="&#x1791;"
+ latin:keySpec="&#x1791;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BD: "ួ" KHMER VOWEL SIGN UA -->
<Key
- latin:keyLabel="&#x17BD;"
+ latin:keySpec="&#x17BD;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BC: "ូ" KHMER VOWEL SIGN UU -->
<Key
- latin:keyLabel="&#x17BC;"
+ latin:keySpec="&#x17BC;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17B8: "ី" KHMER VOWEL SIGN II -->
<Key
- latin:keyLabel="&#x17B8;"
+ latin:keySpec="&#x17B8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C5: "ៅ" KHMER VOWEL SIGN AU -->
<Key
- latin:keyLabel="&#x17C5;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17C5;"
+ latin:keyLabelFlags="fontNormal|autoScale" />
<!-- U+1797: "ភ" KHMER LETTER PHO -->
<Key
- latin:keyLabel="&#x1797;"
+ latin:keySpec="&#x1797;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BF: "ឿ" KHMER VOWEL SIGN YA -->
<Key
- latin:keyLabel="&#x17BF;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17BF;"
+ latin:keyLabelFlags="fontNormal|autoScale" />
<!-- U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI -->
<Key
- latin:keyLabel="&#x17B0;"
+ latin:keySpec="&#x17B0;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+1786: "ឆ" KHMER LETTER CHA -->
<Key
- latin:keyLabel="&#x1786;"
+ latin:keySpec="&#x1786;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17B9: "ឹ" KHMER VOWEL SIGN Y -->
<Key
- latin:keyLabel="&#x17B9;"
+ latin:keySpec="&#x17B9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C1: "េ" KHMER VOWEL SIGN E -->
<Key
- latin:keyLabel="&#x17C1;"
+ latin:keySpec="&#x17C1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+179A: "រ" KHMER LETTER RO -->
<Key
- latin:keyLabel="&#x179A;"
+ latin:keySpec="&#x179A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+178F: "ត" KHMER LETTER TA -->
<Key
- latin:keyLabel="&#x178F;"
+ latin:keySpec="&#x178F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1799: "យ" KHMER LETTER YO -->
<Key
- latin:keyLabel="&#x1799;"
+ latin:keySpec="&#x1799;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BB: "ុ" KHMER VOWEL SIGN U -->
<Key
- latin:keyLabel="&#x17BB;"
+ latin:keySpec="&#x17BB;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17B7: "ិ" KHMER VOWEL SIGN I -->
<Key
- latin:keyLabel="&#x17B7;"
+ latin:keySpec="&#x17B7;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C4: "ោ" KHMER VOWEL SIGN OO -->
<Key
- latin:keyLabel="&#x17C4;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17C4;"
+ latin:keyLabelFlags="fontNormal|autoScale" />
<!-- U+1795: "ផ" KHMER LETTER PHA -->
<Key
- latin:keyLabel="&#x1795;"
+ latin:keySpec="&#x1795;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C0: "ៀ" KHMER VOWEL SIGN IE -->
<Key
- latin:keyLabel="&#x17C0;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17C0;"
+ 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="&#x17AA;"
+ latin:keySpec="&#x17AA;"
latin:keyHintLabel="&#x17A7;"
latin:moreKeys="&#x17A7;,&#x17B1;,&#x17B3;,&#x17A9;,&#x17A8;"
latin:keyLabelFlags="fontNormal" />
diff --git a/java/res/xml/rowkeys_khmer3.xml b/java/res/xml/rowkeys_khmer3.xml
index ff6c9ca51..7a2efa7da 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="&#x17B6;&#x17C6;"
+ latin:keySpec="&#x17B6;&#x17C6;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+17C3: "ៃ" KHMER VOWEL SIGN AI -->
<Key
- latin:keyLabel="&#x17C3;"
+ latin:keySpec="&#x17C3;"
latin:keyLabelFlags="fontNormal" />
<!-- U+178C: "ឌ" KHMER LETTER DO -->
<Key
- latin:keyLabel="&#x178C;"
+ latin:keySpec="&#x178C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1792: "ធ" KHMER LETTER THO -->
<Key
- latin:keyLabel="&#x1792;"
+ latin:keySpec="&#x1792;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17A2: "អ" KHMER LETTER QA -->
<Key
- latin:keyLabel="&#x17A2;"
+ latin:keySpec="&#x17A2;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C7: "ះ" KHMER SIGN REAHMUK
U+17C8: "ៈ" KHMER SIGN YUUKALEAPINTU;-->
<Key
- latin:keyLabel="&#x17C7;"
+ latin:keySpec="&#x17C7;"
latin:keyHintLabel="&#x17C8;"
latin:moreKeys="&#x17C8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1789: "ញ" KHMER LETTER NYO -->
<Key
- latin:keyLabel="&#x1789;"
+ latin:keySpec="&#x1789;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1782: "គ" KHMER LETTER KO
U+179D: "ឝ" KHMER LETTER SHA -->
<Key
- latin:keyLabel="&#x1782;"
+ latin:keySpec="&#x1782;"
latin:keyHintLabel="&#x179D;"
latin:moreKeys="&#x179D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17A1: "ឡ" KHMER LETTER LA -->
<Key
- latin:keyLabel="&#x17A1;"
+ latin:keySpec="&#x17A1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C4/U+17C7: "ោះ" KHMER VOWEL SIGN OO/KHMER SIGN REAHMUK -->
<Key
- latin:keyLabel="&#x17C4;&#x17C7;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17C4;&#x17C7;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio|autoScale" />
<!-- U+17C9: "៉" KHMER SIGN MUUSIKATOAN -->
<Key
- latin:keyLabel="&#x17C9;"
+ latin:keySpec="&#x17C9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17AF: "ឯ" KHMER INDEPENDENT VOWEL QE -->
<Key
- latin:keyLabel="&#x17AF;"
+ latin:keySpec="&#x17AF;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+17B6: "ា" KHMER VOWEL SIGN AA -->
<Key
- latin:keyLabel="&#x17B6;"
+ latin:keySpec="&#x17B6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+179F: "ស" KHMER LETTER SA -->
<Key
- latin:keyLabel="&#x179F;"
+ latin:keySpec="&#x179F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+178A: "ដ" KHMER LETTER DA -->
<Key
- latin:keyLabel="&#x178A;"
+ latin:keySpec="&#x178A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1790: "ថ" KHMER LETTER THA -->
<Key
- latin:keyLabel="&#x1790;"
+ latin:keySpec="&#x1790;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1784: "ង" KHMER LETTER NGO -->
<Key
- latin:keyLabel="&#x1784;"
+ latin:keySpec="&#x1784;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17A0: "ហ" KHMER LETTER HA -->
<Key
- latin:keyLabel="&#x17A0;"
+ latin:keySpec="&#x17A0;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17D2: "្" KHMER SIGN COENG -->
<Key
- latin:keyLabel="&#x17D2;"
+ latin:keySpec="&#x17D2;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1780: "ក" KHMER LETTER KA -->
<Key
- latin:keyLabel="&#x1780;"
+ latin:keySpec="&#x1780;"
latin:keyLabelFlags="fontNormal" />
<!-- U+179B: "ល" KHMER LETTER LO -->
<Key
- latin:keyLabel="&#x179B;"
+ latin:keySpec="&#x179B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BE: "ើ" KHMER VOWEL SIGN OE -->
<Key
- latin:keyLabel="&#x17BE;"
+ latin:keySpec="&#x17BE;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17CB: "់" KHMER SIGN BANTOC -->
<Key
- latin:keyLabel="&#x17CB;"
+ latin:keySpec="&#x17CB;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17AE: "ឮ" KHMER INDEPENDENT VOWEL LYY
U+17AD: "ឭ" KHMER INDEPENDENT VOWEL LY
U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI -->
<Key
- latin:keyLabel="&#x17AE;"
+ latin:keySpec="&#x17AE;"
latin:keyHintLabel="&#x17AD;"
latin:moreKeys="&#x17AD;,&#x17B0;"
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="&#x178D;"
+ latin:keySpec="&#x178D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1783: "ឃ" KHMER LETTER KHO -->
<Key
- latin:keyLabel="&#x1783;"
+ latin:keySpec="&#x1783;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1787: "ជ" KHMER LETTER CO -->
<Key
- latin:keyLabel="&#x1787;"
+ latin:keySpec="&#x1787;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17C1/U+17C7: "េះ" KHMER VOWEL SIGN E/KHMER SIGN REAHMUK -->
<Key
- latin:keyLabel="&#x17C1;&#x17C7;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x17C1;&#x17C7;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio|autoScale" />
<!-- U+1796: "ព" KHMER LETTER PO
U+179E: "ឞ" KHMER LETTER SSO -->
<Key
- latin:keyLabel="&#x1796;"
+ latin:keySpec="&#x1796;"
latin:keyHintLabel="&#x179E;"
latin:moreKeys="&#x179E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+178E: "ណ" KHMER LETTER NNO -->
<Key
- latin:keyLabel="&#x178E;"
- latin:keyLabelFlags="fontNormal" />
+ latin:keySpec="&#x178E;"
+ latin:keyLabelFlags="fontNormal|autoScale" />
<!-- U+17C6: "ំ" KHMER SIGN NIKAHIT -->
<Key
- latin:keyLabel="&#x17C6;"
+ latin:keySpec="&#x17C6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BB/U+17C7: "ុះ" KHMER VOWEL SIGN U/KHMER SIGN REAHMUK -->
<Key
- latin:keyLabel="&#x17BB;&#x17C7;"
+ latin:keySpec="&#x17BB;&#x17C7;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+17D5: "៕" KHMER SIGN BARIYOOSAN -->
<Key
- latin:keyLabel="&#x17D5;"
+ latin:keySpec="&#x17D5;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="\?" />
+ latin:keySpec="\?" />
</case>
<default>
<!-- U+178B: "ឋ" KHMER LETTER TTHA -->
<Key
- latin:keyLabel="&#x178B;"
+ latin:keySpec="&#x178B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1781: "ខ" KHMER LETTER KHA -->
<Key
- latin:keyLabel="&#x1781;"
+ latin:keySpec="&#x1781;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1785: "ច" KHMER LETTER CA -->
<Key
- latin:keyLabel="&#x1785;"
+ latin:keySpec="&#x1785;"
latin:keyLabelFlags="fontNormal" />
<!-- U+179C: "វ" KHMER LETTER VO -->
<Key
- latin:keyLabel="&#x179C;"
+ latin:keySpec="&#x179C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1794: "ប" KHMER LETTER BA -->
<Key
- latin:keyLabel="&#x1794;"
+ latin:keySpec="&#x1794;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1793: "ន" KHMER LETTER NO -->
<Key
- latin:keyLabel="&#x1793;"
+ latin:keySpec="&#x1793;"
latin:keyLabelFlags="fontNormal" />
<!-- U+1798: "ម" KHMER LETTER MO -->
<Key
- latin:keyLabel="&#x1798;"
+ latin:keySpec="&#x1798;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17BB/U+17C6: "ុំ" KHMER VOWEL SIGN U/KHMER SIGN NIKAHIT -->
<Key
- latin:keyLabel="&#x17BB;&#x17C6;"
+ latin:keySpec="&#x17BB;&#x17C6;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+17D4: "។" KHMER SIGN KHAN -->
<Key
- latin:keyLabel="&#x17D4;"
+ latin:keySpec="&#x17D4;"
latin:keyLabelFlags="fontNormal" />
<!-- U+17CA: "៊" KHMER SIGN TRIISAP -->
<Key
- latin:keyLabel="&#x17CA;"
+ latin:keySpec="&#x17CA;"
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="&#x0ED1;"
+ latin:keySpec="&#x0ED1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED2: "໒" LAO DIGIT TWO -->
<Key
- latin:keyLabel="&#x0ED2;"
+ latin:keySpec="&#x0ED2;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED3: "໓" LAO DIGIT THREE -->
<Key
- latin:keyLabel="&#x0ED3;"
+ latin:keySpec="&#x0ED3;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED4: "໔" LAO DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0ED4;"
+ latin:keySpec="&#x0ED4;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ECC: "໌" LAO CANCELLATION MARK -->
<Key
- latin:keyLabel="&#x0ECC;"
+ latin:keySpec="&#x0ECC;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EBC: "ຼ" LAO SEMIVOWEL SIGN LO -->
<Key
- latin:keyLabel="&#x0EBC;"
+ latin:keySpec="&#x0EBC;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED5: "໕" LAO DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0ED5;"
+ latin:keySpec="&#x0ED5;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED6: "໖" LAO DIGIT SIX -->
<Key
- latin:keyLabel="&#x0ED6;"
+ latin:keySpec="&#x0ED6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED7: "໗" LAO DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0ED7;"
+ latin:keySpec="&#x0ED7;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED8: "໘" LAO DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0ED8;"
+ latin:keySpec="&#x0ED8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ED9: "໙" LAO DIGIT NINE -->
<Key
- latin:keyLabel="&#x0ED9;"
+ latin:keySpec="&#x0ED9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ECD/U+0EC8: "ໍ່" LAO NIGGAHITA/LAO TONE MAI EK -->
<Key
- latin:keyLabel="&#x0ECD;&#x0EC8;"
+ latin:keySpec="&#x0ECD;&#x0EC8;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</case>
<default>
<!-- U+0EA2: "ຢ" LAO LETTER YO
U+0ED1: "໑" LAO DIGIT ONE -->
<Key
- latin:keyLabel="&#x0EA2;"
+ latin:keySpec="&#x0EA2;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:moreKeys="&#x0ED1;"
@@ -86,7 +86,7 @@
<!-- U+0E9F: "ຟ" LAO LETTER FO SUNG
U+0ED2: "໒" LAO DIGIT TWO -->
<Key
- latin:keyLabel="&#x0E9F;"
+ latin:keySpec="&#x0E9F;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="&#x0ED2;"
@@ -94,7 +94,7 @@
<!-- U+0EC2: "ໂ" LAO VOWEL SIGN O
U+0ED3: "໓" LAO DIGIT THREE -->
<Key
- latin:keyLabel="&#x0EC2;"
+ latin:keySpec="&#x0EC2;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&#x0ED3;"
@@ -102,23 +102,23 @@
<!-- U+0E96: "ຖ" LAO LETTER THO SUNG
U+0ED4: "໔" LAO DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0E96;"
+ latin:keySpec="&#x0E96;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="&#x0ED4;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB8: "ຸ" LAO VOWEL SIGN U -->
<Key
- latin:keyLabel="&#x0EB8;"
+ latin:keySpec="&#x0EB8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB9: "ູ" LAO VOWEL SIGN UU -->
<Key
- latin:keyLabel="&#x0EB9;"
+ latin:keySpec="&#x0EB9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E84: "ຄ" LAO LETTER KHO TAM
U+0ED5: "໕" LAO DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0E84;"
+ latin:keySpec="&#x0E84;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="&#x0ED5;"
@@ -126,7 +126,7 @@
<!-- U+0E95: "ຕ" LAO LETTER TO
U+0ED6: "໖" LAO DIGIT SIX -->
<Key
- latin:keyLabel="&#x0E95;"
+ latin:keySpec="&#x0E95;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="&#x0ED6;"
@@ -134,7 +134,7 @@
<!-- U+0E88: "ຈ" LAO LETTER CO
U+0ED7: "໗" LAO DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0E88;"
+ latin:keySpec="&#x0E88;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="&#x0ED7;"
@@ -142,7 +142,7 @@
<!-- U+0E82: "ຂ" LAO LETTER KHO SUNG
U+0ED8: "໘" LAO DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0E82;"
+ latin:keySpec="&#x0E82;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x0ED8;"
@@ -150,14 +150,14 @@
<!-- U+0E8A: "ຊ" LAO LETTER SO TAM
U+0ED9: "໙" LAO DIGIT NINE -->
<Key
- latin:keyLabel="&#x0E8A;"
+ latin:keySpec="&#x0E8A;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="&#x0ED9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ECD: "ໍ" LAO NIGGAHITA -->
<Key
- latin:keyLabel="&#x0ECD;"
+ latin:keySpec="&#x0ECD;"
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="&#x0EBB;&#x0EC9;"
+ latin:keySpec="&#x0EBB;&#x0EC9;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0ED0: "໐" LAO DIGIT ZERO -->
<Key
- latin:keyLabel="&#x0ED0;"
+ latin:keySpec="&#x0ED0;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB3/U+0EC9: "ຳ້" LAO VOWEL SIGN AM/LAO TONE MAI THO -->
<Key
- latin:keyLabel="&#x0EB3;&#x0EC9;"
+ latin:keySpec="&#x0EB3;&#x0EC9;"
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="&#x0EB4;&#x0EC9;"
+ latin:keySpec="&#x0EB4;&#x0EC9;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0EB5/U+0EC9: "ີ້" LAO VOWEL SIGN II/LAO TONE MAI THO -->
<Key
- latin:keyLabel="&#x0EB5;&#x0EC9;"
+ latin:keySpec="&#x0EB5;&#x0EC9;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0EA3: "ຣ" LAO LETTER LO LING -->
<Key
- latin:keyLabel="&#x0EA3;"
+ latin:keySpec="&#x0EA3;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EDC: "ໜ" LAO HO NO -->
<Key
- latin:keyLabel="&#x0EDC;"
+ latin:keySpec="&#x0EDC;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EBD: "ຽ" LAO SEMIVOWEL SIGN NYO -->
<Key
- latin:keyLabel="&#x0EBD;"
+ latin:keySpec="&#x0EBD;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EAB/U+0EBC: "" LAO LETTER HO SUNG/LAO SEMIVOWEL SIGN LO -->
<Key
- latin:keyLabel="&#x0EAB;&#x0EBC;"
+ latin:keySpec="&#x0EAB;&#x0EBC;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+201D: "”" RIGHT DOUBLE QUOTATION MARK -->
<Key
- latin:keyLabel="&#x201D;" />
+ latin:keySpec="&#x201D;" />
</case>
<default>
<!-- U+0EBB: "ົ" LAO VOWEL SIGN MAI KON -->
<Key
- latin:keyLabel="&#x0EBB;"
+ latin:keySpec="&#x0EBB;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC4: "ໄ" LAO VOWEL SIGN AI
U+0ED0: "໐" LAO DIGIT ZERO -->
<Key
- latin:keyLabel="&#x0EC4;"
+ latin:keySpec="&#x0EC4;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0"
latin:moreKeys="&#x0ED0;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB3: "ຳ" LAO VOWEL SIGN AM -->
<Key
- latin:keyLabel="&#x0EB3;"
+ latin:keySpec="&#x0EB3;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E9E: "ພ" LAO LETTER PHO TAM -->
<Key
- latin:keyLabel="&#x0E9E;"
+ latin:keySpec="&#x0E9E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB0: "ະ" LAO VOWEL SIGN A -->
<Key
- latin:keyLabel="&#x0EB0;"
+ latin:keySpec="&#x0EB0;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB4: "ິ" LAO VOWEL SIGN I -->
<Key
- latin:keyLabel="&#x0EB4;"
+ latin:keySpec="&#x0EB4;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB5: "ີ" LAO VOWEL SIGN II -->
<Key
- latin:keyLabel="&#x0EB5;"
+ latin:keySpec="&#x0EB5;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EAE: "ຮ" LAO LETTER HO TAM -->
<Key
- latin:keyLabel="&#x0EAE;"
+ latin:keySpec="&#x0EAE;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E99: "ນ" LAO LETTER NO -->
<Key
- latin:keyLabel="&#x0E99;"
+ latin:keySpec="&#x0E99;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E8D: "ຍ" LAO LETTER NYO -->
<Key
- latin:keyLabel="&#x0E8D;"
+ latin:keySpec="&#x0E8D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E9A: "ບ" LAO LETTER BO -->
<Key
- latin:keyLabel="&#x0E9A;"
+ latin:keySpec="&#x0E9A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EA5: "ລ" LAO LETTER LO LOOT -->
<Key
- latin:keyLabel="&#x0EA5;"
+ latin:keySpec="&#x0EA5;"
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="&#x0EB1;&#x0EC9;"
+ latin:keySpec="&#x0EB1;&#x0EC9;"
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="&#x0ECA;"
+ latin:keySpec="&#x0ECA;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0ECB: "໋" LAO TONE MAI CATAWA -->
<Key
- latin:keyLabel="&#x0ECB;"
+ latin:keySpec="&#x0ECB;"
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="&#x201C;" />
+ latin:keySpec="&#x201C;" />
</case>
<default>
<!-- U+0EB1: "ັ" LAO VOWEL SIGN MAI KAN -->
<Key
- latin:keyLabel="&#x0EB1;"
+ latin:keySpec="&#x0EB1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EAB: "ຫ" LAO LETTER HO SUNG -->
<Key
- latin:keyLabel="&#x0EAB;"
+ latin:keySpec="&#x0EAB;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E81: "ກ" LAO LETTER KO -->
<Key
- latin:keyLabel="&#x0E81;"
+ latin:keySpec="&#x0E81;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E94: "ດ" LAO LETTER DO -->
<Key
- latin:keyLabel="&#x0E94;"
+ latin:keySpec="&#x0E94;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC0: "ເ" LAO VOWEL SIGN E -->
<Key
- latin:keyLabel="&#x0EC0;"
+ latin:keySpec="&#x0EC0;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC9: "້" LAO TONE MAI THO -->
<Key
- latin:keyLabel="&#x0EC9;"
+ latin:keySpec="&#x0EC9;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC8: "່" LAO TONE MAI EK -->
<Key
- latin:keyLabel="&#x0EC8;"
+ latin:keySpec="&#x0EC8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB2: "າ" LAO VOWEL SIGN AA -->
<Key
- latin:keyLabel="&#x0EB2;"
+ latin:keySpec="&#x0EB2;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EAA: "ສ" LAO LETTER SO SUNG -->
<Key
- latin:keyLabel="&#x0EAA;"
+ latin:keySpec="&#x0EAA;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EA7: "ວ" LAO LETTER WO -->
<Key
- latin:keyLabel="&#x0EA7;"
+ latin:keySpec="&#x0EA7;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E87: "ງ" LAO LETTER NGO -->
<Key
- latin:keyLabel="&#x0E87;"
+ latin:keySpec="&#x0E87;"
latin:keyLabelFlags="fontNormal" />
<!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK -->
<Key
- latin:keyLabel="&#x201C;" />
+ latin:keySpec="&#x201C;" />
</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="&#x20AD;" />
+ latin:keySpec="&#x20AD;" />
<Key
- latin:keyLabel="(" />
+ latin:keySpec="(" />
<!-- U+0EAF: "ຯ" LAO ELLIPSIS -->
<Key
- latin:keyLabel="&#x0EAF;"
+ latin:keySpec="&#x0EAF;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="\@" />
+ latin:keySpec="\@" />
<!-- U+0EB6/U+0EC9: "ຶ້" LAO VOWEL SIGN Y/LAO TONE MAI THO -->
<Key
- latin:keyLabel="&#x0EB6;&#x0EC9;"
+ latin:keySpec="&#x0EB6;&#x0EC9;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0EB7/U+0EC9: "ື້" LAO VOWEL SIGN YY/LAO TONE MAI THO -->
<Key
- latin:keyLabel="&#x0EB7;&#x0EC9;"
+ latin:keySpec="&#x0EB7;&#x0EC9;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0EC6: "ໆ" LAO KO LA -->
<Key
- latin:keyLabel="&#x0EC6;"
+ latin:keySpec="&#x0EC6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EDD: "ໝ" LAO HO MO -->
<Key
- latin:keyLabel="&#x0EDD;"
+ latin:keySpec="&#x0EDD;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="$" />
+ latin:keySpec="$" />
<Key
- latin:keyLabel=")" />
+ latin:keySpec=")" />
</case>
<default>
<!-- U+0E9C: "ຜ" LAO LETTER PHO SUNG -->
<Key
- latin:keyLabel="&#x0E9C;"
+ latin:keySpec="&#x0E9C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E9B: "ປ" LAO LETTER PO -->
<Key
- latin:keyLabel="&#x0E9B;"
+ latin:keySpec="&#x0E9B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC1: "ແ" LAO VOWEL SIGN EI -->
<Key
- latin:keyLabel="&#x0EC1;"
+ latin:keySpec="&#x0EC1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EAD: "ອ" LAO LETTER O -->
<Key
- latin:keyLabel="&#x0EAD;"
+ latin:keySpec="&#x0EAD;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB6: "ຶ" LAO VOWEL SIGN Y -->
<Key
- latin:keyLabel="&#x0EB6;"
+ latin:keySpec="&#x0EB6;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EB7: "ື" LAO VOWEL SIGN YY -->
<Key
- latin:keyLabel="&#x0EB7;"
+ latin:keySpec="&#x0EB7;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E97: "ທ" LAO LETTER THO TAM -->
<Key
- latin:keyLabel="&#x0E97;"
+ latin:keySpec="&#x0E97;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EA1: "ມ" LAO LETTER MO -->
<Key
- latin:keyLabel="&#x0EA1;"
+ latin:keySpec="&#x0EA1;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0EC3: "ໃ" LAO VOWEL SIGN AY -->
<Key
- latin:keyLabel="&#x0EC3;"
+ latin:keySpec="&#x0EC3;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E9D: "ຝ" LAO LETTER FO TAM -->
<Key
- latin:keyLabel="&#x0E9D;"
+ latin:keySpec="&#x0E9D;"
latin:keyLabelFlags="fontNormal" />
</default>
</switch>
diff --git a/java/res/xml/rowkeys_mongolian1.xml b/java/res/xml/rowkeys_mongolian1.xml
index 6c8c8e2fd..4d3375545 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="&#x0444;"
+ latin:keySpec="&#x0444;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
<Key
- latin:keyLabel="&#x0446;"
+ latin:keySpec="&#x0446;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
<Key
- latin:keyLabel="&#x0443;"
+ latin:keySpec="&#x0443;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_cyrillic_u" />
<!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x0436;"
+ latin:keySpec="&#x0436;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+044D: "э" CYRILLIC SMALL LETTER E -->
<Key
- latin:keyLabel="&#x044D;"
+ latin:keySpec="&#x044D;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="!text/more_keys_for_cyrillic_ie" />
<!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
<Key
- latin:keyLabel="&#x043D;"
+ latin:keySpec="&#x043D;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_cyrillic_en" />
<!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
<Key
- latin:keyLabel="&#x0433;"
+ latin:keySpec="&#x0433;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_cyrillic_ghe" />
<!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA
U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
<Key
- latin:keyLabel="&#x0448;"
+ latin:keySpec="&#x0448;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x0449;" />
<!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U -->
<Key
- latin:keyLabel="&#x04AF;"
+ latin:keySpec="&#x04AF;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
<Key
- latin:keyLabel="&#x0437;"
+ latin:keySpec="&#x0437;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
<!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
<Key
- latin:keyLabel="&#x043A;" />
+ latin:keySpec="&#x043A;" />
</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="&#x0439;" />
+ latin:keySpec="&#x0439;" />
<!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU -->
<Key
- latin:keyLabel="&#x044B;" />
+ latin:keySpec="&#x044B;" />
<!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
<Key
- latin:keyLabel="&#x0431;" />
+ latin:keySpec="&#x0431;" />
<!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O -->
<Key
- latin:keyLabel="&#x04E9;" />
+ latin:keySpec="&#x04E9;" />
<!-- U+0430: "а" CYRILLIC SMALL LETTER A -->
<Key
- latin:keyLabel="&#x0430;" />
+ latin:keySpec="&#x0430;" />
<!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
<Key
- latin:keyLabel="&#x0445;" />
+ latin:keySpec="&#x0445;" />
<!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
<Key
- latin:keyLabel="&#x0440;" />
+ latin:keySpec="&#x0440;" />
<!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
<Key
- latin:keyLabel="&#x043E;" />
+ latin:keySpec="&#x043E;" />
<!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
<Key
- latin:keyLabel="&#x043B;" />
+ latin:keySpec="&#x043B;" />
<!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
<Key
- latin:keyLabel="&#x0434;" />
+ latin:keySpec="&#x0434;" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
- latin:keyLabel="&#x043F;" />
+ latin:keySpec="&#x043F;" />
</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="&#x044F;" />
+ latin:keySpec="&#x044F;" />
<!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
<Key
- latin:keyLabel="&#x0447;" />
+ latin:keySpec="&#x0447;" />
<!-- U+0451: "ё" CYRILLIC SMALL LETTER IO
U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
- latin:keyLabel="&#x0451;"
+ latin:keySpec="&#x0451;"
latin:moreKeys="&#x0435;" />
<!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
<Key
- latin:keyLabel="&#x0441;" />
+ latin:keySpec="&#x0441;" />
<!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
<Key
- latin:keyLabel="&#x043C;" />
+ latin:keySpec="&#x043C;" />
<!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
<Key
- latin:keyLabel="&#x0438;" />
+ latin:keySpec="&#x0438;" />
<!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
<Key
- latin:keyLabel="&#x0442;" />
+ latin:keySpec="&#x0442;" />
<!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN
U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
<Key
- latin:keyLabel="&#x044C;"
+ latin:keySpec="&#x044C;"
latin:moreKeys="&#x044A;" />
<!-- U+0432: "в" CYRILLIC SMALL LETTER VE
U+044E: "ю" CYRILLIC SMALL LETTER YU -->
<Key
- latin:keyLabel="&#x0432;"
+ latin:keySpec="&#x0432;"
latin:moreKeys="&#x044E;" />
</merge>
diff --git a/java/res/xml/rowkeys_nepali_romanized1.xml b/java/res/xml/rowkeys_nepali_romanized1.xml
index 408a96648..3c082c2fe 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="&#x0920;"
+ latin:keySpec="&#x0920;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0914: "औ" DEVANAGARI LETTER AU -->
<Key
- latin:keyLabel="&#x0914;"
+ latin:keySpec="&#x0914;"
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
@@ -47,11 +47,11 @@
latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" />
<!-- U+0925: "थ" DEVANAGARI LETTER THA -->
<Key
- latin:keyLabel="&#x0925;"
+ latin:keySpec="&#x0925;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091E: "ञ" DEVANAGARI LETTER NYA -->
<Key
- latin:keyLabel="&#x091E;"
+ latin:keySpec="&#x091E;"
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,15 +69,15 @@
latin:keyStyle="baseKeyDevanagariVowelSignIi" />
<!-- U+0913: "ओ" DEVANAGARI LETTER O -->
<Key
- latin:keyLabel="&#x0913;"
+ latin:keySpec="&#x0913;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092B: "फ" DEVANAGARI LETTER PHA -->
<Key
- latin:keyLabel="&#x092B;"
+ latin:keySpec="&#x092B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0908: "ई" DEVANAGARI LETTER II -->
<Key
- latin:keyLabel="&#x0908;"
+ latin:keySpec="&#x0908;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
@@ -85,7 +85,7 @@
U+0967: "१" DEVANAGARI DIGIT ONE
U+093C: "़" DEVANAGARI SIGN NUKTA -->
<Key
- latin:keyLabel="&#x091F;"
+ latin:keySpec="&#x091F;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="&#x0967;,1"
latin:moreKeys="&#x093C;"
@@ -113,21 +113,21 @@
<!-- U+0930: "र" DEVANAGARI LETTER RA
U+096A: "४" DEVANAGARI DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0930;"
+ latin:keySpec="&#x0930;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="&#x096A;,4"
latin:keyLabelFlags="fontNormal" />
<!-- U+0924: "त" DEVANAGARI LETTER TA
U+096B: "५" DEVANAGARI DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0924;"
+ latin:keySpec="&#x0924;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="&#x096B;,5"
latin:keyLabelFlags="fontNormal" />
<!-- U+092F: "य" DEVANAGARI LETTER YA
U+096C: "६" DEVANAGARI DIGIT SIX -->
<Key
- latin:keyLabel="&#x092F;"
+ latin:keySpec="&#x092F;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="&#x096C;,6"
latin:keyLabelFlags="fontNormal" />
@@ -164,13 +164,13 @@
<!-- U+092A: "प" DEVANAGARI LETTER PA
U+0966: "०" DEVANAGARI DIGIT ZERO -->
<Key
- latin:keyLabel="&#x092A;"
+ latin:keySpec="&#x092A;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="&#x0966;,0"
latin:keyLabelFlags="fontNormal" />
<!-- U+0907: "इ" DEVANAGARI LETTER I -->
<Key
- latin:keyLabel="&#x0907;"
+ latin:keySpec="&#x0907;"
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="&#x0906;"
+ latin:keySpec="&#x0906;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0936: "श" DEVANAGARI LETTER SHA -->
<Key
- latin:keyLabel="&#x0936;"
+ latin:keySpec="&#x0936;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0927: "ध" DEVANAGARI LETTER DHA -->
<Key
- latin:keyLabel="&#x0927;"
+ latin:keySpec="&#x0927;"
latin:keyLabelFlags="fontNormal" />
<!-- U+090A: "ऊ" DEVANAGARI LETTER UU -->
<Key
- latin:keyLabel="&#x090A;"
+ latin:keySpec="&#x090A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0918: "घ" DEVANAGARI LETTER GHA -->
<Key
- latin:keyLabel="&#x0918;"
+ latin:keySpec="&#x0918;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0905: "अ" DEVANAGARI LETTER A -->
<Key
- latin:keyLabel="&#x0905;"
+ latin:keySpec="&#x0905;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091D: "झ" DEVANAGARI LETTER JHA -->
<Key
- latin:keyLabel="&#x091D;"
+ latin:keySpec="&#x091D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
<Key
- latin:keyLabel="&#x0916;"
+ latin:keySpec="&#x0916;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0965: "॥" DEVANAGARI DOUBLE DANDA -->
<Key
- latin:keyLabel="&#x0965;"
+ latin:keySpec="&#x0965;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0910: "ऐ" DEVANAGARI LETTER AI -->
<Key
- latin:keyLabel="&#x0910;"
+ latin:keySpec="&#x0910;"
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="&#x0938;"
+ latin:keySpec="&#x0938;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0926: "द" DEVANAGARI LETTER DA -->
<Key
- latin:keyLabel="&#x0926;"
+ latin:keySpec="&#x0926;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0909: "उ" DEVANAGARI LETTER U -->
<Key
- latin:keyLabel="&#x0909;"
+ latin:keySpec="&#x0909;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0917: "ग" DEVANAGARI LETTER GA -->
<Key
- latin:keyLabel="&#x0917;"
+ latin:keySpec="&#x0917;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0939: "ह" DEVANAGARI LETTER HA -->
<Key
- latin:keyLabel="&#x0939;"
+ latin:keySpec="&#x0939;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091C: "ज" DEVANAGARI LETTER JA -->
<Key
- latin:keyLabel="&#x091C;"
+ latin:keySpec="&#x091C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0915: "क" DEVANAGARI LETTER KA -->
<Key
- latin:keyLabel="&#x0915;"
+ latin:keySpec="&#x0915;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0932: "ल" DEVANAGARI LETTER LA -->
<Key
- latin:keyLabel="&#x0932;"
+ latin:keySpec="&#x0932;"
latin:keyLabelFlags="fontNormal" />
<!-- U+090F: "ए" DEVANAGARI LETTER E -->
<Key
- latin:keyLabel="&#x090F;"
+ latin:keySpec="&#x090F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0950: "ॐ" DEVANAGARI OM -->
<Key
- latin:keyLabel="&#x0950;"
+ latin:keySpec="&#x0950;"
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..232d96e02 100644
--- a/java/res/xml/rowkeys_nepali_romanized3.xml
+++ b/java/res/xml/rowkeys_nepali_romanized3.xml
@@ -27,15 +27,15 @@
>
<!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
<Key
- latin:keyLabel="&#x090B;"
+ latin:keySpec="&#x090B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0922: "ढ" DEVANAGARI LETTER DDHA -->
<Key
- latin:keyLabel="&#x0922;"
+ latin:keySpec="&#x0922;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091B: "छ" DEVANAGARI LETTER CHA -->
<Key
- latin:keyLabel="&#x091B;"
+ latin:keySpec="&#x091B;"
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,11 +44,11 @@
latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
<!-- U+092D: "भ" DEVANAGARI LETTER BHA -->
<Key
- latin:keyLabel="&#x092D;"
+ latin:keySpec="&#x092D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
- latin:keyLabel="&#x0923;"
+ latin:keySpec="&#x0923;"
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
@@ -57,7 +57,7 @@
latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
<!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
<Key
- latin:keyLabel="&#x0919;"
+ latin:keySpec="&#x0919;"
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 +70,36 @@
<default>
<!-- U+0937: "ष" DEVANAGARI LETTER SSA -->
<Key
- latin:keyLabel="&#x0937;"
+ latin:keySpec="&#x0937;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0921: "ड" DEVANAGARI LETTER DDA -->
<Key
- latin:keyLabel="&#x0921;"
+ latin:keySpec="&#x0921;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091A: "च" DEVANAGARI LETTER CA -->
<Key
- latin:keyLabel="&#x091A;"
+ latin:keySpec="&#x091A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0935: "व" DEVANAGARI LETTER VA -->
<Key
- latin:keyLabel="&#x0935;"
+ latin:keySpec="&#x0935;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092C: "ब" DEVANAGARI LETTER BHA -->
<Key
- latin:keyLabel="&#x092C;"
+ latin:keySpec="&#x092C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0928: "न" DEVANAGARI LETTER NA -->
<Key
- latin:keyLabel="&#x0928;"
+ latin:keySpec="&#x0928;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092E: "म" DEVANAGARI LETTER MA -->
<Key
- latin:keyLabel="&#x092E;"
+ latin:keySpec="&#x092E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0964: "।" DEVANAGARI DANDA
U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
<Key
- latin:keyLabel="&#x0964;"
+ latin:keySpec="&#x0964;"
latin:moreKeys="&#x093D;"
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..98a7be260 100644
--- a/java/res/xml/rowkeys_nepali_traditional1.xml
+++ b/java/res/xml/rowkeys_nepali_traditional1.xml
@@ -30,61 +30,61 @@
U+091C/U+094D/U+091E: "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA
U+0965: "॥" DEVANAGARI DOUBLE DANDA -->
<Key
- latin:keyLabel="&#x0924;&#x094D;&#x0924;"
+ latin:keySpec="&#x0924;&#x094D;&#x0924;"
latin:moreKeys="&#x091E;,&#x091C;&#x094D;&#x091E;,&#x0965;"
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="&#x0921;&#x094D;&#x0922;"
+ latin:keySpec="&#x0921;&#x094D;&#x0922;"
latin:moreKeys="&#x0908;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0910: "ऐ" DEVANAGARI LETTER AI
U+0918: "घ" DEVANAGARI LETTER GHA -->
<Key
- latin:keyLabel="&#x0910;"
+ latin:keySpec="&#x0910;"
latin:moreKeys="&#x0918;"
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="&#x0926;&#x094D;&#x0935;"
+ latin:keySpec="&#x0926;&#x094D;&#x0935;"
latin:moreKeys="&#x0926;&#x094D;&#x0927;"
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="&#x091F;&#x094D;&#x091F;"
+ latin:keySpec="&#x091F;&#x094D;&#x091F;"
latin:moreKeys="&#x091B;"
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="&#x0920;&#x094D;&#x0920;"
+ latin:keySpec="&#x0920;&#x094D;&#x0920;"
latin:moreKeys="&#x091F;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+090A: "ऊ" DEVANAGARI LETTER UU
U+0920: "ठ" DEVANAGARI LETTER TTHA -->
<Key
- latin:keyLabel="&#x090A;"
+ latin:keySpec="&#x090A;"
latin:moreKeys="&#x0920;"
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="&#x0915;&#x094D;&#x0937;"
+ latin:keySpec="&#x0915;&#x094D;&#x0937;"
latin:moreKeys="&#x0921;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0907: "इ" DEVANAGARI LETTER I
U+0922: "ढ" DEVANAGARI LETTER DDHA -->
<Key
- latin:keyLabel="&#x0907;"
+ latin:keySpec="&#x0907;"
latin:moreKeys="&#x0922;"
latin:keyLabelFlags="fontNormal" />
<!-- U+090F: "ए" DEVANAGARI LETTER E
U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
- latin:keyLabel="&#x090F;"
+ latin:keySpec="&#x090F;"
latin:moreKeys="&#x0923;"
latin:keyLabelFlags="fontNormal" />
<!-- Because the font rendering system prior to API version 16 can't automatically
@@ -97,77 +97,77 @@
<!-- U+091F: "ट" DEVANAGARI LETTER TTA
U+0967: "१" DEVANAGARI DIGIT ONE -->
<Key
- latin:keyLabel="&#x091F;"
+ latin:keySpec="&#x091F;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="&#x0967;,1"
latin:keyLabelFlags="fontNormal" />
<!-- U+0927: "ध" DEVANAGARI LETTER DHA
U+0968: "२" DEVANAGARI DIGIT TWO -->
<Key
- latin:keyLabel="&#x0927;"
+ latin:keySpec="&#x0927;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="&#x0968;,2"
latin:keyLabelFlags="fontNormal" />
<!-- U+092D: "भ" DEVANAGARI LETTER BHA
U+0969: "३" DEVANAGARI DIGIT THREE -->
<Key
- latin:keyLabel="&#x092D;"
+ latin:keySpec="&#x092D;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="&#x0969;,3"
latin:keyLabelFlags="fontNormal" />
<!-- U+091A: "च" DEVANAGARI LETTER CA
U+096A: "४" DEVANAGARI DIGIT FOUR -->
<Key
- latin:keyLabel="&#x091A;"
+ latin:keySpec="&#x091A;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="&#x096A;,4"
latin:keyLabelFlags="fontNormal" />
<!-- U+0924: "त" DEVANAGARI LETTER TA
U+096B: "५" DEVANAGARI DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0924;"
+ latin:keySpec="&#x0924;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="&#x096B;,5"
latin:keyLabelFlags="fontNormal" />
<!-- U+0925: "थ" DEVANAGARI LETTER THA
U+096C: "६" DEVANAGARI DIGIT SIX -->
<Key
- latin:keyLabel="&#x0925;"
+ latin:keySpec="&#x0925;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="&#x096C;,6"
latin:keyLabelFlags="fontNormal" />
<!-- U+0917: "ग" DEVANAGARI LETTER G
U+096D: "७" DEVANAGARI DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0917;"
+ latin:keySpec="&#x0917;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="&#x096D;,7"
latin:keyLabelFlags="fontNormal" />
<!-- U+0937: "ष" DEVANAGARI LETTER SSA
U+096E: "८" DEVANAGARI DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0937;"
+ latin:keySpec="&#x0937;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="&#x096E;,8"
latin:keyLabelFlags="fontNormal" />
<!-- U+092F: "य" DEVANAGARI LETTER YA
U+096F: "९" DEVANAGARI DIGIT NINE -->
<Key
- latin:keyLabel="&#x092F;"
+ latin:keySpec="&#x092F;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="&#x096F;,9"
latin:keyLabelFlags="fontNormal" />
<!-- U+0909: "उ" DEVANAGARI LETTER U
U+0966: "०" DEVANAGARI DIGIT ZERO -->
<Key
- latin:keyLabel="&#x0909;"
+ latin:keySpec="&#x0909;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="&#x0966;,0"
latin:keyLabelFlags="fontNormal" />
<!-- U+0907: "इ" DEVANAGARI LETTER I
U+0914: "औ" DEVANAGARI LETTER AU -->
<Key
- latin:keyLabel="&#x0907;"
+ latin:keySpec="&#x0907;"
latin:moreKeys="&#x0914;"
latin:keyLabelFlags="fontNormal" />
</default>
diff --git a/java/res/xml/rowkeys_nepali_traditional2.xml b/java/res/xml/rowkeys_nepali_traditional2.xml
index 45620a9d7..5ea14ea0d 100644
--- a/java/res/xml/rowkeys_nepali_traditional2.xml
+++ b/java/res/xml/rowkeys_nepali_traditional2.xml
@@ -27,15 +27,15 @@
>
<!-- U+0906: "आ" DEVANAGARI LETTER AA -->
<Key
- latin:keyLabel="&#x0906;"
+ latin:keySpec="&#x0906;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0919/U+094D: "ङ्" DEVANAGARI LETTER NGA/DEVANAGARI SIGN VIRAMA -->
<Key
- latin:keyLabel="&#x0919;&#x094D;"
+ latin:keySpec="&#x0919;&#x094D;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0921/U+094D/U+0921: "ड्ड" DEVANAGARI LETTER DDA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DDA -->
<Key
- latin:keyLabel="&#x0921;&#x094D;&#x0921;"
+ latin:keySpec="&#x0921;&#x094D;&#x0921;"
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
@@ -44,11 +44,11 @@
latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
<!-- U+0926/U+094D/U+0926: "द्द" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DA -->
<Key
- latin:keyLabel="&#x0926;&#x094D;&#x0926;"
+ latin:keySpec="&#x0926;&#x094D;&#x0926;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+091D: "झ" DEVANAGARI LETTER JHA -->
<Key
- latin:keyLabel="&#x091D;"
+ latin:keySpec="&#x091D;"
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 +59,7 @@
latin:keyStyle="baseKeyDevanagariVowelSignO" />
<!-- U+092B: "फ" DEVANAGARI LETTER PHA -->
<Key
- latin:keyLabel="&#x092B;"
+ latin:keySpec="&#x092B;"
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 +70,7 @@
latin:keyStyle="baseKeyDevanagariVowelSignIi" />
<!-- U+091F/U+094D/U+0920: "ट्ठ" DEVANAGARI LETTER TTA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TTHA -->
<Key
- latin:keyLabel="&#x091F;&#x094D;&#x0920;"
+ latin:keySpec="&#x091F;&#x094D;&#x0920;"
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 +83,15 @@
<default>
<!-- U+092C: "ब" DEVANAGARI LETTER BA -->
<Key
- latin:keyLabel="&#x092C;"
+ latin:keySpec="&#x092C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0915: "क" DEVANAGARI LETTER KA -->
<Key
- latin:keyLabel="&#x0915;"
+ latin:keySpec="&#x0915;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092E: "म" DEVANAGARI LETTER MA -->
<Key
- latin:keyLabel="&#x092E;"
+ latin:keySpec="&#x092E;"
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 +102,19 @@
latin:keyStyle="baseKeyDevanagariVowelSignAa" />
<!-- U+0928: "न" DEVANAGARI LETTER NA -->
<Key
- latin:keyLabel="&#x0928;"
+ latin:keySpec="&#x0928;"
latin:keyLabelFlags="fontNormal" />
<!-- U+091C: "ज" DEVANAGARI LETTER JA -->
<Key
- latin:keyLabel="&#x091C;"
+ latin:keySpec="&#x091C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0935: "व" DEVANAGARI LETTER VA -->
<Key
- latin:keyLabel="&#x0935;"
+ latin:keySpec="&#x0935;"
latin:keyLabelFlags="fontNormal" />
<!-- U+092A: "प" DEVANAGARI LETTER PA -->
<Key
- latin:keyLabel="&#x092A;"
+ latin:keySpec="&#x092A;"
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 +125,7 @@
latin:keyStyle="baseKeyDevanagariVowelSignI" />
<!-- U+0938: "स" DEVANAGARI LETTER SA -->
<Key
- latin:keyLabel="&#x0938;"
+ latin:keySpec="&#x0938;"
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="&#x0915;&#x094D;"
+ latin:keySpec="&#x0915;&#x094D;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0939/U+094D/U+092E: "ह्म" DEVANAGARI LETTER HA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER MA -->
<Key
- latin:keyLabel="&#x0939;&#x094D;&#x092E;"
+ latin:keySpec="&#x0939;&#x094D;&#x092E;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
<Key
- latin:keyLabel="&#x090B;"
+ latin:keySpec="&#x090B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0950: "ॐ" DEVANAGARI OM -->
<Key
- latin:keyLabel="&#x0950;"
+ latin:keySpec="&#x0950;"
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="&#x0926;&#x094D;&#x092F;"
+ latin:keySpec="&#x0926;&#x094D;&#x092F;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</case>
<default>
<!-- U+0936: "श" DEVANAGARI LETTER SHA -->
<Key
- latin:keyLabel="&#x0936;"
+ latin:keySpec="&#x0936;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0939: "ह" DEVANAGARI LETTER HA -->
<Key
- latin:keyLabel="&#x0939;"
+ latin:keySpec="&#x0939;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0905: "अ" DEVANAGARI LETTER A -->
<Key
- latin:keyLabel="&#x0905;"
+ latin:keySpec="&#x0905;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
<Key
- latin:keyLabel="&#x0916;"
+ latin:keySpec="&#x0916;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0926: "द" DEVANAGARI LETTER DA -->
<Key
- latin:keyLabel="&#x0926;"
+ latin:keySpec="&#x0926;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0932: "ल" DEVANAGARI LETTER LA -->
<Key
- latin:keyLabel="&#x0932;"
+ latin:keySpec="&#x0932;"
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..d6a74d46a 100644
--- a/java/res/xml/rowkeys_nepali_traditional3_right3.xml
+++ b/java/res/xml/rowkeys_nepali_traditional3_right3.xml
@@ -32,7 +32,7 @@
latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
<!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
<Key
- latin:keyLabel="&#x0919;"
+ latin:keySpec="&#x0919;"
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 +52,12 @@
latin:keyStyle="baseKeyDevanagariVowelSignE" />
<!-- U+0964: "।" DEVANAGARI DANDA -->
<Key
- latin:keyLabel="&#x0964;"
+ latin:keySpec="&#x0964;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0930: "र" DEVANAGARI LETTER RA
U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
<Key
- latin:keyLabel="&#x0930;"
+ latin:keySpec="&#x0930;"
latin:moreKeys="&#x0930;&#x0941;"
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..a34f40097 100644
--- a/java/res/xml/rowkeys_nepali_traditional3_right5.xml
+++ b/java/res/xml/rowkeys_nepali_traditional3_right5.xml
@@ -32,7 +32,7 @@
latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
<!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
<Key
- latin:keyLabel="&#x0919;"
+ latin:keySpec="&#x0919;"
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,11 +43,11 @@
latin:keyStyle="baseKeyDevanagariVowelSignAi" />
<!-- U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
<Key
- latin:keyLabel="&#x0930;&#x0941;"
+ latin:keySpec="&#x0930;&#x0941;"
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
@@ -71,11 +71,11 @@
latin:keyStyle="baseKeyDevanagariVowelSignE" />
<!-- U+0964: "।" DEVANAGARI DANDA -->
<Key
- latin:keyLabel="&#x0964;"
+ latin:keySpec="&#x0964;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0930: "र" DEVANAGARI LETTER RA -->
<Key
- latin:keyLabel="&#x0930;"
+ latin:keySpec="&#x0930;"
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..40e556b98 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/keylabel_for_nordic_row1_11" />
</merge>
diff --git a/java/res/xml/rowkeys_nordic2.xml b/java/res/xml/rowkeys_nordic2.xml
index 836214abf..4064e4f27 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:keySpec="!text/keylabel_for_nordic_row2_10"
latin:moreKeys="!text/more_keys_for_nordic_row2_10" />
<Key
- latin:keyLabel="!text/keylabel_for_nordic_row2_11"
+ latin:keySpec="!text/keylabel_for_nordic_row2_11"
latin:moreKeys="!text/more_keys_for_nordic_row2_11" />
</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty1.xml b/java/res/xml/rowkeys_pcqwerty1.xml
index de548d0ba..fdb50729b 100644
--- a/java/res/xml/rowkeys_pcqwerty1.xml
+++ b/java/res/xml/rowkeys_pcqwerty1.xml
@@ -22,60 +22,60 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel="`"
+ latin:keySpec="`"
latin:additionalMoreKeys="~" />
<Key
- latin:keyLabel="1"
- latin:additionalMoreKeys="!,!text/more_keys_for_symbols_exclamation"
+ latin:keySpec="1"
+ latin:additionalMoreKeys="!,!text/more_keys_for_exclamation"
latin:moreKeys="!text/more_keys_for_symbols_1" />
<Key
- latin:keyLabel="2"
+ latin:keySpec="2"
latin:additionalMoreKeys="\@"
latin:moreKeys="!text/more_keys_for_symbols_2" />
<Key
- latin:keyLabel="3"
+ latin:keySpec="3"
latin:additionalMoreKeys="\#"
latin:moreKeys="!text/more_keys_for_symbols_3" />
<Key
- latin:keyLabel="4"
+ latin:keySpec="4"
latin:additionalMoreKeys="$"
latin:moreKeys="!text/more_keys_for_symbols_4" />
<Key
- latin:keyLabel="5"
+ latin:keySpec="5"
latin:additionalMoreKeys="\\%"
latin:moreKeys="!text/more_keys_for_symbols_5" />
<Key
- latin:keyLabel="6"
+ latin:keySpec="6"
latin:additionalMoreKeys="^"
latin:moreKeys="!text/more_keys_for_symbols_6" />
<Key
- latin:keyLabel="7"
+ latin:keySpec="7"
latin:additionalMoreKeys="&amp;"
latin:moreKeys="!text/more_keys_for_symbols_7" />
<Key
- latin:keyLabel="8"
+ latin:keySpec="8"
latin:additionalMoreKeys="*"
latin:moreKeys="!text/more_keys_for_symbols_8" />
<Key
- latin:keyLabel="9"
+ latin:keySpec="9"
latin:additionalMoreKeys="("
latin:moreKeys="!text/more_keys_for_symbols_9" />
<Key
- latin:keyLabel="0"
+ latin:keySpec="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:keySpec="-"
latin:additionalMoreKeys="_"
latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
<!-- U+221E: "∞" INFINITY
U+2260: "≠" NOT EQUAL TO
U+2248: "≈" ALMOST EQUAL TO -->
<Key
- latin:keyLabel="="
+ latin:keySpec="="
latin:additionalMoreKeys="+"
latin:moreKeys="!fixedColumnOrder!4,&#x221E;,&#x2260;,&#x2248;,%" />
</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty1_shift.xml b/java/res/xml/rowkeys_pcqwerty1_shift.xml
index bc39f944e..b9597c066 100644
--- a/java/res/xml/rowkeys_pcqwerty1_shift.xml
+++ b/java/res/xml/rowkeys_pcqwerty1_shift.xml
@@ -22,39 +22,39 @@
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/more_keys_for_exclamation" />
<Key
- latin:keyLabel="\@" />
+ latin:keySpec="\@" />
<Key
- latin:keyLabel="\#" />
+ latin:keySpec="\#" />
<Key
- latin:keyLabel="$"
+ latin:keySpec="$"
latin:additionalMoreKeys="!text/more_keys_for_currency_dollar" />
<Key
- latin:keyLabel="%"
+ latin:keySpec="%"
latin:additionalMoreKeys="!text/more_keys_for_symbols_percent" />
<Key
- latin:keyLabel="^" />
+ latin:keySpec="^" />
<Key
- latin:keyLabel="&amp;" />
+ latin:keySpec="&amp;" />
<Key
- latin:keyLabel="*"
+ latin:keySpec="*"
latin:additionalMoreKeys="!text/more_keys_for_star" />
<Key
- latin:keyLabel="(" />
+ latin:keySpec="(" />
<Key
- latin:keyLabel=")" />
+ latin:keySpec=")" />
<Key
- latin:keyLabel="_" />
+ latin:keySpec="_" />
<!-- U+00B1: "±" PLUS-MINUS SIGN
U+00D7: "×" MULTIPLICATION SIGN
U+00F7: "÷" DIVISION SIGN
U+221A: "√" SQUARE ROOT -->
<Key
- latin:keyLabel="+"
+ latin:keySpec="+"
latin:additionalMoreKeys="!text/more_keys_for_plus"
latin:moreKeys="&#x00B1;,&#x00D7;,&#x00F7;,&#x221A;" />
</merge>
diff --git a/java/res/xml/rowkeys_qwerty1.xml b/java/res/xml/rowkeys_qwerty1.xml
index e7c9b590b..7ebde8d00 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/keylabel_for_q"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:moreKeys="!text/more_keys_for_q" />
<Key
- latin:keyLabel="!text/keylabel_for_w"
+ latin:keySpec="!text/keylabel_for_w"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="!text/more_keys_for_w" />
<Key
- latin:keyLabel="e"
+ latin:keySpec="e"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_e" />
<Key
- latin:keyLabel="r"
+ latin:keySpec="r"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="!text/more_keys_for_r" />
<Key
- latin:keyLabel="t"
+ latin:keySpec="t"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="!text/more_keys_for_t" />
<Key
- latin:keyLabel="!text/keylabel_for_y"
+ latin:keySpec="!text/keylabel_for_y"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_y" />
<Key
- latin:keyLabel="u"
+ latin:keySpec="u"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_u" />
<Key
- latin:keyLabel="i"
+ latin:keySpec="i"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_i" />
<Key
- latin:keyLabel="o"
+ latin:keySpec="o"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="!text/more_keys_for_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..0700ccecd 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:keySpec="a"
latin:moreKeys="!text/more_keys_for_a" />
<Key
- latin:keyLabel="s"
+ latin:keySpec="s"
latin:moreKeys="!text/more_keys_for_s" />
<Key
- latin:keyLabel="d"
+ latin:keySpec="d"
latin:moreKeys="!text/more_keys_for_d" />
<Key
- latin:keyLabel="f" />
+ latin:keySpec="f" />
<Key
- latin:keyLabel="g"
+ latin:keySpec="g"
latin:moreKeys="!text/more_keys_for_g" />
<Key
- latin:keyLabel="h"
+ latin:keySpec="h"
latin:moreKeys="!text/more_keys_for_h" />
<Key
- latin:keyLabel="j"
+ latin:keySpec="j"
latin:moreKeys="!text/more_keys_for_j" />
<Key
- latin:keyLabel="k"
+ latin:keySpec="k"
latin:moreKeys="!text/more_keys_for_k" />
<Key
- latin:keyLabel="l"
+ latin:keySpec="l"
latin:moreKeys="!text/more_keys_for_l" />
</merge>
diff --git a/java/res/xml/rowkeys_qwerty3.xml b/java/res/xml/rowkeys_qwerty3.xml
index b70fd729f..b48606c25 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:keySpec="z"
latin:moreKeys="!text/more_keys_for_z" />
<Key
- latin:keyLabel="!text/keylabel_for_x"
+ latin:keySpec="!text/keylabel_for_x"
latin:moreKeys="!text/more_keys_for_x" />
<Key
- latin:keyLabel="c"
+ latin:keySpec="c"
latin:moreKeys="!text/more_keys_for_c" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
<Key
- latin:keyLabel="b" />
+ latin:keySpec="b" />
<Key
- latin:keyLabel="n"
+ latin:keySpec="n"
latin:moreKeys="!text/more_keys_for_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..61ce97b83 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" />
<Key
- latin:keyLabel="e"
+ latin:keySpec="e"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_e" />
<Key
- latin:keyLabel="r"
+ latin:keySpec="r"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="!text/more_keys_for_r" />
<Key
- latin:keyLabel="t"
+ latin:keySpec="t"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="!text/more_keys_for_t" />
<Key
- latin:keyLabel="z"
+ latin:keySpec="z"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="!text/more_keys_for_z" />
<Key
- latin:keyLabel="u"
+ latin:keySpec="u"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="!text/more_keys_for_u" />
<Key
- latin:keyLabel="i"
+ latin:keySpec="i"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_i" />
<Key
- latin:keyLabel="o"
+ latin:keySpec="o"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="!text/more_keys_for_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..55a8ffa18 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:keySpec="y"
latin:moreKeys="!text/more_keys_for_y" />
<Key
- latin:keyLabel="x" />
+ latin:keySpec="x" />
<Key
- latin:keyLabel="c"
+ latin:keySpec="c"
latin:moreKeys="!text/more_keys_for_c" />
<Key
- latin:keyLabel="v"
+ latin:keySpec="v"
latin:moreKeys="!text/more_keys_for_v" />
<Key
- latin:keyLabel="b" />
+ latin:keySpec="b" />
<Key
- latin:keyLabel="n"
+ latin:keySpec="n"
latin:moreKeys="!text/more_keys_for_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..8b1d696b7 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="&#x0459;"
+ latin:keySpec="&#x0459;"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
<!-- U+045A: "њ" CYRILLIC SMALL LETTER NJE -->
<Key
- latin:keyLabel="&#x045A;"
+ latin:keySpec="&#x045A;"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
<!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
- latin:keyLabel="&#x0435;"
+ latin:keySpec="&#x0435;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="!text/more_keys_for_cyrillic_ie" />
<!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
<Key
- latin:keyLabel="&#x0440;"
+ latin:keySpec="&#x0440;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
<!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
<Key
- latin:keyLabel="&#x0442;"
+ latin:keySpec="&#x0442;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<Key
- latin:keyLabel="!text/keylabel_for_south_slavic_row1_6"
+ latin:keySpec="!text/keylabel_for_south_slavic_row1_6"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6" />
<!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
<Key
- latin:keyLabel="&#x0443;"
+ latin:keySpec="&#x0443;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7" />
<!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
<Key
- latin:keyLabel="&#x0438;"
+ latin:keySpec="&#x0438;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="!text/more_keys_for_cyrillic_i" />
<!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
<Key
- latin:keyLabel="&#x043E;"
+ latin:keySpec="&#x043E;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
- latin:keyLabel="&#x043F;"
+ latin:keySpec="&#x043F;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0" />
<!-- U+0448: "ш" CYRILLIC SMALL LETTER SHA -->
<Key
- latin:keyLabel="&#x0448;" />
+ latin:keySpec="&#x0448;" />
</merge>
diff --git a/java/res/xml/rowkeys_south_slavic2.xml b/java/res/xml/rowkeys_south_slavic2.xml
index 88e894053..fa2426442 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="&#x0430;" />
+ latin:keySpec="&#x0430;" />
<!-- U+0441: "с" CYRILLIC SMALL LETTER ES -->
<Key
- latin:keyLabel="&#x0441;" />
+ latin:keySpec="&#x0441;" />
<!-- U+0434: "д" CYRILLIC SMALL LETTER DE -->
<Key
- latin:keyLabel="&#x0434;" />
+ latin:keySpec="&#x0434;" />
<!-- U+0444: "ф" CYRILLIC SMALL LETTER EF -->
<Key
- latin:keyLabel="&#x0444;" />
+ latin:keySpec="&#x0444;" />
<!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
<Key
- latin:keyLabel="&#x0433;" />
+ latin:keySpec="&#x0433;" />
<!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
<Key
- latin:keyLabel="&#x0445;" />
+ latin:keySpec="&#x0445;" />
<!-- U+0458: "ј" CYRILLIC SMALL LETTER JE -->
<Key
- latin:keyLabel="&#x0458;" />
+ latin:keySpec="&#x0458;" />
<!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
<Key
- latin:keyLabel="&#x043A;" />
+ latin:keySpec="&#x043A;" />
<!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
<Key
- latin:keyLabel="&#x043B;" />
+ latin:keySpec="&#x043B;" />
<!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
<Key
- latin:keyLabel="&#x0447;" />
+ latin:keySpec="&#x0447;" />
<Key
- latin:keyLabel="!text/keylabel_for_south_slavic_row2_11" />
+ latin:keySpec="!text/keylabel_for_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..8b54ec8c1 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/keylabel_for_south_slavic_row3_1" />
<!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE -->
<Key
- latin:keyLabel="&#x045F;" />
+ latin:keySpec="&#x045F;" />
<!-- U+0446: "ц" CYRILLIC SMALL LETTER TSE -->
<Key
- latin:keyLabel="&#x0446;" />
+ latin:keySpec="&#x0446;" />
<!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
<Key
- latin:keyLabel="&#x0432;" />
+ latin:keySpec="&#x0432;" />
<!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
<Key
- latin:keyLabel="&#x0431;" />
+ latin:keySpec="&#x0431;" />
<!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
<Key
- latin:keyLabel="&#x043D;" />
+ latin:keySpec="&#x043D;" />
<!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
<Key
- latin:keyLabel="&#x043C;" />
+ latin:keySpec="&#x043C;" />
<Key
- latin:keyLabel="!text/keylabel_for_south_slavic_row3_8" />
+ latin:keySpec="!text/keylabel_for_south_slavic_row3_8" />
<!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
<Key
- latin:keyLabel="&#x0436;" />
+ latin:keySpec="&#x0436;" />
</merge>
diff --git a/java/res/xml/rowkeys_spanish2.xml b/java/res/xml/rowkeys_spanish2.xml
index 335dff33c..68632fd2c 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/keylabel_for_spanish_row2_10" />
</merge>
diff --git a/java/res/layout/key_preview_gb.xml b/java/res/xml/rowkeys_swiss1.xml
index 2f2a321a3..458771d0c 100644
--- a/java/res/layout/key_preview_gb.xml
+++ b/java/res/xml/rowkeys_swiss1.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2010, 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,12 @@
*/
-->
-<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"
-/>
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwertz1" />
+ <Key
+ latin:keySpec="!text/keylabel_for_swiss_row1_11"
+ latin:moreKeys="!text/more_keys_for_swiss_row1_11" />
+</merge>
diff --git a/java/res/xml/key_space_3kw.xml b/java/res/xml/rowkeys_swiss2.xml
index 20ec882df..0c25fe806 100644
--- a/java/res/xml/key_space_3kw.xml
+++ b/java/res/xml/rowkeys_swiss2.xml
@@ -21,21 +21,12 @@
<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>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2" />
+ <Key
+ latin:keySpec="!text/keylabel_for_swiss_row2_10"
+ latin:moreKeys="!text/more_keys_for_swiss_row2_10" />
+ <Key
+ latin:keySpec="!text/keylabel_for_swiss_row2_11"
+ latin:moreKeys="!text/more_keys_for_swiss_row2_11" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols1.xml b/java/res/xml/rowkeys_symbols1.xml
index 6e2f92dd9..b35b18079 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:keySpec="!text/keylabel_for_symbols_1"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_1"
latin:moreKeys="!text/more_keys_for_symbols_1" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_2"
+ latin:keySpec="!text/keylabel_for_symbols_2"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_2"
latin:moreKeys="!text/more_keys_for_symbols_2" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_3"
+ latin:keySpec="!text/keylabel_for_symbols_3"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_3"
latin:moreKeys="!text/more_keys_for_symbols_3" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_4"
+ latin:keySpec="!text/keylabel_for_symbols_4"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_4"
latin:moreKeys="!text/more_keys_for_symbols_4" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_5"
+ latin:keySpec="!text/keylabel_for_symbols_5"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_5"
latin:moreKeys="!text/more_keys_for_symbols_5" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_6"
+ latin:keySpec="!text/keylabel_for_symbols_6"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_6"
latin:moreKeys="!text/more_keys_for_symbols_6" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_7"
+ latin:keySpec="!text/keylabel_for_symbols_7"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_7"
latin:moreKeys="!text/more_keys_for_symbols_7" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_8"
+ latin:keySpec="!text/keylabel_for_symbols_8"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_8"
latin:moreKeys="!text/more_keys_for_symbols_8" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_9"
+ latin:keySpec="!text/keylabel_for_symbols_9"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_9"
latin:moreKeys="!text/more_keys_for_symbols_9" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_0"
+ latin:keySpec="!text/keylabel_for_symbols_0"
latin:additionalMoreKeys="!text/additional_more_keys_for_symbols_0"
latin:moreKeys="!text/more_keys_for_symbols_0" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols2.xml b/java/res/xml/rowkeys_symbols2.xml
index 76cbf6259..fe8653d1c 100644
--- a/java/res/xml/rowkeys_symbols2.xml
+++ b/java/res/xml/rowkeys_symbols2.xml
@@ -28,36 +28,36 @@
<!-- U+066C: "٬" ARABIC THOUSANDS SEPARATOR
U+066B: "٫" ARABIC DECIMAL SEPARATOR -->
<Key
- latin:keyLabel="&#x066C;"
+ latin:keySpec="&#x066C;"
latin:keyHintLabel="\@"
latin:moreKeys="\@" />
<Key
- latin:keyLabel="&#x066B;"
+ latin:keySpec="&#x066B;"
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:keySpec="!text/keylabel_for_symbols_percent"
latin:moreKeys="!text/more_keys_for_symbols_percent" />
<Key
- latin:keyLabel="&amp;" />
+ latin:keySpec="&amp;" />
<!-- U+2013: "–" EN DASH
U+2014: "—" EM DASH
U+00B7: "·" MIDDLE DOT -->
<Key
- latin:keyLabel="-"
+ latin:keySpec="-"
latin:moreKeys="_,&#x2013;,&#x2014;,&#x00B7;" />
<Key
- latin:keyLabel="+"
+ latin:keySpec="+"
latin:moreKeys="!text/more_keys_for_plus" />
<include
latin:keyboardLayout="@xml/keys_parentheses" />
diff --git a/java/res/xml/rowkeys_symbols3.xml b/java/res/xml/rowkeys_symbols3.xml
index 074078cb6..3dbfe81fb 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:keySpec="*"
latin:moreKeys="!text/more_keys_for_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="&#x00AB;"
- latin:code="0x00BB"
+ latin:keySpec="!text/keyspec_left_double_angle_quote"
latin:moreKeys="!text/more_keys_for_double_quote" />
<Key
- latin:keyLabel="&#x00BB;"
- latin:code="0x00AB"
+ latin:keySpec="!text/keyspec_right_double_angle_quote"
latin:moreKeys="!text/more_keys_for_single_quote" />
</case>
<default>
<Key
- latin:keyLabel="&quot;"
+ latin:keySpec="&quot;"
latin:moreKeys="!text/more_keys_for_double_quote" />
<Key
- latin:keyLabel="\'"
+ latin:keySpec="\'"
latin:moreKeys="!text/more_keys_for_single_quote" />
</default>
</switch>
<Key
- latin:keyLabel=":" />
+ latin:keySpec=":" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_semicolon"
+ latin:keySpec="!text/keylabel_for_symbols_semicolon"
latin:moreKeys="!text/more_keys_for_symbols_semicolon" />
<Key
- latin:keyLabel="!"
- latin:moreKeys="!text/more_keys_for_symbols_exclamation" />
+ latin:keySpec="!"
+ latin:moreKeys="!text/more_keys_for_exclamation" />
<Key
- latin:keyLabel="!text/keylabel_for_symbols_question"
- latin:moreKeys="!text/more_keys_for_symbols_question" />
+ latin:keySpec="!text/keylabel_for_symbols_question"
+ latin:moreKeys="!text/more_keys_for_question" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols_shift1.xml b/java/res/xml/rowkeys_symbols_shift1.xml
index 6013493e5..7cb3213f0 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="&#x2022;"
+ latin:keySpec="&#x2022;"
latin:moreKeys="!text/more_keys_for_bullet" />
<!-- U+221A: "√" SQUARE ROOT -->
<Key
- latin:keyLabel="&#x221A;" />
+ latin:keySpec="&#x221A;" />
<!-- U+03A0: "Π" GREEK CAPITAL LETTER PI
U+03C0: "π" GREEK SMALL LETTER PI -->
<Key
- latin:keyLabel="&#x03A0;"
+ latin:keySpec="&#x03A0;"
latin:moreKeys="&#x03C0;" />
<!-- U+00F7: "÷" DIVISION SIGN -->
<Key
- latin:keyLabel="&#x00F7;" />
+ latin:keySpec="&#x00F7;" />
<!-- U+00D7: "×" MULTIPLICATION SIGN -->
<Key
- latin:keyLabel="&#x00D7;" />
+ latin:keySpec="&#x00D7;" />
<!-- U+00B6: "¶" PILCROW SIGN
U+00A7: "§" SECTION SIGN -->
<Key
- latin:keyLabel="&#x00B6;"
+ latin:keySpec="&#x00B6;"
latin:moreKeys="&#x00A7;" />
<!-- U+2206: "∆" INCREMENT -->
<Key
- latin:keyLabel="&#x2206;" />
+ latin:keySpec="&#x2206;" />
</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="&#x2191;,&#x2193;,&#x2190;,&#x2192;" />
<!-- U+00B0: "°" DEGREE SIGN
U+2032: "′" PRIME
U+2033: "″" DOUBLE PRIME -->
<Key
- latin:keyLabel="&#x00B0;"
+ latin:keySpec="&#x00B0;"
latin:moreKeys="&#x2032;,&#x2033;" />
<!-- U+2260: "≠" NOT EQUAL TO
U+2248: "≈" ALMOST EQUAL TO
U+221E: "∞" INFINITY -->
<Key
- latin:keyLabel="="
+ latin:keySpec="="
latin:moreKeys="&#x2260;,&#x2248;,&#x221E;" />
<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="&#x00A9;" />
+ latin:keySpec="&#x00A9;" />
<!-- U+00AE: "®" REGISTERED SIGN -->
<Key
- latin:keyLabel="&#x00AE;" />
+ latin:keySpec="&#x00AE;" />
<!-- U+2122: "™" TRADE MARK SIGN -->
<Key
- latin:keyLabel="&#x2122;" />
+ latin:keySpec="&#x2122;" />
<!-- U+2105: "℅" CARE OF -->
<Key
- latin:keyLabel="&#x2105;" />
+ latin:keySpec="&#x2105;" />
<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="&#x0E51;"
+ latin:keySpec="&#x0E51;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E52: "๒" THAI DIGIT TWO -->
<Key
- latin:keyLabel="&#x0E52;"
+ latin:keySpec="&#x0E52;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E53: "๓" THAI DIGIT THREE -->
<Key
- latin:keyLabel="&#x0E53;"
+ latin:keySpec="&#x0E53;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E54: "๔" THAI DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0E54;"
+ latin:keySpec="&#x0E54;"
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="&#x20;&#x0E39;"
- latin:code="0x0E39"
+ latin:keySpec="&#x20;&#x0E39;|&#x0E39;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT -->
<Key
- latin:keyLabel="&#x0E3F;"
+ latin:keySpec="&#x0E3F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E55: "๕" THAI DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0E55;"
+ latin:keySpec="&#x0E55;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E56: "๖" THAI DIGIT SIX -->
<Key
- latin:keyLabel="&#x0E56;"
+ latin:keySpec="&#x0E56;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E57: "๗" THAI DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0E57;"
+ latin:keySpec="&#x0E57;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E58: "๘" THAI DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0E58;"
+ latin:keySpec="&#x0E58;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E59: "๙" THAI DIGIT NINE -->
<Key
- latin:keyLabel="&#x0E59;"
+ latin:keySpec="&#x0E59;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+0E45: "ๅ" THAI CHARACTER LAKKHANGYAO -->
<Key
- latin:keyLabel="&#x0E45;"
+ latin:keySpec="&#x0E45;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E51: "๑" THAI DIGIT ONE -->
<Key
latin:keyHintLabel="1"
latin:additionalMoreKeys="1"
latin:moreKeys="&#x0E51;"
- latin:keyLabel="/" />
+ latin:keySpec="/" />
<!-- U+0E52: "๒" THAI DIGIT TWO -->
<Key
latin:keyHintLabel="2"
latin:additionalMoreKeys="2"
latin:moreKeys="&#x0E52;"
- latin:keyLabel="_" />
+ latin:keySpec="_" />
<!-- U+0E20: "ภ" THAI CHARACTER PHO SAMPHAO
U+0E53: "๓" THAI DIGIT THREE -->
<Key
- latin:keyLabel="&#x0E20;"
+ latin:keySpec="&#x0E20;"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3"
latin:moreKeys="&#x0E53;"
@@ -104,7 +103,7 @@
<!-- U+0E16: "ถ" THAI CHARACTER THO THUNG
U+0E54: "๔" THAI DIGIT FOUR -->
<Key
- latin:keyLabel="&#x0E16;"
+ latin:keySpec="&#x0E16;"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4"
latin:moreKeys="&#x0E54;"
@@ -114,21 +113,19 @@
<!-- Note: The space character is needed as a preceding letter to draw some Thai
composing characters correctly. -->
<Key
- latin:keyLabel="&#x20;&#x0E38;"
- latin:code="0x0E38"
+ latin:keySpec="&#x20;&#x0E38;|&#x0E38;"
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="&#x20;&#x0E36;"
- latin:code="0x0E36"
+ latin:keySpec="&#x20;&#x0E36;|&#x0E36;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E04: "ค" THAI CHARACTER KHO KHWAI
U+0E55: "๕" THAI DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0E04;"
+ latin:keySpec="&#x0E04;"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5"
latin:moreKeys="&#x0E55;"
@@ -136,7 +133,7 @@
<!-- U+0E15: "ต" THAI CHARACTER TO TAO
U+0E56: "๖" THAI DIGIT SIX -->
<Key
- latin:keyLabel="&#x0E15;"
+ latin:keySpec="&#x0E15;"
latin:keyHintLabel="6"
latin:additionalMoreKeys="6"
latin:moreKeys="&#x0E56;"
@@ -144,7 +141,7 @@
<!-- U+0E08: "จ" THAI CHARACTER CHO CHAN
U+0E57: "๗" THAI DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x0E08;"
+ latin:keySpec="&#x0E08;"
latin:keyHintLabel="7"
latin:additionalMoreKeys="7"
latin:moreKeys="&#x0E57;"
@@ -152,7 +149,7 @@
<!-- U+0E02: "ข" THAI CHARACTER KHO KHAI
U+0E58: "๘" THAI DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x0E02;"
+ latin:keySpec="&#x0E02;"
latin:keyHintLabel="8"
latin:additionalMoreKeys="8"
latin:moreKeys="&#x0E58;"
@@ -160,7 +157,7 @@
<!-- U+0E0A: "ช" THAI CHARACTER CHO CHANG
U+0E59: "๙" THAI DIGIT NINE -->
<Key
- latin:keyLabel="&#x0E0A;"
+ latin:keySpec="&#x0E0A;"
latin:keyHintLabel="9"
latin:additionalMoreKeys="9"
latin:moreKeys="&#x0E59;"
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="&#x0E50;"
+ latin:keySpec="&#x0E50;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="&quot;" />
+ latin:keySpec="&quot;" />
<!-- U+0E0E: "ฎ" THAI CHARACTER DO CHADA -->
<Key
- latin:keyLabel="&#x0E0E;"
+ latin:keySpec="&#x0E0E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E11: "ฑ" THAI CHARACTER THO NANGMONTHO -->
<Key
- latin:keyLabel="&#x0E11;"
+ latin:keySpec="&#x0E11;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E18: "ธ" THAI CHARACTER THO THONG -->
<Key
- latin:keyLabel="&#x0E18;"
+ latin:keySpec="&#x0E18;"
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="&#x20;&#x0E4D;"
- latin:code="0x0E4D"
+ latin:keySpec="&#x20;&#x0E4D;|&#x0E4D;"
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="&#x20;&#x0E4A;"
- latin:code="0x0E4A"
+ latin:keySpec="&#x20;&#x0E4A;|&#x0E4A;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E13: "ณ" THAI CHARACTER NO NEN -->
<Key
- latin:keyLabel="&#x0E13;"
+ latin:keySpec="&#x0E13;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2F: "ฯ" THAI CHARACTER PAIYANNOI -->
<Key
- latin:keyLabel="&#x0E2F;"
+ latin:keySpec="&#x0E2F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E0D: "ญ" THAI CHARACTER YO YING -->
<Key
- latin:keyLabel="&#x0E0D;"
+ latin:keySpec="&#x0E0D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E10: "ฐ" THAI CHARACTER THO THAN -->
<Key
- latin:keyLabel="&#x0E10;"
+ latin:keySpec="&#x0E10;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="," />
+ latin:keySpec="," />
</case>
<default>
<!-- U+0E46: "ๆ" THAI CHARACTER MAIYAMOK
U+0E50: "๐" THAI DIGIT ZERO -->
<Key
- latin:keyLabel="&#x0E46;"
+ latin:keySpec="&#x0E46;"
latin:keyHintLabel="0"
latin:additionalMoreKeys="0"
latin:moreKeys="&#x0E50;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E44: "ไ" THAI CHARACTER SARA AI MAIMALAI -->
<Key
- latin:keyLabel="&#x0E44;"
+ latin:keySpec="&#x0E44;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E33: "ำ" THAI CHARACTER SARA AM -->
<Key
- latin:keyLabel="&#x0E33;"
+ latin:keySpec="&#x0E33;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E1E: "พ" THAI CHARACTER PHO PHAN -->
<Key
- latin:keyLabel="&#x0E1E;"
+ latin:keySpec="&#x0E1E;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E30: "ะ" THAI CHARACTER SARA A -->
<Key
- latin:keyLabel="&#x0E30;"
+ latin:keySpec="&#x0E30;"
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="&#x20;&#x0E31;"
- latin:code="0x0E31"
+ latin:keySpec="&#x20;&#x0E31;|&#x0E31;"
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="&#x20;&#x0E35;"
- latin:code="0x0E35"
+ latin:keySpec="&#x20;&#x0E35;|&#x0E35;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E23: "ร" THAI CHARACTER RO RUA -->
<Key
- latin:keyLabel="&#x0E23;"
+ latin:keySpec="&#x0E23;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E19: "น" THAI CHARACTER NO NU -->
<Key
- latin:keyLabel="&#x0E19;"
+ latin:keySpec="&#x0E19;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E22: "ย" THAI CHARACTER YO YAK -->
<Key
- latin:keyLabel="&#x0E22;"
+ latin:keySpec="&#x0E22;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E1A: "บ" THAI CHARACTER BO BAIMAI -->
<Key
- latin:keyLabel="&#x0E1A;"
+ latin:keySpec="&#x0E1A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E25: "ล" THAI CHARACTER LO LING -->
<Key
- latin:keyLabel="&#x0E25;"
+ latin:keySpec="&#x0E25;"
latin:keyLabelFlags="fontNormal" />
</default>
</switch>
diff --git a/java/res/xml/rowkeys_thai3.xml b/java/res/xml/rowkeys_thai3.xml
index 7b6e6372e..4af4d232b 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="&#x0E24;"
+ latin:keySpec="&#x0E24;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E06: "ฆ" THAI CHARACTER KHO RAKHANG -->
<Key
- latin:keyLabel="&#x0E06;"
+ latin:keySpec="&#x0E06;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E0F: "ฏ" THAI CHARACTER TO PATAK -->
<Key
- latin:keyLabel="&#x0E0F;"
+ latin:keySpec="&#x0E0F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E42: "โ" THAI CHARACTER SARA O -->
<Key
- latin:keyLabel="&#x0E42;"
+ latin:keySpec="&#x0E42;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E0C: "ฌ" THAI CHARACTER CHO CHOE -->
<Key
- latin:keyLabel="&#x0E0C;"
+ latin:keySpec="&#x0E0C;"
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="&#x20;&#x0E47;"
- latin:code="0x0E47"
+ latin:keySpec="&#x20;&#x0E47;|&#x0E47;"
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="&#x20;&#x0E4B;"
- latin:code="0x0E4B"
+ latin:keySpec="&#x20;&#x0E4B;|&#x0E4B;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E29: "ษ" THAI CHARACTER SO RUSI -->
<Key
- latin:keyLabel="&#x0E29;"
+ latin:keySpec="&#x0E29;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E28: "ศ" THAI CHARACTER SO SALA -->
<Key
- latin:keyLabel="&#x0E28;"
+ latin:keySpec="&#x0E28;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E0B: "ซ" THAI CHARACTER SO SO -->
<Key
- latin:keyLabel="&#x0E0B;"
+ latin:keySpec="&#x0E0B;"
latin:keyLabelFlags="fontNormal" />
<Key
- latin:keyLabel="." />
+ latin:keySpec="." />
</case>
<default>
<!-- U+0E1F: "ฟ" THAI CHARACTER FO FAN -->
<Key
- latin:keyLabel="&#x0E1F;"
+ latin:keySpec="&#x0E1F;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2B: "ห" THAI CHARACTER HO HIP -->
<Key
- latin:keyLabel="&#x0E2B;"
+ latin:keySpec="&#x0E2B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E01: "ก" THAI CHARACTER KO KAI -->
<Key
- latin:keyLabel="&#x0E01;"
+ latin:keySpec="&#x0E01;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E14: "ด" THAI CHARACTER DO DEK -->
<Key
- latin:keyLabel="&#x0E14;"
+ latin:keySpec="&#x0E14;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E40: "เ" THAI CHARACTER SARA E -->
<Key
- latin:keyLabel="&#x0E40;"
+ latin:keySpec="&#x0E40;"
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="&#x20;&#x0E49;"
- latin:code="0x0E49"
+ latin:keySpec="&#x20;&#x0E49;|&#x0E49;"
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="&#x20;&#x0E48;"
- latin:code="0x0E48"
+ latin:keySpec="&#x20;&#x0E48;|&#x0E48;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E32: "า" THAI CHARACTER SARA AA -->
<Key
- latin:keyLabel="&#x0E32;"
+ latin:keySpec="&#x0E32;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2A: "ส" THAI CHARACTER SO SUA -->
<Key
- latin:keyLabel="&#x0E2A;"
+ latin:keySpec="&#x0E2A;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E27: "ว" THAI CHARACTER WO WAEN -->
<Key
- latin:keyLabel="&#x0E27;"
+ latin:keySpec="&#x0E27;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E07: "ง" THAI CHARACTER NGO NGU -->
<Key
- latin:keyLabel="&#x0E07;"
+ latin:keySpec="&#x0E07;"
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="&#x0E09;"
+ latin:keySpec="&#x0E09;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2E: "ฮ" THAI CHARACTER HO NOKHUK -->
<Key
- latin:keyLabel="&#x0E2E;"
+ latin:keySpec="&#x0E2E;"
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="&#x20;&#x0E3A;"
- latin:code="0x0E3A"
+ latin:keySpec="&#x20;&#x0E3A;|&#x0E3A;"
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="&#x20;&#x0E4C;"
- latin:code="0x0E4C"
+ latin:keySpec="&#x20;&#x0E4C;|&#x0E4C;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<Key
- latin:keyLabel="\?" />
+ latin:keySpec="\?" />
<!-- U+0E12: "ฒ" THAI CHARACTER THO PHUTHAO -->
<Key
- latin:keyLabel="&#x0E12;"
+ latin:keySpec="&#x0E12;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2C: "ฬ" THAI CHARACTER LO CHULA -->
<Key
- latin:keyLabel="&#x0E2C;"
+ latin:keySpec="&#x0E2C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E26: "ฦ" THAI CHARACTER LU -->
<Key
- latin:keyLabel="&#x0E26;"
+ latin:keySpec="&#x0E26;"
latin:keyLabelFlags="fontNormal" />
</case>
<default>
<!-- U+0E1C: "ผ" THAI CHARACTER PHO PHUNG -->
<Key
- latin:keyLabel="&#x0E1C;"
+ latin:keySpec="&#x0E1C;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E1B: "ป" THAI CHARACTER PO PLA -->
<Key
- latin:keyLabel="&#x0E1B;"
+ latin:keySpec="&#x0E1B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E41: "แ" THAI CHARACTER SARA AE -->
<Key
- latin:keyLabel="&#x0E41;"
+ latin:keySpec="&#x0E41;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E2D: "อ" THAI CHARACTER O ANG -->
<Key
- latin:keyLabel="&#x0E2D;"
+ latin:keySpec="&#x0E2D;"
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="&#x20;&#x0E34;"
- latin:code="0x0E34"
+ latin:keySpec="&#x20;&#x0E34;|&#x0E34;"
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="&#x20;&#x0E37;"
- latin:code="0x0E37"
+ latin:keySpec="&#x20;&#x0E37;|&#x0E37;"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
<!-- U+0E17: "ท" THAI CHARACTER THO THAHAN -->
<Key
- latin:keyLabel="&#x0E17;"
+ latin:keySpec="&#x0E17;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E21: "ม" THAI CHARACTER MO MA -->
<Key
- latin:keyLabel="&#x0E21;"
+ latin:keySpec="&#x0E21;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E43: "ใ" THAI CHARACTER SARA AI MAIMUAN -->
<Key
- latin:keyLabel="&#x0E43;"
+ latin:keySpec="&#x0E43;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0E1D: "ฝ" THAI CHARACTER FO FA -->
<Key
- latin:keyLabel="&#x0E1D;"
+ latin:keySpec="&#x0E1D;"
latin:keyLabelFlags="fontNormal" />
</default>
</switch>
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index 291018a14..8c9267a53 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,7 +61,7 @@
latin:mode="time|datetime"
>
<Key
- latin:keyLabel="."
+ latin:keySpec="."
latin:keyLabelFlags="hasPopupHint"
latin:moreKeys="!text/more_keys_for_am_pm"
latin:keyStyle="numFunctionalKeyStyle"
@@ -69,7 +69,7 @@
</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_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/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index 10fb9fef4..216a825e0 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -158,7 +158,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..0043b7844 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java
@@ -29,10 +29,10 @@ 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;
public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat {
@@ -82,7 +82,7 @@ public final class AccessibleKeyboardViewProxy extends AccessibilityDelegateComp
private void initInternal(final InputMethodService inputMethod) {
mInputMethod = inputMethod;
mEdgeSlop = inputMethod.getResources().getDimensionPixelSize(
- R.dimen.accessibility_edge_slop);
+ R.dimen.config_accessibility_edge_slop);
}
/**
@@ -204,25 +204,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 +222,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;
}
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/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/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/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..8badaf4b9 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -533,12 +533,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 +564,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 +632,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 +656,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/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..4c53b528f 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -23,16 +23,19 @@ 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.graphics.Typeface;
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 +47,8 @@ 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.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
@@ -58,6 +61,7 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
/**
* View class to implement Emoji palettes.
@@ -71,17 +75,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;
@@ -149,7 +155,7 @@ 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);
+ 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 +180,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,20 +188,20 @@ 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];
}
@@ -211,7 +217,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 +228,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 +250,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 +261,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,7 +280,7 @@ 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;
}
@@ -283,9 +289,9 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
// 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 +302,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 +311,41 @@ 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.getKeys(), 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,29 +357,31 @@ 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;
+ }
+ if (lhs.getCode() == rhs.getCode()) {
+ return 0;
+ }
+ return lhs.getCode() < rhs.getCode() ? -1 : 1;
+ }
+ };
+
+ private static Key[][] sortKeysIntoPages(final Key[] inKeys, final int maxPageCount) {
+ final Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
+ Arrays.sort(keys, 0, keys.length, EMOJI_KEY_COMPARATOR);
final int pageCount = (keys.length - 1) / maxPageCount + 1;
final Key[][] retval = new Key[pageCount][maxPageCount];
for (int i = 0; i < keys.length; ++i) {
@@ -404,12 +414,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 +433,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);
}
@@ -458,42 +468,52 @@ 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
@@ -503,7 +523,6 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
updateEmojiCategoryPageIdView();
}
-
@Override
public void onPageSelected(final int position) {
final Pair<Integer, Integer> newPos =
@@ -522,6 +541,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 +561,93 @@ 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);
- return;
+ 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;
}
- private void registerCode(final int code) {
- mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */);
+ /**
+ * 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);
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 onPressKey(final Key key) {
+ final int code = key.getCode();
+ mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */);
+ }
+
+ /**
+ * 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);
}
- registerCode(code);
+ mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
}
public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
// TODO:
}
- public void startEmojiPalettes() {
+ // Hack: These parameters are hacky.
+ public void startEmojiPalettes(final String switchToAlphaLabel, final int switchToAlphaColor,
+ final float switchToAlphaSize, final Typeface switchToAlphaTypeface) {
if (DEBUG_PAGER) {
Log.d(TAG, "allocate emoji palettes memory " + mCurrentPagerPosition);
}
+ mAlphabetKeyLeft.setText(switchToAlphaLabel);
+ mAlphabetKeyLeft.setTextColor(switchToAlphaColor);
+ mAlphabetKeyLeft.setTextSize(TypedValue.COMPLEX_UNIT_PX, switchToAlphaSize);
+ mAlphabetKeyLeft.setTypeface(switchToAlphaTypeface);
+ mAlphabetKeyRight.setText(switchToAlphaLabel);
+ mAlphabetKeyRight.setTextColor(switchToAlphaColor);
+ mAlphabetKeyRight.setTextSize(TypedValue.COMPLEX_UNIT_PX, switchToAlphaSize);
+ mAlphabetKeyRight.setTypeface(switchToAlphaTypeface);
mEmojiPager.setAdapter(mEmojiPalettesAdapter);
mEmojiPager.setCurrentItem(mCurrentPagerPosition);
}
@@ -628,16 +700,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 +736,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 +770,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 +779,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 +799,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 +812,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 +824,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 */);
+ Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */);
+ }
+
+ private void handleKeyUp() {
mKeyboardActionListener.onCodeInput(
Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
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..ceda9ee9a 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;
@@ -185,22 +183,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 +206,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 +215,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 +252,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 +263,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 +287,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 +314,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 +350,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.
*/
@@ -687,7 +668,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 +684,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() {
@@ -928,9 +915,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 +925,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..03d9defa0 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,7 @@ 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) {
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
@@ -117,20 +110,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..4fd3bac2f 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -23,6 +23,7 @@ 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;
/**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
@@ -217,4 +218,20 @@ public class Keyboard {
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/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 736f13ed6..02beb3f11 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -70,8 +70,7 @@ public final class KeyboardId {
public final int mElementId;
private 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..6215e2710 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
+import android.graphics.Paint;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -30,6 +31,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.latin.Constants;
import com.android.inputmethod.latin.InputView;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
@@ -74,12 +76,13 @@ 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;
+ private SettingsValues mCurrentSettingsValues;
+ private Key mSwitchToAlphaKey;
/** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
* what user actually typed. */
@@ -105,7 +108,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);
@@ -154,12 +156,15 @@ 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 */,
+ mSubtypeSwitcher.isShortcutImeEnabled(),
+ settingsValues.mShowsVoiceInputKey,
settingsValues.isLanguageSwitchKeyEnabled());
mKeyboardLayoutSet = builder.build();
+ mCurrentSettingsValues = settingsValues;
try {
mState.onLoadKeyboard();
+ final Keyboard symbols = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS);
+ mSwitchToAlphaKey = symbols.getKey(Constants.CODE_SWITCH_ALPHA_SYMBOL);
} catch (KeyboardLayoutSetException e) {
Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause());
LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause());
@@ -187,10 +192,15 @@ 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)
@@ -280,7 +290,10 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
@Override
public void setEmojiKeyboard() {
mMainKeyboardFrame.setVisibility(View.GONE);
- mEmojiPalettesView.startEmojiPalettes();
+ final Paint paint = mKeyboardView.newLabelPaint(mSwitchToAlphaKey);
+ mEmojiPalettesView.startEmojiPalettes(
+ mSwitchToAlphaKey.getLabel(), paint.getColor(), paint.getTextSize(),
+ paint.getTypeface());
mEmojiPalettesView.setVisibility(View.VISIBLE);
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 5578713a0..dd3ab9cce 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);
}
@@ -322,7 +319,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 +327,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 +367,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 +386,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 +399,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 +452,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 +530,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 +582,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..6c56b8aab 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -28,18 +28,13 @@ 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 +42,16 @@ 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.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.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 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);
@@ -637,12 +417,17 @@ 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) {
+ if (mDrawingPreviewPlacerView.getParent() != null) {
return;
}
final int width = getWidth();
@@ -665,10 +450,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");
+ Log.w(TAG, "Cannot find android.R.id.content view to add DrawingPreviewPlacerView");
} else {
- windowContentView.addView(mPreviewPlacerView);
- mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height);
+ windowContentView.addView(mDrawingPreviewPlacerView);
+ mDrawingPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height);
}
}
@@ -678,80 +463,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 +482,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 +554,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.
@@ -894,7 +586,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 +614,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;
}
@@ -979,26 +673,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 */);
}
@@ -1016,7 +708,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public void onDismissMoreKeysPanel(final MoreKeysPanel panel) {
dimEntireKeyboard(false /* dimmed */);
if (isShowingMoreKeysPanel()) {
- mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView());
+ mMoreKeysPanel.removeFromParent();
mMoreKeysPanel = null;
}
}
@@ -1034,14 +726,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 +733,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 +753,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 +789,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.
@@ -1169,12 +859,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 +901,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,7 +912,7 @@ 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.
@@ -1238,17 +946,17 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (mNeedsToDisplayLanguage) {
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 +968,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..abff202b7 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.getKeys()) {
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..1891dfc74 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);
@@ -139,7 +142,11 @@ 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);
+ } else {
+ mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+ }
}
}
@@ -214,12 +221,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..4a33e6536 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 {
@@ -119,9 +120,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..59cf64d4b 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,10 +313,10 @@ 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;
@@ -525,8 +326,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// primaryCode is different from {@link Key#mCode}.
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 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,11 +345,16 @@ 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);
+ } else {
+ sListener.onCodeInput(code,
+ Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+ }
}
}
}
@@ -561,7 +367,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
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) {
@@ -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,21 @@ 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());
}
+ 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/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java
index b814fc162..cd7dd6f18 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java
@@ -22,8 +22,9 @@ 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;
@@ -49,9 +50,7 @@ public abstract class AbstractDrawingPreview {
// Default implementation is empty.
}
- 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/CustomViewPager.java b/java/src/com/android/inputmethod/keyboard/internal/CustomViewPager.java
new file mode 100644
index 000000000..f5cc45ca7
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/CustomViewPager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+/**
+ * Custom view pager to prevent {@link ViewPager} from crashing while handling multi-touch
+ * event.
+ */
+public class CustomViewPager extends ViewPager {
+ private static final String TAG = CustomViewPager.class.getSimpleName();
+
+ public CustomViewPager(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(final MotionEvent event) {
+ // This only happens when you multi-touch, take the first finger off and move.
+ // Unfortunately this causes {@link ViewPager} to crash, so we will ignore such events.
+ if (event.getAction() == MotionEvent.ACTION_MOVE && event.getPointerId(0) != 0) {
+ Log.w(TAG, "Ignored multi-touch move event to prevent ViewPager from crashing");
+ return false;
+ }
+
+ return super.onInterceptTouchEvent(event);
+ }
+}
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..606addcc4 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);
}
@@ -59,16 +59,20 @@ public final class PreviewPlacerView extends RelativeLayout {
}
}
- @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..e2fd39017 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -25,7 +25,7 @@ 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;
@@ -53,7 +53,7 @@ public class DynamicGridKeyboard extends Keyboard {
private 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);
@@ -124,7 +124,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 +139,48 @@ 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) {
+ private static Key getKeyByCode(final Collection<DynamicGridKeyboard> keyboards,
+ final int code) {
+ for (final DynamicGridKeyboard keyboard : keyboards) {
+ final Key key = keyboard.getKey(code);
+ if (key != null) {
+ return key;
+ }
+ }
+ return null;
+ }
+
+ private static Key getKeyByOutputText(final Collection<DynamicGridKeyboard> keyboards,
+ final String outputText) {
for (final DynamicGridKeyboard kbd : keyboards) {
- if (o instanceof Integer) {
- final int code = (Integer) o;
- final Key key = kbd.getKey(code);
- if (key != null) {
- return key;
- }
- } else if (o instanceof String) {
- final String outputText = (String) o;
- final Key key = kbd.getKeyFromOutputText(outputText);
- if (key != null) {
- return key;
- }
- } else {
- Log.w(TAG, "Invalid object: " + o);
+ final Key key = kbd.getKeyFromOutputText(outputText);
+ if (key != null) {
+ return key;
}
}
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);
}
}
@@ -217,7 +229,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..12e063261 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,26 @@ 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 void setActionBarProperties(final LinearLayout ll) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
lp.height = mEmojiActionBarHeight - mBottomPadding;
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..eef4b36ed 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));
@@ -93,18 +96,14 @@ 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);
+ 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 +143,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 +188,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/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..c3e0aa685 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
@@ -47,6 +47,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 +67,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;
@@ -127,5 +130,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..81a8e7196 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;
@@ -37,6 +38,7 @@ 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;
@@ -276,9 +278,8 @@ 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 Locale locale = params.mId.mLocale;
+ params.mTextsSet.setLocale(locale);
final RunInLocale<Void> job = new RunInLocale<Void>() {
@Override
protected Void job(final Resources res) {
@@ -287,9 +288,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
}
};
// Null means the current system locale.
- final Locale locale = SubtypeLocaleUtils.isNoLanguage(params.mId.mSubtype)
- ? null : params.mId.mLocale;
- job.runInLocale(mResources, locale);
+ job.runInLocale(mResources,
+ SubtypeLocaleUtils.isNoLanguage(params.mId.mSubtype) ? null : locale);
final int resourceId = keyboardAttr.getResourceId(
R.styleable.Keyboard_touchPositionCorrectionData, 0);
@@ -456,11 +456,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 +481,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 +505,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 +665,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 +686,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 +708,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..da8bf7d69 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -30,6 +30,7 @@ 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;
@@ -48,7 +49,6 @@ public final class KeyboardIconsSet {
"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,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index d32bb7581..153391eed 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -62,7 +62,6 @@ public class KeyboardParams {
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);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index dd98c1703..ec0b5c95f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -304,6 +304,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 +317,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,6 +329,7 @@ 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);
@@ -642,6 +645,8 @@ public final class KeyboardState {
updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
} else if (code == Constants.CODE_EMOJI) {
setEmojiKeyboard();
+ } else if (code == Constants.CODE_ALPHA_FROM_EMOJI) {
+ setAlphabetKeyboard();
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index c2a01b5e8..89221ba24 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -18,46 +18,27 @@ 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 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/";
+ private static final char BACKSLASH = Constants.CODE_BACKSLASH;
+ private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;
- private String[] mTexts;
+ 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 setLocale(final Locale locale) {
+ final String language = locale.getLanguage();
+ mTextsTable = KeyboardTextsTable.getTextsTable(language);
}
public void loadStringResources(final Context context) {
@@ -77,21 +58,76 @@ public final class KeyboardTextsSet {
}
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;
}
+ 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.
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",
@@ -100,3422 +136,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">&#x0161;,&#x00DF;,&#x015B;</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">&#x010D;,&#x00E7;,&#x0107;</string>
- // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
- // <string name="more_keys_for_d">&#x010F;</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">&#x017E;,&#x017A;,&#x017C;</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..96acb1551
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -0,0 +1,3655 @@
+/*
+ * 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;
+
+/**
+ * !!!!! 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();
+ // Language to texts table map.
+ private static final HashMap<String, String[]> sLanguageToTextsTableMap =
+ CollectionUtils.newHashMap();
+ // TODO: Remove this variable after debugging.
+ // Texts table to language maps.
+ private static final HashMap<String[], String> sTextsTableToLanguageMap =
+ 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 + " language="
+ + sTextsTableToLanguageMap.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 < LANGUAGE_DEFAULT.length) {
+ return LANGUAGE_DEFAULT[index];
+ }
+ // Throw exception for debugging purpose.
+ throw new RuntimeException("Illegal index=" + index + " for name=" + name
+ + " language=" + sTextsTableToLanguageMap.get(textsTable));
+ }
+
+ public static String[] getTextsTable(final String language) {
+ final String[] textsTable = sLanguageToTextsTableMap.get(language);
+ return textsTable != null ? textsTable : LANGUAGE_DEFAULT;
+ }
+
+ private static final String[] NAMES = {
+ // /* index:histogram */ "name",
+ /* 0:30 */ "more_keys_for_a",
+ /* 1:30 */ "more_keys_for_o",
+ /* 2:28 */ "more_keys_for_u",
+ /* 3:27 */ "more_keys_for_e",
+ /* 4:26 */ "more_keys_for_i",
+ /* 5:23 */ "double_quotes",
+ /* 6:22 */ "single_quotes",
+ /* 7:21 */ "more_keys_for_c",
+ /* 8:20 */ "more_keys_for_s",
+ /* 9:20 */ "more_keys_for_n",
+ /* 10:20 */ "label_to_alpha_key",
+ /* 11:15 */ "more_keys_for_y",
+ /* 12:13 */ "more_keys_for_d",
+ /* 13:12 */ "more_keys_for_z",
+ /* 14:10 */ "more_keys_for_t",
+ /* 15:10 */ "more_keys_for_l",
+ /* 16: 9 */ "more_keys_for_g",
+ /* 17: 9 */ "single_angle_quotes",
+ /* 18: 9 */ "double_angle_quotes",
+ /* 19: 9 */ "keylabel_for_currency",
+ /* 20: 8 */ "more_keys_for_r",
+ /* 21: 6 */ "more_keys_for_k",
+ /* 22: 6 */ "keylabel_for_nordic_row1_11",
+ /* 23: 6 */ "keylabel_for_nordic_row2_10",
+ /* 24: 6 */ "keylabel_for_nordic_row2_11",
+ /* 25: 6 */ "more_keys_for_cyrillic_ie",
+ /* 26: 5 */ "more_keys_for_nordic_row2_10",
+ /* 27: 5 */ "keylabel_for_east_slavic_row1_9",
+ /* 28: 5 */ "keylabel_for_east_slavic_row1_12",
+ /* 29: 5 */ "keylabel_for_east_slavic_row2_1",
+ /* 30: 5 */ "keylabel_for_east_slavic_row2_11",
+ /* 31: 5 */ "keylabel_for_east_slavic_row3_5",
+ /* 32: 5 */ "more_keys_for_cyrillic_soft_sign",
+ /* 33: 5 */ "more_keys_for_punctuation",
+ /* 34: 4 */ "more_keys_for_nordic_row2_11",
+ /* 35: 4 */ "keylabel_for_symbols_1",
+ /* 36: 4 */ "keylabel_for_symbols_2",
+ /* 37: 4 */ "keylabel_for_symbols_3",
+ /* 38: 4 */ "keylabel_for_symbols_4",
+ /* 39: 4 */ "keylabel_for_symbols_5",
+ /* 40: 4 */ "keylabel_for_symbols_6",
+ /* 41: 4 */ "keylabel_for_symbols_7",
+ /* 42: 4 */ "keylabel_for_symbols_8",
+ /* 43: 4 */ "keylabel_for_symbols_9",
+ /* 44: 4 */ "keylabel_for_symbols_0",
+ /* 45: 4 */ "label_to_symbol_key",
+ /* 46: 4 */ "label_to_symbol_with_microphone_key",
+ /* 47: 4 */ "additional_more_keys_for_symbols_1",
+ /* 48: 4 */ "additional_more_keys_for_symbols_2",
+ /* 49: 4 */ "additional_more_keys_for_symbols_3",
+ /* 50: 4 */ "additional_more_keys_for_symbols_4",
+ /* 51: 4 */ "additional_more_keys_for_symbols_5",
+ /* 52: 4 */ "additional_more_keys_for_symbols_6",
+ /* 53: 4 */ "additional_more_keys_for_symbols_7",
+ /* 54: 4 */ "additional_more_keys_for_symbols_8",
+ /* 55: 4 */ "additional_more_keys_for_symbols_9",
+ /* 56: 4 */ "additional_more_keys_for_symbols_0",
+ /* 57: 3 */ "more_keys_for_star",
+ /* 58: 3 */ "keyspec_left_parenthesis",
+ /* 59: 3 */ "keyspec_right_parenthesis",
+ /* 60: 3 */ "keyspec_left_square_bracket",
+ /* 61: 3 */ "keyspec_right_square_bracket",
+ /* 62: 3 */ "keyspec_left_curly_bracket",
+ /* 63: 3 */ "keyspec_right_curly_bracket",
+ /* 64: 3 */ "keyspec_less_than",
+ /* 65: 3 */ "keyspec_greater_than",
+ /* 66: 3 */ "keyspec_less_than_equal",
+ /* 67: 3 */ "keyspec_greater_than_equal",
+ /* 68: 3 */ "keyspec_left_double_angle_quote",
+ /* 69: 3 */ "keyspec_right_double_angle_quote",
+ /* 70: 3 */ "keyspec_left_single_angle_quote",
+ /* 71: 3 */ "keyspec_right_single_angle_quote",
+ /* 72: 3 */ "keylabel_for_tablet_comma",
+ /* 73: 3 */ "more_keys_for_tablet_period",
+ /* 74: 3 */ "more_keys_for_question",
+ /* 75: 2 */ "more_keys_for_h",
+ /* 76: 2 */ "more_keys_for_w",
+ /* 77: 2 */ "more_keys_for_cyrillic_u",
+ /* 78: 2 */ "more_keys_for_cyrillic_en",
+ /* 79: 2 */ "more_keys_for_cyrillic_ghe",
+ /* 80: 2 */ "more_keys_for_east_slavic_row2_1",
+ /* 81: 2 */ "more_keys_for_cyrillic_o",
+ /* 82: 2 */ "keylabel_for_south_slavic_row1_6",
+ /* 83: 2 */ "keylabel_for_south_slavic_row2_11",
+ /* 84: 2 */ "keylabel_for_south_slavic_row3_1",
+ /* 85: 2 */ "keylabel_for_south_slavic_row3_8",
+ /* 86: 2 */ "more_keys_for_cyrillic_i",
+ /* 87: 2 */ "keylabel_for_swiss_row1_11",
+ /* 88: 2 */ "keylabel_for_swiss_row2_10",
+ /* 89: 2 */ "keylabel_for_swiss_row2_11",
+ /* 90: 2 */ "more_keys_for_swiss_row1_11",
+ /* 91: 2 */ "more_keys_for_swiss_row2_10",
+ /* 92: 2 */ "more_keys_for_swiss_row2_11",
+ /* 93: 2 */ "keylabel_for_spanish_row2_10",
+ /* 94: 2 */ "more_keys_for_bullet",
+ /* 95: 2 */ "more_keys_for_left_parenthesis",
+ /* 96: 2 */ "more_keys_for_right_parenthesis",
+ /* 97: 2 */ "more_keys_for_arabic_diacritics",
+ /* 98: 2 */ "keylabel_for_comma",
+ /* 99: 2 */ "more_keys_for_comma",
+ /* 100: 2 */ "keyhintlabel_for_tablet_comma",
+ /* 101: 2 */ "more_keys_for_tablet_comma",
+ /* 102: 2 */ "keyhintlabel_for_period",
+ /* 103: 2 */ "more_keys_for_period",
+ /* 104: 2 */ "keyhintlabel_for_tablet_period",
+ /* 105: 2 */ "keylabel_for_symbols_question",
+ /* 106: 2 */ "keylabel_for_symbols_semicolon",
+ /* 107: 2 */ "keylabel_for_symbols_percent",
+ /* 108: 2 */ "more_keys_for_symbols_semicolon",
+ /* 109: 2 */ "more_keys_for_symbols_percent",
+ /* 110: 1 */ "more_keys_for_v",
+ /* 111: 1 */ "more_keys_for_j",
+ /* 112: 1 */ "more_keys_for_cyrillic_ka",
+ /* 113: 1 */ "more_keys_for_cyrillic_a",
+ /* 114: 1 */ "more_keys_for_east_slavic_row2_11",
+ /* 115: 1 */ "more_keys_for_currency_dollar",
+ /* 116: 1 */ "more_keys_for_tablet_punctuation",
+ /* 117: 1 */ "more_keys_for_plus",
+ /* 118: 1 */ "more_keys_for_less_than",
+ /* 119: 1 */ "more_keys_for_greater_than",
+ /* 120: 1 */ "keylabel_for_period",
+ /* 121: 1 */ "keylabel_for_tablet_period",
+ /* 122: 1 */ "more_keys_for_exclamation",
+ /* 123: 1 */ "more_keys_for_q",
+ /* 124: 1 */ "more_keys_for_x",
+ /* 125: 1 */ "keylabel_for_q",
+ /* 126: 1 */ "keylabel_for_w",
+ /* 127: 1 */ "keylabel_for_y",
+ /* 128: 1 */ "keylabel_for_x",
+ /* 129: 0 */ "more_keys_for_currency",
+ /* 130: 0 */ "more_keys_for_symbols_1",
+ /* 131: 0 */ "more_keys_for_symbols_2",
+ /* 132: 0 */ "more_keys_for_symbols_3",
+ /* 133: 0 */ "more_keys_for_symbols_4",
+ /* 134: 0 */ "more_keys_for_symbols_5",
+ /* 135: 0 */ "more_keys_for_symbols_6",
+ /* 136: 0 */ "more_keys_for_symbols_7",
+ /* 137: 0 */ "more_keys_for_symbols_8",
+ /* 138: 0 */ "more_keys_for_symbols_9",
+ /* 139: 0 */ "more_keys_for_symbols_0",
+ /* 140: 0 */ "more_keys_for_am_pm",
+ /* 141: 0 */ "settings_as_more_key",
+ /* 142: 0 */ "shortcut_as_more_key",
+ /* 143: 0 */ "action_next_as_more_key",
+ /* 144: 0 */ "action_previous_as_more_key",
+ /* 145: 0 */ "label_to_more_symbol_key",
+ /* 146: 0 */ "label_to_more_symbol_for_tablet_key",
+ /* 147: 0 */ "label_to_phone_numeric_key",
+ /* 148: 0 */ "label_to_phone_symbols_key",
+ /* 149: 0 */ "label_time_am",
+ /* 150: 0 */ "label_time_pm",
+ /* 151: 0 */ "keylabel_for_popular_domain",
+ /* 152: 0 */ "more_keys_for_popular_domain",
+ /* 153: 0 */ "keyspecs_for_left_parenthesis_more_keys",
+ /* 154: 0 */ "keyspecs_for_right_parenthesis_more_keys",
+ /* 155: 0 */ "single_laqm_raqm",
+ /* 156: 0 */ "single_raqm_laqm",
+ /* 157: 0 */ "double_laqm_raqm",
+ /* 158: 0 */ "double_raqm_laqm",
+ /* 159: 0 */ "single_lqm_rqm",
+ /* 160: 0 */ "single_9qm_lqm",
+ /* 161: 0 */ "single_9qm_rqm",
+ /* 162: 0 */ "single_rqm_9qm",
+ /* 163: 0 */ "double_lqm_rqm",
+ /* 164: 0 */ "double_9qm_lqm",
+ /* 165: 0 */ "double_9qm_rqm",
+ /* 166: 0 */ "double_rqm_9qm",
+ /* 167: 0 */ "more_keys_for_single_quote",
+ /* 168: 0 */ "more_keys_for_double_quote",
+ /* 169: 0 */ "more_keys_for_tablet_double_quote",
+ /* 170: 0 */ "emoji_key_as_more_key",
+ };
+
+ private static final String EMPTY = "";
+
+ /* Default texts */
+ private static final String[] LANGUAGE_DEFAULT = {
+ /* more_keys_for_a ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_lqm_rqm",
+ /* single_quotes */ "!text/single_lqm_rqm",
+ /* more_keys_for_c ~ */
+ EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ /* label_to_alpha_key */ "ABC",
+ /* more_keys_for_y ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_laqm_raqm",
+ /* double_angle_quotes */ "!text/double_laqm_raqm",
+ /* keylabel_for_currency */ "$",
+ /* more_keys_for_r ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,;,/,!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,#,!,\\,,?,&,\\%,+,\",-,:,',@",
+ /* more_keys_for_nordic_row2_11 */ EMPTY,
+ /* keylabel_for_symbols_1 */ "1",
+ /* keylabel_for_symbols_2 */ "2",
+ /* keylabel_for_symbols_3 */ "3",
+ /* keylabel_for_symbols_4 */ "4",
+ /* keylabel_for_symbols_5 */ "5",
+ /* keylabel_for_symbols_6 */ "6",
+ /* keylabel_for_symbols_7 */ "7",
+ /* keylabel_for_symbols_8 */ "8",
+ /* keylabel_for_symbols_9 */ "9",
+ /* keylabel_for_symbols_0 */ "0",
+ // Label for "switch to symbols" key.
+ /* label_to_symbol_key */ "?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.
+ /* label_to_symbol_with_microphone_key */ "123",
+ /* additional_more_keys_for_symbols_1 ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ additional_more_keys_for_symbols_0 */
+ // U+2020: "†" DAGGER
+ // U+2021: "‡" DOUBLE DAGGER
+ // U+2605: "★" BLACK STAR
+ /* more_keys_for_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",
+ /* keylabel_for_tablet_comma */ ",",
+ /* more_keys_for_tablet_period */ "!text/more_keys_for_tablet_punctuation",
+ // U+00BF: "¿" INVERTED QUESTION MARK
+ /* more_keys_for_question */ "\u00BF",
+ /* more_keys_for_h ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_swiss_row2_11 */
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ /* keylabel_for_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
+ /* more_keys_for_bullet */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+ /* more_keys_for_left_parenthesis */ "!fixedColumnOrder!3,!text/keyspecs_for_left_parenthesis_more_keys",
+ /* more_keys_for_right_parenthesis */ "!fixedColumnOrder!3,!text/keyspecs_for_right_parenthesis_more_keys",
+ /* more_keys_for_arabic_diacritics */ EMPTY,
+ // Comma key
+ /* keylabel_for_comma */ ",",
+ /* more_keys_for_comma ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ keyhintlabel_for_period */
+ /* more_keys_for_period */ "!text/more_keys_for_punctuation",
+ /* keyhintlabel_for_tablet_period */ EMPTY,
+ /* keylabel_for_symbols_question */ "?",
+ /* keylabel_for_symbols_semicolon */ ";",
+ /* keylabel_for_symbols_percent */ "%",
+ /* more_keys_for_symbols_semicolon */ EMPTY,
+ // U+2030: "‰" PER MILLE SIGN
+ /* more_keys_for_symbols_percent */ "\u2030",
+ /* more_keys_for_v ~ */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~ more_keys_for_east_slavic_row2_11 */
+ // U+00A2: "¢" CENT SIGN
+ // U+00A3: "£" POUND SIGN
+ // U+20AC: "€" EURO SIGN
+ // U+00A5: "¥" YEN SIGN
+ // U+20B1: "₱" PESO SIGN
+ /* more_keys_for_currency_dollar */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+ /* more_keys_for_tablet_punctuation */ "!fixedColumnOrder!7,;,/,!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,#,',\\,,&,\\%,+,\",-,:,@",
+ // U+00B1: "±" PLUS-MINUS SIGN
+ /* more_keys_for_plus */ "\u00B1",
+ /* more_keys_for_less_than */ "!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote,!text/keyspec_less_than_equal,!text/keyspec_left_double_angle_quote",
+ /* more_keys_for_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_right_double_angle_quote",
+ // Period key
+ /* keylabel_for_period */ ".",
+ /* keylabel_for_tablet_period */ ".",
+ // U+00A1: "¡" INVERTED EXCLAMATION MARK
+ /* more_keys_for_exclamation */ "\u00A1",
+ /* more_keys_for_q */ EMPTY,
+ /* more_keys_for_x */ EMPTY,
+ /* keylabel_for_q */ "q",
+ /* keylabel_for_w */ "w",
+ /* keylabel_for_y */ "y",
+ /* keylabel_for_x */ "x",
+ /* more_keys_for_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
+ /* more_keys_for_symbols_1 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+ // U+00B2: "²" SUPERSCRIPT TWO
+ // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
+ /* more_keys_for_symbols_2 */ "\u00B2,\u2154",
+ // U+00B3: "³" SUPERSCRIPT THREE
+ // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
+ // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
+ /* more_keys_for_symbols_3 */ "\u00B3,\u00BE,\u215C",
+ // U+2074: "⁴" SUPERSCRIPT FOUR
+ /* more_keys_for_symbols_4 */ "\u2074",
+ // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
+ /* more_keys_for_symbols_5 */ "\u215D",
+ /* more_keys_for_symbols_6 */ EMPTY,
+ // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+ /* more_keys_for_symbols_7 */ "\u215E",
+ /* more_keys_for_symbols_8 */ EMPTY,
+ /* more_keys_for_symbols_9 */ EMPTY,
+ // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
+ // U+2205: "∅" EMPTY SET
+ /* more_keys_for_symbols_0 */ "\u207F,\u2205",
+ /* more_keys_for_am_pm */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+ /* settings_as_more_key */ "!icon/settings_key|!code/key_settings",
+ /* shortcut_as_more_key */ "!icon/shortcut_key|!code/key_shortcut",
+ /* action_next_as_more_key */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+ /* action_previous_as_more_key */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+ // Label for "switch to more symbol" modifier key ("= \ <"). Must be short to fit on key!
+ /* label_to_more_symbol_key */ "= \\\\ <",
+ // Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
+ /* label_to_more_symbol_for_tablet_key */ "~ [ <",
+ // Label for "switch to phone numeric" key. Must be short to fit on key!
+ /* label_to_phone_numeric_key */ "123",
+ // Label for "switch to phone symbols" key. Must be short to fit on key!
+ // U+FF0A: "*" FULLWIDTH ASTERISK
+ // U+FF03: "#" FULLWIDTH NUMBER SIGN
+ /* label_to_phone_symbols_key */ "\uFF0A\uFF03",
+ // Key label for "ante meridiem"
+ /* label_time_am */ "AM",
+ // Key label for "post meridiem"
+ /* label_time_pm */ "PM",
+ /* keylabel_for_popular_domain */ ".com",
+ // popular web domains for the locale - most popular, displayed on the keyboard
+ /* more_keys_for_popular_domain */ "!hasLabels!,.net,.org,.gov,.edu",
+ /* keyspecs_for_left_parenthesis_more_keys */ "!text/keyspec_less_than,!text/keyspec_left_curly_bracket,!text/keyspec_left_square_bracket",
+ /* keyspecs_for_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",
+ /* more_keys_for_single_quote */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
+ /* more_keys_for_double_quote */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
+ /* more_keys_for_tablet_double_quote */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
+ /* emoji_key_as_more_key */ "!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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133",
+ /* double_quotes ~ */
+ null, null, null, null,
+ /* ~ more_keys_for_s */
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+0133: "ij" LATIN SMALL LIGATURE IJ
+ /* more_keys_for_y */ "\u00FD,\u0133",
+ };
+
+ /* Language ar: Arabic */
+ private static final String[] LANGUAGE_ar = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // 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
+ /* label_to_alpha_key */ "\u0623\u200C\u0628\u200C\u062C",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(",
+ /* more_keys_for_nordic_row2_11 */ null,
+ // U+0661: "١" ARABIC-INDIC DIGIT ONE
+ /* keylabel_for_symbols_1 */ "\u0661",
+ // U+0662: "٢" ARABIC-INDIC DIGIT TWO
+ /* keylabel_for_symbols_2 */ "\u0662",
+ // U+0663: "٣" ARABIC-INDIC DIGIT THREE
+ /* keylabel_for_symbols_3 */ "\u0663",
+ // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
+ /* keylabel_for_symbols_4 */ "\u0664",
+ // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
+ /* keylabel_for_symbols_5 */ "\u0665",
+ // U+0666: "٦" ARABIC-INDIC DIGIT SIX
+ /* keylabel_for_symbols_6 */ "\u0666",
+ // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
+ /* keylabel_for_symbols_7 */ "\u0667",
+ // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
+ /* keylabel_for_symbols_8 */ "\u0668",
+ // U+0669: "٩" ARABIC-INDIC DIGIT NINE
+ /* keylabel_for_symbols_9 */ "\u0669",
+ // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
+ /* keylabel_for_symbols_0 */ "\u0660",
+ // Label for "switch to symbols" key.
+ // U+061F: "؟" ARABIC QUESTION MARK
+ /* label_to_symbol_key */ "\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.
+ /* label_to_symbol_with_microphone_key */ "\u0663\u0662\u0661",
+ /* additional_more_keys_for_symbols_1 */ "1",
+ /* additional_more_keys_for_symbols_2 */ "2",
+ /* additional_more_keys_for_symbols_3 */ "3",
+ /* additional_more_keys_for_symbols_4 */ "4",
+ /* additional_more_keys_for_symbols_5 */ "5",
+ /* additional_more_keys_for_symbols_6 */ "6",
+ /* additional_more_keys_for_symbols_7 */ "7",
+ /* additional_more_keys_for_symbols_8 */ "8",
+ /* additional_more_keys_for_symbols_9 */ "9",
+ // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+ // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+ /* additional_more_keys_for_symbols_0 */ "0,\u066B,\u066C",
+ // U+2605: "★" BLACK STAR
+ // U+066D: "٭" ARABIC FIVE POINTED STAR
+ /* more_keys_for_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",
+ // U+061F: "؟" ARABIC QUESTION MARK
+ // U+060C: "،" ARABIC COMMA
+ // U+061B: "؛" ARABIC SEMICOLON
+ /* keylabel_for_tablet_comma */ "\u060C",
+ /* more_keys_for_tablet_period */ "!text/more_keys_for_arabic_diacritics",
+ // U+00BF: "¿" INVERTED QUESTION MARK
+ /* more_keys_for_question */ "?,\u00BF",
+ /* more_keys_for_h ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null,
+ /* ~ keylabel_for_spanish_row2_10 */
+ // U+266A: "♪" EIGHTH NOTE
+ /* more_keys_for_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
+ /* more_keys_for_left_parenthesis */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,!text/keyspecs_for_left_parenthesis_more_keys",
+ /* more_keys_for_right_parenthesis */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,!text/keyspecs_for_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.
+ /* more_keys_for_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
+ /* keylabel_for_comma */ "\u060C",
+ /* more_keys_for_comma */ "\\,",
+ /* keyhintlabel_for_tablet_comma */ "\u061F",
+ /* more_keys_for_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\",\'",
+ // U+0651: "ّ" ARABIC SHADDA
+ /* keyhintlabel_for_period */ "\u0651",
+ /* more_keys_for_period */ "!text/more_keys_for_arabic_diacritics",
+ /* keyhintlabel_for_tablet_period */ "\u0651",
+ /* keylabel_for_symbols_question */ "\u061F",
+ /* keylabel_for_symbols_semicolon */ "\u061B",
+ // U+066A: "٪" ARABIC PERCENT SIGN
+ /* keylabel_for_symbols_percent */ "\u066A",
+ /* more_keys_for_symbols_semicolon */ ";",
+ // U+2030: "‰" PER MILLE SIGN
+ /* more_keys_for_symbols_percent */ "\\%,\u2030",
+ };
+
+ /* Language az_AZ: Azerbaijani (Azerbaijan) */
+ private static final String[] LANGUAGE_az_AZ = {
+ // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ // U+0259: "ə" LATIN SMALL LETTER SCHWA
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ // 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
+ /* more_keys_for_s */ "\u015F,\u00DF,\u015B,\u0161",
+ /* more_keys_for_n ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_l */
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u011F",
+ };
+
+ /* Language be_BY: Belarusian (Belarus) */
+ private static final String[] LANGUAGE_be_BY = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* more_keys_for_cyrillic_ie */ "\u0451",
+ /* more_keys_for_nordic_row2_10 */ null,
+ // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U
+ /* keylabel_for_east_slavic_row1_9 */ "\u045E",
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* keylabel_for_east_slavic_row1_12 */ "\u0451",
+ // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+ /* keylabel_for_east_slavic_row2_1 */ "\u044B",
+ // U+044D: "э" CYRILLIC SMALL LETTER E
+ /* keylabel_for_east_slavic_row2_11 */ "\u044D",
+ // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ /* keylabel_for_east_slavic_row3_5 */ "\u0456",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* more_keys_for_cyrillic_soft_sign */ "\u044A",
+ };
+
+ /* Language bg: Bulgarian */
+ private static final String[] LANGUAGE_bg = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ // single_quotes of Bulgarian is default single_quotes_right_left.
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes ~ */
+ null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ /* more_keys_for_s */ null,
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_t */
+ // U+00B7: "·" MIDDLE DOT
+ // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+ /* more_keys_for_l */ "l\u00B7l,\u0142",
+ /* more_keys_for_g ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ // U+00B7: "·" MIDDLE DOT
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!9,;,/,(,),#,\u00B7,!,\\,,?,&,\\%,+,\",-,:,',@",
+ /* more_keys_for_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, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_swiss_row2_11 */
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ /* keylabel_for_spanish_row2_10 */ "\u00E7",
+ /* more_keys_for_bullet ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_currency_dollar */
+ /* more_keys_for_tablet_punctuation */ "!fixedColumnOrder!8,;,/,(,),#,\u00B7,',\\,,&,\\%,+,\",-,:,@",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u00E7,\u0107",
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0148,\u00F1,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017A,\u017C",
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ /* more_keys_for_t */ "\u0165",
+ /* more_keys_for_l */ null,
+ /* more_keys_for_g */ null,
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_currency */ null,
+ // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+ /* more_keys_for_r */ "\u0159",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+ // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+ // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+ /* more_keys_for_e */ "\u00E9,\u00EB",
+ // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+ // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+ /* more_keys_for_i */ "\u00ED,\u00EF",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c */ null,
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ /* more_keys_for_s */ "\u00DF,\u015B,\u0161",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+00F0: "ð" LATIN SMALL LETTER ETH
+ /* more_keys_for_d */ "\u00F0",
+ /* more_keys_for_z */ null,
+ /* more_keys_for_t */ null,
+ // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+ /* more_keys_for_l */ "\u0142",
+ /* more_keys_for_g */ null,
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_currency ~ */
+ null, null, null,
+ /* ~ more_keys_for_k */
+ // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+ /* keylabel_for_nordic_row1_11 */ "\u00E5",
+ // U+00E6: "æ" LATIN SMALL LETTER AE
+ /* keylabel_for_nordic_row2_10 */ "\u00E6",
+ // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ /* keylabel_for_nordic_row2_11 */ "\u00F8",
+ /* more_keys_for_cyrillic_ie */ null,
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* more_keys_for_nordic_row2_10 */ "\u00E4",
+ /* keylabel_for_east_slavic_row1_9 ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_punctuation */
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* more_keys_for_nordic_row2_11 */ "\u00F6",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0117",
+ /* more_keys_for_i */ null,
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c */ null,
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ /* more_keys_for_s */ "\u00DF,\u015B,\u0161",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_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, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_i */
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ /* keylabel_for_swiss_row1_11 */ "\u00FC",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* keylabel_for_swiss_row2_10 */ "\u00F6",
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* keylabel_for_swiss_row2_11 */ "\u00E4",
+ // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+ /* more_keys_for_swiss_row1_11 */ "\u00E8",
+ // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+ /* more_keys_for_swiss_row2_10 */ "\u00E9",
+ // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+ /* more_keys_for_swiss_row2_11 */ "\u00E0",
+ };
+
+ /* Language el: Greek */
+ private static final String[] LANGUAGE_el = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0391: "Α" GREEK CAPITAL LETTER ALPHA
+ // U+0392: "Β" GREEK CAPITAL LETTER BETA
+ // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA
+ /* label_to_alpha_key */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
+ /* double_quotes */ null,
+ /* single_quotes */ null,
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ /* more_keys_for_c */ "\u00E7",
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ /* more_keys_for_s */ "\u00DF",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ /* more_keys_for_n */ "\u00F1",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EE,\u00EF,\u0129,\u00EC,\u012F,\u012B,\u0131,\u0133",
+ /* double_quotes */ null,
+ /* single_quotes */ null,
+ // 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
+ /* more_keys_for_c */ "\u0107,\u010D,\u00E7,\u010B",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B",
+ /* label_to_alpha_key */ null,
+ // 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_g */ "\u011F,\u0121,\u0123",
+ /* single_angle_quotes ~ */
+ null, null, null,
+ /* ~ keylabel_for_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
+ /* more_keys_for_r */ "\u0159,\u0155,\u0157",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ // U+0138: "ĸ" LATIN SMALL LETTER KRA
+ /* more_keys_for_k */ "\u0137,\u0138",
+ /* keylabel_for_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,
+ /* ~ more_keys_for_question */
+ // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX
+ // U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE
+ /* more_keys_for_h */ "\u0125,\u0127",
+ // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX
+ /* more_keys_for_w */ "w,\u0175",
+ /* more_keys_for_cyrillic_u ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null,
+ /* ~ more_keys_for_swiss_row2_11 */
+ // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
+ /* keylabel_for_spanish_row2_10 */ "\u0135",
+ /* more_keys_for_bullet ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null,
+ /* ~ more_keys_for_symbols_percent */
+ // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX
+ /* more_keys_for_v */ "w,\u0175",
+ /* more_keys_for_j ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_exclamation */
+ /* more_keys_for_q */ "q",
+ /* more_keys_for_x */ "x",
+ // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
+ /* keylabel_for_q */ "\u015D",
+ // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
+ /* keylabel_for_w */ "\u011D",
+ // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
+ /* keylabel_for_y */ "\u016D",
+ // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
+ /* keylabel_for_x */ "\u0109",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ /* more_keys_for_s */ null,
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ // U+00A1: "¡" INVERTED EXCLAMATION MARK
+ // U+00BF: "¿" INVERTED QUESTION MARK
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!9,\u00A1,;,/,(,),#,!,\\,,?,\u00BF,&,\\%,+,\",-,:,',@",
+ };
+
+ /* Language et_EE: Estonian (Estonia) */
+ private static final String[] LANGUAGE_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u012B,\u00EC,\u012F,\u00ED,\u00EE,\u00EF,\u0131",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u00E7,\u0107",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0146,\u00F1,\u0144,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017C,\u017A",
+ // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_l */ "\u013C,\u0142,\u013A,\u013E",
+ // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u0123,\u011F",
+ /* single_angle_quotes ~ */
+ null, null, null,
+ /* ~ keylabel_for_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
+ /* more_keys_for_r */ "\u0157,\u0159,\u0155",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ /* more_keys_for_k */ "\u0137",
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ /* keylabel_for_nordic_row1_11 */ "\u00FC",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* keylabel_for_nordic_row2_10 */ "\u00F6",
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* keylabel_for_nordic_row2_11 */ "\u00E4",
+ /* more_keys_for_cyrillic_ie */ null,
+ // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+ /* more_keys_for_nordic_row2_10 */ "\u00F5",
+ };
+
+ /* Language fa: Persian */
+ private static final String[] LANGUAGE_fa = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // 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
+ /* label_to_alpha_key */ "\u0627\u200C\u0628\u200C\u067E",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+FDFC: "﷼" RIAL SIGN
+ /* keylabel_for_currency */ "\uFDFC",
+ /* more_keys_for_r ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ // U+061F: "؟" ARABIC QUESTION MARK
+ // U+060C: "،" ARABIC COMMA
+ // U+061B: "؛" ARABIC SEMICOLON
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis",
+ /* more_keys_for_nordic_row2_11 */ null,
+ // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
+ /* keylabel_for_symbols_1 */ "\u06F1",
+ // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
+ /* keylabel_for_symbols_2 */ "\u06F2",
+ // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
+ /* keylabel_for_symbols_3 */ "\u06F3",
+ // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
+ /* keylabel_for_symbols_4 */ "\u06F4",
+ // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
+ /* keylabel_for_symbols_5 */ "\u06F5",
+ // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
+ /* keylabel_for_symbols_6 */ "\u06F6",
+ // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
+ /* keylabel_for_symbols_7 */ "\u06F7",
+ // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
+ /* keylabel_for_symbols_8 */ "\u06F8",
+ // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
+ /* keylabel_for_symbols_9 */ "\u06F9",
+ // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
+ /* keylabel_for_symbols_0 */ "\u06F0",
+ // Label for "switch to symbols" key.
+ // U+061F: "؟" ARABIC QUESTION MARK
+ /* label_to_symbol_key */ "\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.
+ /* label_to_symbol_with_microphone_key */ "\u06F3\u06F2\u06F1",
+ /* additional_more_keys_for_symbols_1 */ "1",
+ /* additional_more_keys_for_symbols_2 */ "2",
+ /* additional_more_keys_for_symbols_3 */ "3",
+ /* additional_more_keys_for_symbols_4 */ "4",
+ /* additional_more_keys_for_symbols_5 */ "5",
+ /* additional_more_keys_for_symbols_6 */ "6",
+ /* additional_more_keys_for_symbols_7 */ "7",
+ /* additional_more_keys_for_symbols_8 */ "8",
+ /* additional_more_keys_for_symbols_9 */ "9",
+ // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+ // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+ /* additional_more_keys_for_symbols_0 */ "0,\u066B,\u066C",
+ // U+2605: "★" BLACK STAR
+ // U+066D: "٭" ARABIC FIVE POINTED STAR
+ /* more_keys_for_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",
+ // 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
+ /* keylabel_for_tablet_comma */ "\u060C",
+ /* more_keys_for_tablet_period */ "!text/more_keys_for_arabic_diacritics",
+ // U+00BF: "¿" INVERTED QUESTION MARK
+ /* more_keys_for_question */ "?,\u00BF",
+ /* more_keys_for_h ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null,
+ /* ~ keylabel_for_spanish_row2_10 */
+ // U+266A: "♪" EIGHTH NOTE
+ /* more_keys_for_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
+ /* more_keys_for_left_parenthesis */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,!text/keyspecs_for_left_parenthesis_more_keys",
+ /* more_keys_for_right_parenthesis */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,!text/keyspecs_for_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.
+ /* more_keys_for_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
+ /* keylabel_for_comma */ "\u060C",
+ /* more_keys_for_comma */ "\\,",
+ /* keyhintlabel_for_tablet_comma */ "\u061F",
+ /* more_keys_for_tablet_comma */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,!text/keyspec_left_double_angle_quote,!text/keyspec_right_double_angle_quote",
+ // U+064B: "ً" ARABIC FATHATAN
+ /* keyhintlabel_for_period */ "\u064B",
+ /* more_keys_for_period */ "!text/more_keys_for_arabic_diacritics",
+ /* keyhintlabel_for_tablet_period */ "\u064B",
+ /* keylabel_for_symbols_question */ "\u061F",
+ /* keylabel_for_symbols_semicolon */ "\u061B",
+ // U+066A: "٪" ARABIC PERCENT SIGN
+ /* keylabel_for_symbols_percent */ "\u066A",
+ /* more_keys_for_symbols_semicolon */ ";",
+ // U+2030: "‰" PER MILLE SIGN
+ /* more_keys_for_symbols_percent */ "\\%,\u2030",
+ /* more_keys_for_v ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_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
+ /* more_keys_for_less_than */ "!fixedColumnOrder!3,!text/keyspec_left_single_angle_quote;,!text/keyspec_less_than_equal;,!text/keyspec_less_than",
+ /* more_keys_for_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote;,!text/keyspec_greater_than_equal;,!text/keyspec_greater_than",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_o */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ /* more_keys_for_u */ "\u00FC",
+ /* more_keys_for_e ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_c */
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ /* more_keys_for_s */ "\u0161,\u00DF,\u015B",
+ /* more_keys_for_n ~ */
+ null, null, null, null,
+ /* ~ more_keys_for_d */
+ // 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
+ /* more_keys_for_z */ "\u017E,\u017A,\u017C",
+ /* more_keys_for_t ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_k */
+ // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+ /* keylabel_for_nordic_row1_11 */ "\u00E5",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* keylabel_for_nordic_row2_10 */ "\u00F6",
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* keylabel_for_nordic_row2_11 */ "\u00E4",
+ /* more_keys_for_cyrillic_ie */ null,
+ // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ /* more_keys_for_nordic_row2_10 */ "\u00F8",
+ /* keylabel_for_east_slavic_row1_9 ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_punctuation */
+ // U+00E6: "æ" LATIN SMALL LETTER AE
+ /* more_keys_for_nordic_row2_11 */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EE,%,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ /* more_keys_for_s ~ */
+ null, null, null,
+ /* ~ label_to_alpha_key */
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "%,\u00FF",
+ /* more_keys_for_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, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_i */
+ // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+ /* keylabel_for_swiss_row1_11 */ "\u00E8",
+ // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+ /* keylabel_for_swiss_row2_10 */ "\u00E9",
+ // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+ /* keylabel_for_swiss_row2_11 */ "\u00E0",
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ /* more_keys_for_swiss_row1_11 */ "\u00FC",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* more_keys_for_swiss_row2_10 */ "\u00F6",
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* more_keys_for_swiss_row2_11 */ "\u00E4",
+ };
+
+ /* Language hi: Hindi */
+ private static final String[] LANGUAGE_hi = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0915: "क" DEVANAGARI LETTER KA
+ // U+0916: "ख" DEVANAGARI LETTER KHA
+ // U+0917: "ग" DEVANAGARI LETTER GA
+ /* label_to_alpha_key */ "\u0915\u0916\u0917",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20B9: "₹" INDIAN RUPEE SIGN
+ /* keylabel_for_currency */ "\u20B9",
+ /* more_keys_for_r ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_nordic_row2_11 */
+ // U+0967: "१" DEVANAGARI DIGIT ONE
+ /* keylabel_for_symbols_1 */ "\u0967",
+ // U+0968: "२" DEVANAGARI DIGIT TWO
+ /* keylabel_for_symbols_2 */ "\u0968",
+ // U+0969: "३" DEVANAGARI DIGIT THREE
+ /* keylabel_for_symbols_3 */ "\u0969",
+ // U+096A: "४" DEVANAGARI DIGIT FOUR
+ /* keylabel_for_symbols_4 */ "\u096A",
+ // U+096B: "५" DEVANAGARI DIGIT FIVE
+ /* keylabel_for_symbols_5 */ "\u096B",
+ // U+096C: "६" DEVANAGARI DIGIT SIX
+ /* keylabel_for_symbols_6 */ "\u096C",
+ // U+096D: "७" DEVANAGARI DIGIT SEVEN
+ /* keylabel_for_symbols_7 */ "\u096D",
+ // U+096E: "८" DEVANAGARI DIGIT EIGHT
+ /* keylabel_for_symbols_8 */ "\u096E",
+ // U+096F: "९" DEVANAGARI DIGIT NINE
+ /* keylabel_for_symbols_9 */ "\u096F",
+ // U+0966: "०" DEVANAGARI DIGIT ZERO
+ /* keylabel_for_symbols_0 */ "\u0966",
+ // Label for "switch to symbols" key.
+ /* label_to_symbol_key */ "?\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.
+ /* label_to_symbol_with_microphone_key */ "\u0967\u0968\u0969",
+ /* additional_more_keys_for_symbols_1 */ "1",
+ /* additional_more_keys_for_symbols_2 */ "2",
+ /* additional_more_keys_for_symbols_3 */ "3",
+ /* additional_more_keys_for_symbols_4 */ "4",
+ /* additional_more_keys_for_symbols_5 */ "5",
+ /* additional_more_keys_for_symbols_6 */ "6",
+ /* additional_more_keys_for_symbols_7 */ "7",
+ /* additional_more_keys_for_symbols_8 */ "8",
+ /* additional_more_keys_for_symbols_9 */ "9",
+ /* additional_more_keys_for_symbols_0 */ "0",
+ };
+
+ /* Language hr: Croatian */
+ private static final String[] LANGUAGE_hr = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ /* more_keys_for_c */ "\u010D,\u0107,\u00E7",
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ /* more_keys_for_s */ "\u0161,\u015B,\u00DF",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key */ null,
+ /* more_keys_for_y */ null,
+ // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017A,\u017C",
+ /* more_keys_for_t ~ */
+ null, null, null,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ /* more_keys_for_c ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ };
+
+ /* Language hy_AM: Armenian (Armenia) */
+ private static final String[] LANGUAGE_hy_AM = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB
+ // U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN
+ // U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM
+ /* label_to_alpha_key */ "\u0531\u0532\u0533",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_soft_sign */
+ // 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
+ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,!,?,\u0559,\u055A,.,\u055C,\\,,\u055E,:,;,\u055F,\u00AB,\u00BB,\u058A,\u055D,\u055B",
+ /* more_keys_for_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,
+ /* ~ keyspec_right_single_angle_quote */
+ // U+058F: "֏" ARMENIAN DRAM SIGN
+ // TODO: Enable this when we have glyph for the following letter
+ // <string name="keylabel_for_currency">&#x058F;</string>
+ //
+ // U+055D: "՝" ARMENIAN COMMA
+ /* keylabel_for_tablet_comma */ "\u055D",
+ /* more_keys_for_tablet_period */ "!text/more_keys_for_punctuation",
+ // U+055E: "՞" ARMENIAN QUESTION MARK
+ // U+00BF: "¿" INVERTED QUESTION MARK
+ /* more_keys_for_question */ "\u055E,\u00BF",
+ /* more_keys_for_h ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_greater_than */
+ // U+0589: "։" ARMENIAN FULL STOP
+ /* keylabel_for_period */ "\u0589",
+ /* keylabel_for_tablet_period */ "\u0589",
+ // U+055C: "՜" ARMENIAN EXCLAMATION MARK
+ // U+00A1: "¡" INVERTED EXCLAMATION MARK
+ /* more_keys_for_exclamation */ "\u055C,\u00A1",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null, null,
+ /* ~ label_to_alpha_key */
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+00F0: "ð" LATIN SMALL LETTER ETH
+ /* more_keys_for_d */ "\u00F0",
+ /* more_keys_for_z */ null,
+ // U+00FE: "þ" LATIN SMALL LETTER THORN
+ /* more_keys_for_t */ "\u00FE",
+ /* more_keys_for_l ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_k */
+ // U+00F0: "ð" LATIN SMALL LETTER ETH
+ /* keylabel_for_nordic_row1_11 */ "\u00F0",
+ // U+00E6: "æ" LATIN SMALL LETTER AE
+ /* keylabel_for_nordic_row2_10 */ "\u00E6",
+ // U+00FE: "þ" LATIN SMALL LETTER THORN
+ /* keylabel_for_nordic_row2_11 */ "\u00FE",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u012F,\u012B",
+ };
+
+ /* Language iw: Hebrew */
+ private static final String[] LANGUAGE_iw = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_rqm_9qm",
+ /* single_quotes */ "!text/single_rqm_9qm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+05D0: "א" HEBREW LETTER ALEF
+ // U+05D1: "ב" HEBREW LETTER BET
+ // U+05D2: "ג" HEBREW LETTER GIMEL
+ /* label_to_alpha_key */ "\u05D0\u05D1\u05D2",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20AA: "₪" NEW SHEQEL SIGN
+ /* keylabel_for_currency */ "\u20AA",
+ /* more_keys_for_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,
+ /* ~ additional_more_keys_for_symbols_0 */
+ // U+2605: "★" BLACK STAR
+ /* more_keys_for_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",
+ /* keylabel_for_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,
+ /* ~ more_keys_for_tablet_punctuation */
+ // U+00B1: "±" PLUS-MINUS SIGN
+ // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
+ /* more_keys_for_plus */ "\u00B1,\uFB29",
+ };
+
+ /* Language ka_GE: Georgian (Georgia) */
+ private static final String[] LANGUAGE_ka_GE = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+10D0: "ა" GEORGIAN LETTER AN
+ // U+10D1: "ბ" GEORGIAN LETTER BAN
+ // U+10D2: "გ" GEORGIAN LETTER GAN
+ /* label_to_alpha_key */ "\u10D0\u10D1\u10D2",
+ };
+
+ /* Language kk: Kazakh */
+ private static final String[] LANGUAGE_kk = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* more_keys_for_cyrillic_ie */ "\u0451",
+ /* more_keys_for_nordic_row2_10 */ null,
+ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+ /* keylabel_for_east_slavic_row1_9 */ "\u0449",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* keylabel_for_east_slavic_row1_12 */ "\u044A",
+ // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+ /* keylabel_for_east_slavic_row2_1 */ "\u044B",
+ // U+044D: "э" CYRILLIC SMALL LETTER E
+ /* keylabel_for_east_slavic_row2_11 */ "\u044D",
+ // U+0438: "и" CYRILLIC SMALL LETTER I
+ /* keylabel_for_east_slavic_row3_5 */ "\u0438",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* more_keys_for_cyrillic_soft_sign */ "\u044A",
+ /* more_keys_for_punctuation ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_w */
+ // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
+ // U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+ /* more_keys_for_cyrillic_u */ "\u04AF,\u04B1",
+ // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER
+ /* more_keys_for_cyrillic_en */ "\u04A3",
+ // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE
+ /* more_keys_for_cyrillic_ghe */ "\u0493",
+ // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ /* more_keys_for_east_slavic_row2_1 */ "\u0456",
+ // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O
+ /* more_keys_for_cyrillic_o */ "\u04E9",
+ /* keylabel_for_south_slavic_row1_6 ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_j */
+ // U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER
+ /* more_keys_for_cyrillic_ka */ "\u049B",
+ // U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA
+ /* more_keys_for_cyrillic_a */ "\u04D9",
+ // U+04BB: "һ" CYRILLIC SMALL LETTER SHHA
+ /* more_keys_for_east_slavic_row2_11 */ "\u04BB",
+ };
+
+ /* Language km_KH: Khmer (Cambodia) */
+ private static final String[] LANGUAGE_km_KH = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+1780: "ក" KHMER LETTER KA
+ // U+1781: "ខ" KHMER LETTER KHA
+ // U+1782: "គ" KHMER LETTER KO
+ /* label_to_alpha_key */ "\u1780\u1781\u1782",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_east_slavic_row2_11 */
+ // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
+ /* more_keys_for_currency_dollar */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+ };
+
+ /* Language ky: Kirghiz */
+ private static final String[] LANGUAGE_ky = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* more_keys_for_cyrillic_ie */ "\u0451",
+ /* more_keys_for_nordic_row2_10 */ null,
+ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+ /* keylabel_for_east_slavic_row1_9 */ "\u0449",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* keylabel_for_east_slavic_row1_12 */ "\u044A",
+ // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+ /* keylabel_for_east_slavic_row2_1 */ "\u044B",
+ // U+044D: "э" CYRILLIC SMALL LETTER E
+ /* keylabel_for_east_slavic_row2_11 */ "\u044D",
+ // U+0438: "и" CYRILLIC SMALL LETTER I
+ /* keylabel_for_east_slavic_row3_5 */ "\u0438",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* more_keys_for_cyrillic_soft_sign */ "\u044A",
+ /* more_keys_for_punctuation ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_w */
+ // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
+ /* more_keys_for_cyrillic_u */ "\u04AF",
+ // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER
+ /* more_keys_for_cyrillic_en */ "\u04A3",
+ /* more_keys_for_cyrillic_ghe */ null,
+ /* more_keys_for_east_slavic_row2_1 */ null,
+ // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O
+ /* more_keys_for_cyrillic_o */ "\u04E9",
+ };
+
+ /* Language lo_LA: Lao (Laos) */
+ private static final String[] LANGUAGE_lo_LA = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0E81: "ກ" LAO LETTER KO
+ // U+0E82: "ຂ" LAO LETTER KHO SUNG
+ // U+0E84: "ຄ" LAO LETTER KHO TAM
+ /* label_to_alpha_key */ "\u0E81\u0E82\u0E84",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20AD: "₭" KIP SIGN
+ /* keylabel_for_currency */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u012F,\u012B,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u00E7,\u0107",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0146,\u00F1,\u0144,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017C,\u017A",
+ // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_l */ "\u013C,\u0142,\u013A,\u013E",
+ // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u0123,\u011F",
+ /* single_angle_quotes ~ */
+ null, null, null,
+ /* ~ keylabel_for_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
+ /* more_keys_for_r */ "\u0157,\u0159,\u0155",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ /* more_keys_for_k */ "\u0137",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u012B,\u012F,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u00E7,\u0107",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0146,\u00F1,\u0144,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017C,\u017A",
+ // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_l */ "\u013C,\u0142,\u013A,\u013E",
+ // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u0123,\u011F",
+ /* single_angle_quotes ~ */
+ null, null, null,
+ /* ~ keylabel_for_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
+ /* more_keys_for_r */ "\u0157,\u0159,\u0155",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ /* more_keys_for_k */ "\u0137",
+ };
+
+ /* Language mk: Macedonian */
+ private static final String[] LANGUAGE_mk = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
+ /* more_keys_for_cyrillic_ie */ "\u0450",
+ /* more_keys_for_nordic_row2_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, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_o */
+ // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
+ /* keylabel_for_south_slavic_row1_6 */ "\u0455",
+ // U+045C: "ќ" CYRILLIC SMALL LETTER KJE
+ /* keylabel_for_south_slavic_row2_11 */ "\u045C",
+ // U+0437: "з" CYRILLIC SMALL LETTER ZE
+ /* keylabel_for_south_slavic_row3_1 */ "\u0437",
+ // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE
+ /* keylabel_for_south_slavic_row3_8 */ "\u0453",
+ // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
+ /* more_keys_for_cyrillic_i */ "\u045D",
+ };
+
+ /* Language mn_MN: Mongolian (Mongolia) */
+ private static final String[] LANGUAGE_mn_MN = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20AE: "₮" TUGRIK SIGN
+ /* keylabel_for_currency */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
+ /* more_keys_for_i */ null,
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ /* more_keys_for_c ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_k */
+ // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+ /* keylabel_for_nordic_row1_11 */ "\u00E5",
+ // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ /* keylabel_for_nordic_row2_10 */ "\u00F8",
+ // U+00E6: "æ" LATIN SMALL LETTER AE
+ /* keylabel_for_nordic_row2_11 */ "\u00E6",
+ /* more_keys_for_cyrillic_ie */ null,
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* more_keys_for_nordic_row2_10 */ "\u00F6",
+ /* keylabel_for_east_slavic_row1_9 ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_punctuation */
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* more_keys_for_nordic_row2_11 */ "\u00E4",
+ };
+
+ /* Language ne_NP: Nepali (Nepal) */
+ private static final String[] LANGUAGE_ne_NP = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0915: "क" DEVANAGARI LETTER KA
+ // U+0916: "ख" DEVANAGARI LETTER KHA
+ // U+0917: "ग" DEVANAGARI LETTER GA
+ /* label_to_alpha_key */ "\u0915\u0916\u0917",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
+ /* keylabel_for_currency */ "\u0930\u0941.",
+ /* more_keys_for_r ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_nordic_row2_11 */
+ // U+0967: "१" DEVANAGARI DIGIT ONE
+ /* keylabel_for_symbols_1 */ "\u0967",
+ // U+0968: "२" DEVANAGARI DIGIT TWO
+ /* keylabel_for_symbols_2 */ "\u0968",
+ // U+0969: "३" DEVANAGARI DIGIT THREE
+ /* keylabel_for_symbols_3 */ "\u0969",
+ // U+096A: "४" DEVANAGARI DIGIT FOUR
+ /* keylabel_for_symbols_4 */ "\u096A",
+ // U+096B: "५" DEVANAGARI DIGIT FIVE
+ /* keylabel_for_symbols_5 */ "\u096B",
+ // U+096C: "६" DEVANAGARI DIGIT SIX
+ /* keylabel_for_symbols_6 */ "\u096C",
+ // U+096D: "७" DEVANAGARI DIGIT SEVEN
+ /* keylabel_for_symbols_7 */ "\u096D",
+ // U+096E: "८" DEVANAGARI DIGIT EIGHT
+ /* keylabel_for_symbols_8 */ "\u096E",
+ // U+096F: "९" DEVANAGARI DIGIT NINE
+ /* keylabel_for_symbols_9 */ "\u096F",
+ // U+0966: "०" DEVANAGARI DIGIT ZERO
+ /* keylabel_for_symbols_0 */ "\u0966",
+ // Label for "switch to symbols" key.
+ /* label_to_symbol_key */ "?\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.
+ /* label_to_symbol_with_microphone_key */ "\u0967\u0968\u0969",
+ /* additional_more_keys_for_symbols_1 */ "1",
+ /* additional_more_keys_for_symbols_2 */ "2",
+ /* additional_more_keys_for_symbols_3 */ "3",
+ /* additional_more_keys_for_symbols_4 */ "4",
+ /* additional_more_keys_for_symbols_5 */ "5",
+ /* additional_more_keys_for_symbols_6 */ "6",
+ /* additional_more_keys_for_symbols_7 */ "7",
+ /* additional_more_keys_for_symbols_8 */ "8",
+ /* additional_more_keys_for_symbols_9 */ "9",
+ /* additional_more_keys_for_symbols_0 */ "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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133",
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ /* more_keys_for_c */ null,
+ /* more_keys_for_s */ null,
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+0133: "ij" LATIN SMALL LIGATURE IJ
+ /* more_keys_for_y */ "\u0133",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+ /* more_keys_for_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
+ /* more_keys_for_e */ "\u0119,\u00E8,\u00E9,\u00EA,\u00EB,\u0117,\u0113",
+ /* more_keys_for_i */ null,
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ /* more_keys_for_c */ "\u0107,\u00E7,\u010D",
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ /* more_keys_for_s */ "\u015B,\u00DF,\u0161",
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ /* more_keys_for_n */ "\u0144,\u00F1",
+ /* label_to_alpha_key ~ */
+ null, null, null,
+ /* ~ more_keys_for_d */
+ // 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
+ /* more_keys_for_z */ "\u017C,\u017A,\u017E",
+ /* more_keys_for_t */ null,
+ // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+ /* more_keys_for_l */ "\u0142",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EE,\u00EC,\u00EF,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u010D,\u0107",
+ };
+
+ /* Language rm: Raeto-Romance */
+ private static final String[] LANGUAGE_rm = {
+ /* more_keys_for_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
+ /* more_keys_for_o */ "\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
+ /* more_keys_for_a */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101",
+ /* more_keys_for_o ~ */
+ null, null, null,
+ /* ~ more_keys_for_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
+ /* more_keys_for_i */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+ /* double_quotes */ "!text/double_9qm_rqm",
+ /* single_quotes */ "!text/single_9qm_rqm",
+ /* more_keys_for_c */ 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
+ /* more_keys_for_s */ "\u0219,\u00DF,\u015B,\u0161",
+ /* more_keys_for_n ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_z */
+ // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW
+ /* more_keys_for_t */ "\u021B",
+ };
+
+ /* Language ru: Russian */
+ private static final String[] LANGUAGE_ru = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* more_keys_for_cyrillic_ie */ "\u0451",
+ /* more_keys_for_nordic_row2_10 */ null,
+ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+ /* keylabel_for_east_slavic_row1_9 */ "\u0449",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* keylabel_for_east_slavic_row1_12 */ "\u044A",
+ // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+ /* keylabel_for_east_slavic_row2_1 */ "\u044B",
+ // U+044D: "э" CYRILLIC SMALL LETTER E
+ /* keylabel_for_east_slavic_row2_11 */ "\u044D",
+ // U+0438: "и" CYRILLIC SMALL LETTER I
+ /* keylabel_for_east_slavic_row3_5 */ "\u0438",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* more_keys_for_cyrillic_soft_sign */ "\u044A",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u012B,\u012F,\u00EC,\u00EE,\u00EF,\u0131",
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u00E7,\u0107",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0148,\u0146,\u00F1,\u0144,\u0144",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF",
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017E,\u017C,\u017A",
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+ /* more_keys_for_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
+ /* more_keys_for_l */ "\u013E,\u013A,\u013C,\u0142",
+ // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u0123,\u011F",
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_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
+ /* more_keys_for_r */ "\u0155,\u0159,\u0157",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ /* more_keys_for_k */ "\u0137",
+ };
+
+ /* Language sl: Slovenian */
+ private static final String[] LANGUAGE_sl = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ /* more_keys_for_c */ "\u010D,\u0107",
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ /* more_keys_for_s */ "\u0161",
+ /* more_keys_for_n ~ */
+ null, null, null,
+ /* ~ more_keys_for_y */
+ // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+ /* more_keys_for_d */ "\u0111",
+ // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+ /* more_keys_for_z */ "\u017E",
+ /* more_keys_for_t ~ */
+ null, null, null,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ };
+
+ /* Language sr: Serbian */
+ private static final String[] LANGUAGE_sr = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // 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
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null,
+ /* ~ more_keys_for_g */
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_currency ~ */
+ null, null, null, null, null, null,
+ /* ~ keylabel_for_nordic_row2_11 */
+ // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
+ /* more_keys_for_cyrillic_ie */ "\u0450",
+ /* more_keys_for_nordic_row2_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, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_cyrillic_o */
+ // 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">&#x0161;,&#x00DF;,&#x015B;</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">&#x010D;,&#x00E7;,&#x0107;</string>
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ // <string name="more_keys_for_d">&#x010F;</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">&#x017E;,&#x017A;,&#x017C;</string>
+ // END: More keys definitions for Serbian (Latin)
+ // BEGIN: More keys definitions for Serbian (Cyrillic)
+ // U+0437: "з" CYRILLIC SMALL LETTER ZE
+ /* keylabel_for_south_slavic_row1_6 */ "\u0437",
+ // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE
+ /* keylabel_for_south_slavic_row2_11 */ "\u045B",
+ // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
+ /* keylabel_for_south_slavic_row3_1 */ "\u0455",
+ // U+0452: "ђ" CYRILLIC SMALL LETTER DJE
+ /* keylabel_for_south_slavic_row3_8 */ "\u0452",
+ // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
+ /* more_keys_for_cyrillic_i */ "\u045D",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EC,\u00EE,\u00EF",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u0144,\u00F1,\u0148",
+ /* label_to_alpha_key */ null,
+ // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+ // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ /* more_keys_for_y */ "\u00FD,\u00FF,\u00FC",
+ // U+00F0: "ð" LATIN SMALL LETTER ETH
+ // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+ /* more_keys_for_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
+ /* more_keys_for_z */ "\u017A,\u017E,\u017C",
+ // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+ // U+00FE: "þ" LATIN SMALL LETTER THORN
+ /* more_keys_for_t */ "\u0165,\u00FE",
+ // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+ /* more_keys_for_l */ "\u0142",
+ /* more_keys_for_g */ null,
+ /* single_angle_quotes */ "!text/single_raqm_laqm",
+ /* double_angle_quotes */ "!text/double_raqm_laqm",
+ /* keylabel_for_currency */ null,
+ // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+ /* more_keys_for_r */ "\u0159",
+ /* more_keys_for_k */ null,
+ // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+ /* keylabel_for_nordic_row1_11 */ "\u00E5",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ /* keylabel_for_nordic_row2_10 */ "\u00F6",
+ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+ /* keylabel_for_nordic_row2_11 */ "\u00E4",
+ /* more_keys_for_cyrillic_ie */ null,
+ // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ // U+0153: "œ" LATIN SMALL LIGATURE OE
+ /* more_keys_for_nordic_row2_10 */ "\u00F8,\u0153",
+ /* keylabel_for_east_slavic_row1_9 ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_punctuation */
+ // U+00E6: "æ" LATIN SMALL LETTER AE
+ /* more_keys_for_nordic_row2_11 */ "\u00E6",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
+ /* double_quotes */ null,
+ /* single_quotes */ null,
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ /* more_keys_for_c */ "\u00E7",
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ /* more_keys_for_s */ "\u00DF",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ /* more_keys_for_n */ "\u00F1",
+ /* label_to_alpha_key ~ */
+ null, null, null, null, null, null,
+ /* ~ more_keys_for_l */
+ /* more_keys_for_g */ "g\'",
+ };
+
+ /* Language th: Thai */
+ private static final String[] LANGUAGE_th = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null, null, null, null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0E01: "ก" THAI CHARACTER KO KAI
+ // U+0E02: "ข" THAI CHARACTER KHO KHAI
+ // U+0E04: "ค" THAI CHARACTER KHO KHWAI
+ /* label_to_alpha_key */ "\u0E01\u0E02\u0E04",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
+ /* keylabel_for_currency */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ /* more_keys_for_s */ null,
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+ /* more_keys_for_n */ "\u00F1,\u0144",
+ };
+
+ /* Language tr: Turkish */
+ private static final String[] LANGUAGE_tr = {
+ // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+ /* double_quotes */ null,
+ /* single_quotes */ 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u010D",
+ // 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
+ /* more_keys_for_s */ "\u015F,\u00DF,\u015B,\u0161",
+ /* more_keys_for_n ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_l */
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* more_keys_for_g */ "\u011F",
+ };
+
+ /* Language uk: Ukrainian */
+ private static final String[] LANGUAGE_uk = {
+ /* more_keys_for_a ~ */
+ null, null, null, null, null,
+ /* ~ more_keys_for_i */
+ /* double_quotes */ "!text/double_9qm_lqm",
+ /* single_quotes */ "!text/single_9qm_lqm",
+ /* more_keys_for_c ~ */
+ null, null, null,
+ /* ~ more_keys_for_n */
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* label_to_alpha_key */ "\u0410\u0411\u0412",
+ /* more_keys_for_y ~ */
+ null, null, null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20B4: "₴" HRYVNIA SIGN
+ /* keylabel_for_currency */ "\u20B4",
+ /* more_keys_for_r ~ */
+ null, null, null, null, null, null, null,
+ /* ~ more_keys_for_nordic_row2_10 */
+ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+ /* keylabel_for_east_slavic_row1_9 */ "\u0449",
+ // U+0457: "ї" CYRILLIC SMALL LETTER YI
+ /* keylabel_for_east_slavic_row1_12 */ "\u0457",
+ // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ /* keylabel_for_east_slavic_row2_1 */ "\u0456",
+ // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE
+ /* keylabel_for_east_slavic_row2_11 */ "\u0454",
+ // U+0438: "и" CYRILLIC SMALL LETTER I
+ /* keylabel_for_east_slavic_row3_5 */ "\u0438",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* more_keys_for_cyrillic_soft_sign */ "\u044A",
+ /* more_keys_for_punctuation ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null,
+ /* ~ more_keys_for_cyrillic_en */
+ // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN
+ /* more_keys_for_cyrillic_ghe */ "\u0491",
+ // U+0457: "ї" CYRILLIC SMALL LETTER YI
+ /* more_keys_for_east_slavic_row2_1 */ "\u0457",
+ };
+
+ /* 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EC,\u00ED,\u1EC9,\u0129,\u1ECB",
+ /* double_quotes ~ */
+ null, null, null, null, null, null,
+ /* ~ label_to_alpha_key */
+ // 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
+ /* more_keys_for_y */ "\u1EF3,\u00FD,\u1EF7,\u1EF9,\u1EF5",
+ // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+ /* more_keys_for_d */ "\u0111",
+ /* more_keys_for_z ~ */
+ null, null, null, null, null, null,
+ /* ~ double_angle_quotes */
+ // U+20AB: "₫" DONG SIGN
+ /* keylabel_for_currency */ "\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
+ /* double_quotes */ null,
+ /* single_quotes */ null,
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ /* more_keys_for_c */ "\u00E7",
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ /* more_keys_for_s */ "\u00DF",
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ /* more_keys_for_n */ "\u00F1",
+ };
+
+ /* 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
+ /* more_keys_for_a */ "\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u00E3,\u00E5,\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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u0129,\u012B,\u012D,\u012F,\u0131,\u0133",
+ /* double_quotes */ null,
+ /* single_quotes */ null,
+ // 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
+ /* more_keys_for_c */ "\u00E7,\u0107,\u0109,\u010B,\u010D",
+ // 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
+ /* more_keys_for_s */ "\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
+ /* more_keys_for_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B",
+ /* label_to_alpha_key */ null,
+ // 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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_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
+ /* more_keys_for_g */ "\u011D,\u011F,\u0121,\u0123",
+ /* single_angle_quotes ~ */
+ null, null, null,
+ /* ~ keylabel_for_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
+ /* more_keys_for_r */ "\u0155,\u0157,\u0159",
+ // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+ // U+0138: "ĸ" LATIN SMALL LETTER KRA
+ /* more_keys_for_k */ "\u0137,\u0138",
+ /* keylabel_for_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,
+ /* ~ more_keys_for_question */
+ // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX
+ /* more_keys_for_h */ "\u0125",
+ // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX
+ /* more_keys_for_w */ "\u0175",
+ /* more_keys_for_cyrillic_u ~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null,
+ /* ~ more_keys_for_v */
+ // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
+ /* more_keys_for_j */ "\u0135",
+ };
+
+ // TODO: Use the language + "_" + region representation for the locale string key.
+ // Currently we are dropping the region from the key.
+ private static final Object[] LANGUAGES_AND_TEXTS = {
+ // "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */
+ "DEFAULT", LANGUAGE_DEFAULT, /* 171/171 default */
+ "af", LANGUAGE_af, /* 8/ 12 Afrikaans */
+ "ar", LANGUAGE_ar, /* 58/110 Arabic */
+ "az", LANGUAGE_az_AZ, /* 8/ 17 Azerbaijani (Azerbaijan) */
+ "be", LANGUAGE_be_BY, /* 10/ 33 Belarusian (Belarus) */
+ "bg", LANGUAGE_bg, /* 2/ 11 Bulgarian */
+ "ca", LANGUAGE_ca, /* 11/117 Catalan */
+ "cs", LANGUAGE_cs, /* 17/ 21 Czech */
+ "da", LANGUAGE_da, /* 19/ 35 Danish */
+ "de", LANGUAGE_de, /* 16/ 93 German */
+ "el", LANGUAGE_el, /* 1/ 11 Greek */
+ "en", LANGUAGE_en, /* 8/ 10 English */
+ "eo", LANGUAGE_eo, /* 26/129 Esperanto */
+ "es", LANGUAGE_es, /* 8/ 34 Spanish */
+ "et", LANGUAGE_et_EE, /* 22/ 27 Estonian (Estonia) */
+ "fa", LANGUAGE_fa, /* 61/120 Persian */
+ "fi", LANGUAGE_fi, /* 10/ 35 Finnish */
+ "fr", LANGUAGE_fr, /* 13/ 93 French */
+ "hi", LANGUAGE_hi, /* 24/ 57 Hindi */
+ "hr", LANGUAGE_hr, /* 9/ 19 Croatian */
+ "hu", LANGUAGE_hu, /* 9/ 19 Hungarian */
+ "hy", LANGUAGE_hy_AM, /* 8/123 Armenian (Armenia) */
+ "is", LANGUAGE_is, /* 13/ 25 Icelandic */
+ "it", LANGUAGE_it, /* 5/ 5 Italian */
+ "iw", LANGUAGE_iw, /* 20/118 Hebrew */
+ "ka", LANGUAGE_ka_GE, /* 3/ 11 Georgian (Georgia) */
+ "kk", LANGUAGE_kk, /* 16/115 Kazakh */
+ "km", LANGUAGE_km_KH, /* 2/116 Khmer (Cambodia) */
+ "ky", LANGUAGE_ky, /* 11/ 82 Kirghiz */
+ "lo", LANGUAGE_lo_LA, /* 2/ 20 Lao (Laos) */
+ "lt", LANGUAGE_lt, /* 18/ 22 Lithuanian */
+ "lv", LANGUAGE_lv, /* 18/ 22 Latvian */
+ "mk", LANGUAGE_mk, /* 9/ 87 Macedonian */
+ "mn", LANGUAGE_mn_MN, /* 2/ 20 Mongolian (Mongolia) */
+ "nb", LANGUAGE_nb, /* 11/ 35 Norwegian Bokmål */
+ "ne", LANGUAGE_ne_NP, /* 24/ 57 Nepali (Nepal) */
+ "nl", LANGUAGE_nl, /* 9/ 12 Dutch */
+ "pl", LANGUAGE_pl, /* 10/ 16 Polish */
+ "pt", LANGUAGE_pt, /* 6/ 8 Portuguese */
+ "rm", LANGUAGE_rm, /* 1/ 2 Raeto-Romance */
+ "ro", LANGUAGE_ro, /* 6/ 15 Romanian */
+ "ru", LANGUAGE_ru, /* 10/ 33 Russian */
+ "sk", LANGUAGE_sk, /* 20/ 22 Slovak */
+ "sl", LANGUAGE_sl, /* 8/ 19 Slovenian */
+ "sr", LANGUAGE_sr, /* 11/ 87 Serbian */
+ "sv", LANGUAGE_sv, /* 21/ 35 Swedish */
+ "sw", LANGUAGE_sw, /* 9/ 17 Swahili */
+ "th", LANGUAGE_th, /* 2/ 20 Thai */
+ "tl", LANGUAGE_tl, /* 7/ 10 Tagalog */
+ "tr", LANGUAGE_tr, /* 7/ 17 Turkish */
+ "uk", LANGUAGE_uk, /* 12/ 81 Ukrainian */
+ "vi", LANGUAGE_vi, /* 8/ 20 Vietnamese */
+ "zu", LANGUAGE_zu, /* 8/ 10 Zulu */
+ "zz", LANGUAGE_zz, /* 19/112 Alphabet */
+ };
+
+ static {
+ for (int index = 0; index < NAMES.length; index++) {
+ sNameToIndexesMap.put(NAMES[index], index);
+ }
+
+ for (int i = 0; i < LANGUAGES_AND_TEXTS.length; i += 2) {
+ final String language = (String)LANGUAGES_AND_TEXTS[i];
+ final String[] textsTable = (String[])LANGUAGES_AND_TEXTS[i + 1];
+ sLanguageToTextsTableMap.put(language, textsTable);
+ sTextsTableToLanguageMap.put(textsTable, language);
+ }
+ }
+}
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
index 463d09344..1c6a14efe 100644
--- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
@@ -16,27 +16,22 @@
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 com.android.inputmethod.latin.makedict.Ver4DictEncoder;
+import com.android.inputmethod.latin.utils.FileUtils;
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 {
+abstract public class AbstractDictionaryWriter {
/** 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;
+ public AbstractDictionaryWriter() {
}
abstract public void clear();
@@ -55,22 +50,19 @@ abstract public class AbstractDictionaryWriter extends Dictionary {
// 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);
+ 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);
+ public void write(final File file, final Map<String, String> attributeMap) {
try {
- final DictEncoder dictEncoder = new Ver3DictEncoder(tempFile);
+ FileUtils.deleteRecursively(file);
+ file.mkdir();
+ final DictEncoder dictEncoder = new Ver4DictEncoder(file);
writeDictionary(dictEncoder, attributeMap);
- tempFile.renameTo(file);
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
} catch (UnsupportedFormatException 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..c450a1d4f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -17,19 +17,28 @@
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.FusionDictionary.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.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,10 +66,27 @@ 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;
+
private long mNativeDict;
private final Locale mLocale;
private final long mDictSize;
private final String mDictFilePath;
+ private final boolean mIsUpdatable;
private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS];
private final int[] mSpaceIndices = new int[MAX_RESULTS];
@@ -107,6 +133,7 @@ public final class BinaryDictionary extends Dictionary {
mLocale = locale;
mDictSize = length;
mDictFilePath = filename;
+ mIsUpdatable = isUpdatable;
mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
loadDictionary(filename, offset, length, isUpdatable);
}
@@ -116,15 +143,24 @@ public final class BinaryDictionary extends Dictionary {
}
private static native boolean createEmptyDictFileNative(String filePath, long dictVersion,
- String[] attributeKeyStringArray, String[] attributeValueStringArray);
+ String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray);
private static native long openNative(String sourceDir, long dictOffset, long dictSize,
boolean isUpdatable);
+ 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 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 int getSuggestionsNative(long dict, long proximityInfo,
long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
@@ -133,17 +169,22 @@ public final class BinaryDictionary extends Dictionary {
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);
+ 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 int setCurrentTimeForTestNative(int currentTime);
private static native String getPropertyNative(long dict, String query);
+ private static native boolean isCorruptedNative(long dict);
- @UsedForTesting
public static boolean createEmptyDictFile(final String filePath, final long dictVersion,
- final Map<String, String> attributeMap) {
+ 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;
@@ -152,7 +193,8 @@ public final class BinaryDictionary extends Dictionary {
valueArray[index] = attributeMap.get(key);
index++;
}
- return createEmptyDictFileNative(filePath, dictVersion, keyArray, valueArray);
+ return createEmptyDictFileNative(filePath, dictVersion, locale.toString(), keyArray,
+ valueArray);
}
// TODO: Move native dict into session
@@ -161,6 +203,48 @@ public final class BinaryDictionary extends Dictionary {
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;
+ }
+
+ @UsedForTesting
+ 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,
@@ -235,6 +319,10 @@ public final class BinaryDictionary extends Dictionary {
return mNativeDict != 0;
}
+ public int getFormatVersion() {
+ return getFormatVersionNative(mNativeDict);
+ }
+
public static float calcNormalizedScore(final String before, final String after,
final int score) {
return calcNormalizedScoreNative(StringUtils.toCodePointArray(before),
@@ -274,23 +362,75 @@ 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);
}
- // 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);
}
// Remove a bigram entry form binary dictionary in native code.
@@ -303,11 +443,29 @@ public final class BinaryDictionary extends Dictionary {
removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
}
+ 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);
+ 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);
}
public void flush() {
@@ -339,8 +497,22 @@ public final class BinaryDictionary extends Dictionary {
return calculateProbabilityNative(mNativeDict, unigramProbability, bigramProbability);
}
+ /**
+ * 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) {
+ return setCurrentTimeForTestNative(currentTime);
+ }
+
@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..a7008379f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -22,8 +22,8 @@ import android.content.res.AssetFileDescriptor;
import android.util.Log;
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.FormatSpec.FileHeader;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
@@ -112,7 +112,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) {
@@ -230,7 +230,7 @@ final public class BinaryDictionaryGetter {
try {
// Read the version of the file
final DictDecoder dictDecoder = FormatSpec.getDictDecoder(f);
- final FileHeader header = dictDecoder.readHeader();
+ final DictionaryHeader header = dictDecoder.readHeader();
final String version = header.mDictionaryOptions.mAttributes.get(VERSION_KEY);
if (null == version) {
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 9a9653094..d1ff714fc 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,7 @@ public final class Constants {
}
public static final int NOT_A_CODE = -1;
-
+ public static final int NOT_A_CURSOR_POSITION = -1;
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 +156,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 +183,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 +191,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 +218,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 +244,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 +252,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..ae9bdf3fc 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,8 +72,13 @@ 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) {
+ super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_CONTACTS,
+ false /* isUpdatable */, dictFile);
mLocale = locale;
mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale);
registerObserver(context);
@@ -83,8 +89,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
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 =
@@ -133,23 +137,24 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
private void loadDictionaryAsyncForUri(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();
+ addWords(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();
+ }
}
}
@@ -168,6 +173,10 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
if (isValidName(name)) {
addName(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;
}
@@ -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.
@@ -268,26 +282,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) && !isNameInDictionary(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)
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index fa79f5af7..e04524843 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -52,13 +52,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) {
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..43d4ba421
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -0,0 +1,582 @@
+/*
+ * 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.settings.SettingsValues;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LanguageModelParam;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+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 final Context mContext;
+ public final Locale mLocale;
+
+ private final ConcurrentHashMap<String, Dictionary> mDictionaries =
+ CollectionUtils.newConcurrentHashMap();
+ private HashSet<String> mDictionarySubsetForDebug = null;
+
+ private Dictionary mMainDictionary;
+ private ContactsBinaryDictionary mContactsDictionary;
+ private UserBinaryDictionary mUserDictionary;
+ private UserHistoryDictionary mUserHistoryDictionary;
+ private PersonalizationDictionary mPersonalizationDictionary;
+
+ private final CountDownLatch mLatchForWaitingLoadingMainDictionary;
+
+ public interface DictionaryInitializationListener {
+ public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
+ }
+
+ /**
+ * Creates instance for initialization or when the locale is changed.
+ *
+ * @param context the context
+ * @param locale the locale
+ * @param settingsValues current settings values to control what dictionaries should be used
+ * @param listener the listener
+ * @param oldDictionaryFacilitator the instance having old dictionaries. This is null when the
+ * instance is initially created.
+ */
+ public DictionaryFacilitatorForSuggest(final Context context, final Locale locale,
+ final SettingsValues settingsValues, final DictionaryInitializationListener listener,
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
+ mContext = context;
+ mLocale = locale;
+ mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
+ initForDebug(settingsValues);
+ loadMainDict(context, locale, listener);
+ setUserDictionary(new UserBinaryDictionary(context, locale));
+ resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
+ }
+
+ /**
+ * Creates instance for reloading the main dict.
+ *
+ * @param listener the listener
+ * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
+ */
+ public DictionaryFacilitatorForSuggest(final DictionaryInitializationListener listener,
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
+ mContext = oldDictionaryFacilitator.mContext;
+ mLocale = oldDictionaryFacilitator.mLocale;
+ mDictionarySubsetForDebug = oldDictionaryFacilitator.mDictionarySubsetForDebug;
+ mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
+ loadMainDict(mContext, mLocale, listener);
+ // Transfer user dictionary.
+ setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
+ // Transfer contacts dictionary.
+ setContactsDictionary(oldDictionaryFacilitator.mContactsDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_CONTACTS);
+ // Transfer user history dictionary.
+ setUserHistoryDictionary(oldDictionaryFacilitator.mUserHistoryDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER_HISTORY);
+ // Transfer personalization dictionary.
+ setPersonalizationDictionary(oldDictionaryFacilitator.mPersonalizationDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_PERSONALIZATION);
+ }
+
+ /**
+ * Creates instance for when the settings values have been changed.
+ *
+ * @param settingsValues the new settings values
+ * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
+ */
+ //
+ public DictionaryFacilitatorForSuggest(final SettingsValues settingsValues,
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
+ mContext = oldDictionaryFacilitator.mContext;
+ mLocale = oldDictionaryFacilitator.mLocale;
+ mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+ initForDebug(settingsValues);
+ // Transfer main dictionary.
+ setMainDictionary(oldDictionaryFacilitator.mMainDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_MAIN);
+ // Transfer user dictionary.
+ setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
+ oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
+ // Transfer or create additional dictionaries depending on the settings values.
+ resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
+ }
+
+ @UsedForTesting
+ public DictionaryFacilitatorForSuggest(final Context context, final Locale locale,
+ final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles) {
+ mContext = context;
+ mLocale = locale;
+ mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+ for (final String dictType : dictionaryTypes) {
+ if (dictType.equals(Dictionary.TYPE_MAIN)) {
+ final DictionaryCollection mainDictionary =
+ DictionaryFactory.createMainDictionaryFromManager(context, locale);
+ setMainDictionary(mainDictionary);
+ } else if (dictType.equals(Dictionary.TYPE_USER_HISTORY)) {
+ final UserHistoryDictionary 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();
+ setUserHistoryDictionary(userHistoryDictionary);
+ } else if (dictType.equals(Dictionary.TYPE_PERSONALIZATION)) {
+ final PersonalizationDictionary 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();
+ setPersonalizationDictionary(personalizationDictionary);
+ } else if (dictType.equals(Dictionary.TYPE_USER)) {
+ final File file = dictionaryFiles.get(dictType);
+ final UserBinaryDictionary userDictionary = new UserBinaryDictionary(
+ context, locale, file);
+ userDictionary.reloadDictionaryIfRequired();
+ userDictionary.waitAllTasksForTests();
+ setUserDictionary(userDictionary);
+ } else if (dictType.equals(Dictionary.TYPE_CONTACTS)) {
+ final File file = dictionaryFiles.get(dictType);
+ final ContactsBinaryDictionary contactsDictionary = new ContactsBinaryDictionary(
+ context, locale, file);
+ contactsDictionary.reloadDictionaryIfRequired();
+ contactsDictionary.waitAllTasksForTests();
+ setContactsDictionary(contactsDictionary);
+ } else {
+ throw new RuntimeException("Unknown dictionary type: " + dictType);
+ }
+ }
+ }
+
+ // initialize a debug flag for the personalization
+ private void initForDebug(final SettingsValues settingsValues) {
+ if (settingsValues.mUseOnlyPersonalizationDictionaryForDebug) {
+ mDictionarySubsetForDebug = new HashSet<String>();
+ mDictionarySubsetForDebug.add(Dictionary.TYPE_PERSONALIZATION);
+ }
+ }
+
+ public void close() {
+ final HashSet<Dictionary> dictionaries = CollectionUtils.newHashSet();
+ dictionaries.addAll(mDictionaries.values());
+ for (final Dictionary dictionary : dictionaries) {
+ dictionary.close();
+ }
+ }
+
+ private void loadMainDict(final Context context, final Locale locale,
+ final DictionaryInitializationListener listener) {
+ mMainDictionary = null;
+ if (listener != null) {
+ listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
+ }
+ new Thread("InitializeBinaryDictionary") {
+ @Override
+ public void run() {
+ final DictionaryCollection newMainDict =
+ DictionaryFactory.createMainDictionaryFromManager(context, locale);
+ setMainDictionary(newMainDict);
+ if (listener != null) {
+ listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
+ }
+ mLatchForWaitingLoadingMainDictionary.countDown();
+ }
+ }.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();
+ }
+
+ public boolean hasPersonalizationDictionary() {
+ return null != mPersonalizationDictionary;
+ }
+
+ 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);
+ if (mContactsDictionary != null) {
+ mContactsDictionary.waitAllTasksForTests();
+ }
+ if (mUserDictionary != null) {
+ mUserDictionary.waitAllTasksForTests();
+ }
+ if (mUserHistoryDictionary != null) {
+ mUserHistoryDictionary.waitAllTasksForTests();
+ }
+ if (mPersonalizationDictionary != null) {
+ mPersonalizationDictionary.waitAllTasksForTests();
+ }
+ }
+
+ private void setMainDictionary(final Dictionary mainDictionary) {
+ mMainDictionary = mainDictionary;
+ addOrReplaceDictionary(Dictionary.TYPE_MAIN, mainDictionary);
+ }
+
+ /**
+ * 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.
+ */
+ private void setUserDictionary(final UserBinaryDictionary userDictionary) {
+ mUserDictionary = userDictionary;
+ addOrReplaceDictionary(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.
+ */
+ private void setContactsDictionary(final ContactsBinaryDictionary contactsDictionary) {
+ mContactsDictionary = contactsDictionary;
+ addOrReplaceDictionary(Dictionary.TYPE_CONTACTS, contactsDictionary);
+ }
+
+ private void setUserHistoryDictionary(final UserHistoryDictionary userHistoryDictionary) {
+ mUserHistoryDictionary = userHistoryDictionary;
+ addOrReplaceDictionary(Dictionary.TYPE_USER_HISTORY, userHistoryDictionary);
+ }
+
+ private void setPersonalizationDictionary(
+ final PersonalizationDictionary personalizationDictionary) {
+ mPersonalizationDictionary = personalizationDictionary;
+ addOrReplaceDictionary(Dictionary.TYPE_PERSONALIZATION, personalizationDictionary);
+ }
+
+ /**
+ * Reset dictionaries that can be turned off according to the user settings.
+ *
+ * @param oldDictionaryFacilitator the instance having old dictionaries
+ * @param settingsValues current SettingsValues
+ */
+ private void resetAdditionalDictionaries(
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator,
+ final SettingsValues settingsValues) {
+ // Contacts dictionary
+ resetContactsDictionary(null != oldDictionaryFacilitator ?
+ oldDictionaryFacilitator.mContactsDictionary : null, settingsValues);
+ // User history dictionary & Personalization dictionary
+ resetPersonalizedDictionaries(oldDictionaryFacilitator, settingsValues);
+ }
+
+ /**
+ * Set the user history dictionary and personalization dictionary according to the user
+ * settings.
+ *
+ * @param oldDictionaryFacilitator the instance that has been used
+ * @param settingsValues current settingsValues
+ */
+ // TODO: Consolidate resetPersonalizedDictionaries() and resetContactsDictionary(). Call up the
+ // new method for each dictionary.
+ private void resetPersonalizedDictionaries(
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator,
+ final SettingsValues settingsValues) {
+ final boolean shouldSetDictionaries = settingsValues.mUsePersonalizedDicts;
+
+ final UserHistoryDictionary oldUserHistoryDictionary = (null == oldDictionaryFacilitator) ?
+ null : oldDictionaryFacilitator.mUserHistoryDictionary;
+ final PersonalizationDictionary oldPersonalizationDictionary =
+ (null == oldDictionaryFacilitator) ? null :
+ oldDictionaryFacilitator.mPersonalizationDictionary;
+ final UserHistoryDictionary userHistoryDictionaryToUse;
+ final PersonalizationDictionary personalizationDictionaryToUse;
+ if (!shouldSetDictionaries) {
+ userHistoryDictionaryToUse = null;
+ personalizationDictionaryToUse = null;
+ } else {
+ if (null != oldUserHistoryDictionary
+ && oldUserHistoryDictionary.mLocale.equals(mLocale)) {
+ userHistoryDictionaryToUse = oldUserHistoryDictionary;
+ } else {
+ userHistoryDictionaryToUse =
+ PersonalizationHelper.getUserHistoryDictionary(mContext, mLocale);
+ }
+ if (null != oldPersonalizationDictionary
+ && oldPersonalizationDictionary.mLocale.equals(mLocale)) {
+ personalizationDictionaryToUse = oldPersonalizationDictionary;
+ } else {
+ personalizationDictionaryToUse =
+ PersonalizationHelper.getPersonalizationDictionary(mContext, mLocale);
+ }
+ }
+ setUserHistoryDictionary(userHistoryDictionaryToUse);
+ setPersonalizationDictionary(personalizationDictionaryToUse);
+ }
+
+ /**
+ * Set the contacts dictionary according to the user settings.
+ *
+ * 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 settingsValues current settingsValues
+ */
+ private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary,
+ final SettingsValues settingsValues) {
+ final boolean shouldSetDictionary = settingsValues.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 {
+ if (null != oldContactsDictionary) {
+ if (!oldContactsDictionary.mLocale.equals(mLocale)) {
+ // 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(mContext, mLocale);
+ } 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(mContext);
+ dictionaryToUse = oldContactsDictionary;
+ }
+ } else {
+ dictionaryToUse = new ContactsBinaryDictionary(mContext, mLocale);
+ }
+ }
+ setContactsDictionary(dictionaryToUse);
+ }
+
+ public boolean isUserDictionaryEnabled() {
+ if (mUserDictionary == null) {
+ return false;
+ }
+ return mUserDictionary.mEnabled;
+ }
+
+ public void addWordToUserDictionary(String word) {
+ if (mUserDictionary == null) {
+ return;
+ }
+ mUserDictionary.addWordToUserDictionary(word);
+ }
+
+ public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
+ final String previousWord, final int timeStampInSeconds) {
+ if (mUserHistoryDictionary == null) {
+ return;
+ }
+ final int maxFreq = getMaxFrequency(suggestion);
+ if (maxFreq == 0) {
+ return;
+ }
+ final String suggestionLowerCase = suggestion.toLowerCase(mLocale);
+ final String secondWord;
+ if (wasAutoCapitalized) {
+ 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 = mMainDictionary != null ?
+ mMainDictionary.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;
+ mUserHistoryDictionary.addToDictionary(
+ previousWord, secondWord, isValid, timeStampInSeconds);
+ }
+
+ public void cancelAddingUserHistory(final String previousWord, final String committedWord) {
+ if (mUserHistoryDictionary != null) {
+ mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord);
+ }
+ }
+
+ // TODO: Revise the way to fusion suggestion results.
+ public void getSuggestions(final WordComposer composer,
+ final String prevWord, final ProximityInfo proximityInfo,
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
+ final int sessionId, final Set<SuggestedWordInfo> suggestionSet,
+ final ArrayList<SuggestedWordInfo> rawSuggestions) {
+ for (final String key : mDictionaries.keySet()) {
+ final Dictionary dictionary = mDictionaries.get(key);
+ if (null == dictionary) continue;
+ final ArrayList<SuggestedWordInfo> dictionarySuggestions =
+ dictionary.getSuggestionsWithSessionId(composer, prevWord, proximityInfo,
+ blockOffensiveWords, additionalFeaturesOptions, sessionId);
+ if (null == dictionarySuggestions) continue;
+ suggestionSet.addAll(dictionarySuggestions);
+ if (null != rawSuggestions) {
+ rawSuggestions.addAll(dictionarySuggestions);
+ }
+ }
+ }
+
+ public boolean isValidMainDictWord(final String word) {
+ if (TextUtils.isEmpty(word) || !hasMainDictionary()) {
+ return false;
+ }
+ return mMainDictionary.isValidWord(word);
+ }
+
+ public boolean isValidWord(final String word, final boolean ignoreCase) {
+ if (TextUtils.isEmpty(word)) {
+ return false;
+ }
+ final String lowerCasedWord = word.toLowerCase(mLocale);
+ for (final String key : mDictionaries.keySet()) {
+ final Dictionary dictionary = mDictionaries.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;
+ }
+
+ private int getMaxFrequency(final String word) {
+ if (TextUtils.isEmpty(word)) {
+ return Dictionary.NOT_A_PROBABILITY;
+ }
+ int maxFreq = -1;
+ for (final String key : mDictionaries.keySet()) {
+ final Dictionary dictionary = mDictionaries.get(key);
+ if (null == dictionary) continue;
+ final int tempFreq = dictionary.getFrequency(word);
+ if (tempFreq >= maxFreq) {
+ maxFreq = tempFreq;
+ }
+ }
+ return maxFreq;
+ }
+
+ private void removeDictionary(final String key) {
+ mDictionaries.remove(key);
+ }
+
+ private void addOrReplaceDictionary(final String key, final Dictionary dict) {
+ if (mDictionarySubsetForDebug != null && !mDictionarySubsetForDebug.contains(key)) {
+ Log.w(TAG, "Ignore add " + key + " dictionary for debug.");
+ return;
+ }
+ final Dictionary oldDict;
+ if (dict == null) {
+ oldDict = mDictionaries.remove(key);
+ } else {
+ oldDict = mDictionaries.put(key, dict);
+ }
+ if (oldDict != null && dict != oldDict) {
+ oldDict.close();
+ }
+ }
+
+ public void clearUserHistoryDictionary() {
+ if (mUserHistoryDictionary == null) {
+ return;
+ }
+ mUserHistoryDictionary.clearAndFlushDictionary();
+ }
+
+ // This method gets called only when the IME receives a notification to remove the
+ // personalization dictionary.
+ public void clearPersonalizationDictionary() {
+ if (!hasPersonalizationDictionary()) {
+ return;
+ }
+ mPersonalizationDictionary.clearAndFlushDictionary();
+ }
+
+ public void addMultipleDictionaryEntriesToPersonalizationDictionary(
+ final ArrayList<LanguageModelParam> languageModelParams,
+ final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) {
+ if (!hasPersonalizationDictionary()) {
+ if (callback != null) {
+ callback.onFinished();
+ }
+ return;
+ }
+ mPersonalizationDictionary.addMultipleDictionaryEntriesToDictionary(languageModelParams,
+ callback);
+ }
+
+ public void dumpDictionaryForDebug(final String dictName) {
+ final ExpandableBinaryDictionary dictToDump;
+ if (dictName.equals(Dictionary.TYPE_CONTACTS)) {
+ dictToDump = mContactsDictionary;
+ } else if (dictName.equals(Dictionary.TYPE_USER)) {
+ dictToDump = mUserDictionary;
+ } else if (dictName.equals(Dictionary.TYPE_USER_HISTORY)) {
+ dictToDump = mUserHistoryDictionary;
+ } else if (dictName.equals(Dictionary.TYPE_PERSONALIZATION)) {
+ dictToDump = mPersonalizationDictionary;
+ } else {
+ dictToDump = null;
+ }
+ 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
index 3df2a2b63..b931c66d1 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -16,15 +16,12 @@
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.ProbabilityInfo;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -37,14 +34,13 @@ 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 int BINARY_DICT_VERSION = FormatSpec.VERSION4;
private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
- new FormatSpec.FormatOptions(BINARY_DICT_VERSION, true /* supportsDynamicUpdate */);
+ new FormatSpec.FormatOptions(BINARY_DICT_VERSION, false /* hasTimestamp */);
private FusionDictionary mFusionDictionary;
- public DictionaryWriter(final Context context, final String dictType) {
- super(context, dictType);
+ public DictionaryWriter() {
clear();
}
@@ -52,7 +48,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
public void clear() {
final HashMap<String, String> attributes = CollectionUtils.newHashMap();
mFusionDictionary = new FusionDictionary(new PtNodeArray(),
- new FusionDictionary.DictionaryOptions(attributes, false, false));
+ new FusionDictionary.DictionaryOptions(attributes));
}
/**
@@ -61,22 +57,23 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
// 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) {
+ public void addUnigramWord(final String word, final String shortcutTarget,
+ final int probability, final int shortcutProbability, final boolean isNotAWord) {
if (shortcutTarget == null) {
- mFusionDictionary.add(word, frequency, null, isNotAWord);
+ mFusionDictionary.add(word, new ProbabilityInfo(probability), 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);
+ shortcutTargets.add(new WeightedString(shortcutTarget, shortcutProbability));
+ mFusionDictionary.add(word, new ProbabilityInfo(probability), shortcutTargets,
+ isNotAWord);
}
}
@Override
- public void addBigramWords(final String word0, final String word1, final int frequency,
+ public void addBigramWords(final String word0, final String word1, final int probability,
final boolean isValid, final long lastModifiedTime) {
- mFusionDictionary.setBigram(word0, word1, frequency);
+ mFusionDictionary.setBigram(word0, word1, new ProbabilityInfo(probability));
}
@Override
@@ -92,18 +89,4 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
}
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..f9ab9419b 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -17,23 +17,30 @@
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.CombinedFormatUtils;
+import com.android.inputmethod.latin.utils.FileUtils;
+import com.android.inputmethod.latin.utils.LanguageModelParam;
import com.android.inputmethod.latin.utils.PrioritizedSerialExecutor;
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;
@@ -52,34 +59,29 @@ 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 TIMEOUT_FOR_READ_OPS_FOR_TESTS_IN_MILLISECONDS = 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;
+ private static final int DICTIONARY_FORMAT_VERSION = FormatSpec.VERSION4;
/**
* 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.
+ * the dictionary name and the value is the shared dictionary time recorder associated with
+ * that dictionary name.
*/
private static final ConcurrentHashMap<String, DictionaryUpdateController>
- sFilenameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap();
+ sDictNameDictionaryUpdateControllerMap = CollectionUtils.newConcurrentHashMap();
private static final ConcurrentHashMap<String, PrioritizedSerialExecutor>
- sFilenameExecutorMap = CollectionUtils.newConcurrentHashMap();
+ sDictNameExecutorMap = CollectionUtils.newConcurrentHashMap();
/** The application context. */
protected final Context mContext;
@@ -95,18 +97,24 @@ abstract public class ExpandableBinaryDictionary extends 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. Multiple dictionary instances with the same name is supported, with access
+ * controlled by DictionaryUpdateController.
*/
- private final String mFilename;
+ private final String mDictName;
+
+ /** Dictionary locale */
+ private final Locale mLocale;
/** Whether to support dynamically updating the dictionary */
private final boolean mIsUpdatable;
+ /** Dictionary file */
+ private final File mDictFile;
+
// TODO: remove, once dynamic operations is serialized
/** Controls updating the shared binary dictionary file across multiple instances. */
- private final DictionaryUpdateController mFilenameDictionaryUpdateController;
+ private final DictionaryUpdateController mDictNameDictionaryUpdateController;
// TODO: remove, once dynamic operations is serialized
/** Controls updating the local binary dictionary for this instance. */
@@ -114,7 +122,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
new DictionaryUpdateController();
/* A extension for a binary dictionary file. */
- public static final String DICT_FILE_EXTENSION = ".dict";
+ protected static final String DICT_FILE_EXTENSION = ".dict";
private final AtomicReference<Runnable> mUnfinishedFlushingTask =
new AtomicReference<Runnable>();
@@ -132,45 +140,62 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
protected abstract boolean hasContentChanged();
+ private boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) {
+ return formatVersion == FormatSpec.VERSION4;
+ }
+
+ public boolean isValidDictionary() {
+ return mBinaryDictionary.isValidDictionary();
+ }
+
/**
- * Gets the dictionary update controller for the given filename.
+ * Gets the dictionary update controller for the given dictionary name.
*/
private static DictionaryUpdateController getDictionaryUpdateController(
- String filename) {
- DictionaryUpdateController recorder = sFilenameDictionaryUpdateControllerMap.get(filename);
+ final String dictName) {
+ DictionaryUpdateController recorder = sDictNameDictionaryUpdateControllerMap.get(dictName);
if (recorder == null) {
- synchronized(sFilenameDictionaryUpdateControllerMap) {
+ synchronized(sDictNameDictionaryUpdateControllerMap) {
recorder = new DictionaryUpdateController();
- sFilenameDictionaryUpdateControllerMap.put(filename, recorder);
+ sDictNameDictionaryUpdateControllerMap.put(dictName, recorder);
}
}
return recorder;
}
/**
- * Gets the executor for the given filename.
+ * Gets the executor for the given dictionary name.
*/
- private static PrioritizedSerialExecutor getExecutor(final String filename) {
- PrioritizedSerialExecutor executor = sFilenameExecutorMap.get(filename);
+ private static PrioritizedSerialExecutor getExecutor(final String dictName) {
+ PrioritizedSerialExecutor executor = sDictNameExecutorMap.get(dictName);
if (executor == null) {
- synchronized(sFilenameExecutorMap) {
+ synchronized(sDictNameExecutorMap) {
executor = new PrioritizedSerialExecutor();
- sFilenameExecutorMap.put(filename, executor);
+ sDictNameExecutorMap.put(dictName, executor);
}
}
return executor;
}
- 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);
+ /**
+ * Shutdowns all executors and removes all executors from the executor map for testing.
+ */
+ @UsedForTesting
+ public static void shutdownAllExecutors() {
+ synchronized(sDictNameExecutorMap) {
+ for (final PrioritizedSerialExecutor executor : sDictNameExecutorMap.values()) {
+ executor.shutdown();
+ sDictNameExecutorMap.remove(executor);
}
+ }
+ }
+
+ private static AbstractDictionaryWriter getDictionaryWriter(
+ final boolean isDynamicPersonalizationDictionary) {
+ if (isDynamicPersonalizationDictionary) {
+ return null;
} else {
- return new DictionaryWriter(context, dictType);
+ return new DictionaryWriter();
}
}
@@ -178,26 +203,39 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* 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 boolean isUpdatable,
+ final File dictFile) {
super(dictType);
- mFilename = filename;
+ mDictName = dictName;
mContext = context;
+ mLocale = locale;
mIsUpdatable = isUpdatable;
+ mDictFile = getDictFile(context, dictName, dictFile);
mBinaryDictionary = null;
- mFilenameDictionaryUpdateController = getDictionaryUpdateController(filename);
+ mDictNameDictionaryUpdateController = getDictionaryUpdateController(dictName);
// Currently, only dynamic personalization dictionary is updatable.
- mDictionaryWriter = getDictionaryWriter(context, dictType, isUpdatable);
+ mDictionaryWriter = getDictionaryWriter(isUpdatable);
}
- 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);
+ }
+
+ public static String getDictName(final String name, final Locale locale,
+ final File dictFile) {
+ return dictFile != null ? dictFile.getName() : name + "." + locale.toString();
}
/**
@@ -205,23 +243,20 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
@Override
public void close() {
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
if (mBinaryDictionary!= null) {
mBinaryDictionary.close();
mBinaryDictionary = null;
}
- if (mDictionaryWriter != null) {
- mDictionaryWriter.close();
- }
}
});
}
protected void closeBinaryDictionary() {
// Ensure that no other threads are accessing the local binary dictionary.
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
if (mBinaryDictionary != null) {
@@ -234,24 +269,34 @@ 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())));
return attributeMap;
}
+ 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;
+ }
+
protected void clear() {
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(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());
+ if (mDictionaryWriter == null) {
+ removeBinaryDictionaryLocked();
+ BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(),
+ DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap());
mBinaryDictionary = new BinaryDictionary(
- file.getAbsolutePath(), 0 /* offset */, file.length(),
- true /* useFullEditDistance */, null, mDictType, mIsUpdatable);
+ mDictFile.getAbsolutePath(), 0 /* offset */, mDictFile.length(),
+ true /* useFullEditDistance */, mLocale, mDictType, mIsUpdatable);
} else {
mDictionaryWriter.clear();
}
@@ -286,8 +331,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* 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() {
+ getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
runGCIfRequiredInternalLocked(mindsBlockByGC);
@@ -296,18 +340,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
private void runGCIfRequiredInternalLocked(final boolean mindsBlockByGC) {
- if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) return;
// Calls to needsToRunGC() need to be serialized.
if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) {
- if (setIsRegeneratingIfNotRegenerating()) {
+ if (setProcessingLargeTaskIfNot()) {
// Run GC after currently existing time sensitive operations.
- getExecutor(mFilename).executePrioritized(new Runnable() {
+ getExecutor(mDictName).executePrioritized(new Runnable() {
@Override
public void run() {
try {
mBinaryDictionary.flushWithGC();
} finally {
- mFilenameDictionaryUpdateController.mIsRegenerating.set(false);
+ mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false);
}
}
});
@@ -318,23 +361,19 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/**
* 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) {
+ protected void addWordDynamically(final String word, final int frequency,
+ final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
+ final boolean isBlacklisted, final int timestamp) {
if (!mIsUpdatable) {
- Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename);
+ Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mDictName);
return;
}
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(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);
- }
+ runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
+ mBinaryDictionary.addUnigramWord(word, frequency, shortcutTarget, shortcutFreq,
+ isNotAWord, isBlacklisted, timestamp);
}
});
}
@@ -343,23 +382,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* 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) {
+ final int frequency, final int timestamp) {
if (!mIsUpdatable) {
Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: "
- + mFilename);
+ + mDictName);
return;
}
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(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 */);
- }
+ runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
+ mBinaryDictionary.addBigramWords(word0, word1, frequency, timestamp);
}
});
}
@@ -370,18 +403,48 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
protected void removeBigramDynamically(final String word0, final String word1) {
if (!mIsUpdatable) {
Log.w(TAG, "removeBigramDynamically is called for non-updatable dictionary: "
- + mFilename);
+ + mDictName);
return;
}
- getExecutor(mFilename).execute(new Runnable() {
+ getExecutor(mDictName).execute(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);
+ runGCIfRequiredInternalLocked(true /* mindsBlockByGC */);
+ mBinaryDictionary.removeBigramWords(word0, word1);
+ }
+ });
+ }
+
+ public interface AddMultipleDictionaryEntriesCallback {
+ public void onFinished();
+ }
+
+ /**
+ * Dynamically add multiple entries to the dictionary.
+ */
+ protected void addMultipleDictionaryEntriesDynamically(
+ final ArrayList<LanguageModelParam> languageModelParams,
+ final AddMultipleDictionaryEntriesCallback callback) {
+ if (!mIsUpdatable) {
+ Log.w(TAG, "addMultipleDictionaryEntriesDynamically is called for non-updatable " +
+ "dictionary: " + mDictName);
+ return;
+ }
+ getExecutor(mDictName).execute(new Runnable() {
+ @Override
+ public void run() {
+ final boolean locked = setProcessingLargeTaskIfNot();
+ try {
+ mBinaryDictionary.addMultipleDictionaryEntries(
+ languageModelParams.toArray(
+ new LanguageModelParam[languageModelParams.size()]));
+ } finally {
+ if (callback != null) {
+ callback.onFinished();
+ }
+ if (locked) {
+ mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false);
+ }
}
}
});
@@ -393,48 +456,25 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
final int sessionId) {
reloadDictionaryIfRequired();
- if (isRegenerating()) {
+ if (processingLargeTask()) {
return null;
}
- final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final AsyncResultHolder<ArrayList<SuggestedWordInfo>> holder =
new AsyncResultHolder<ArrayList<SuggestedWordInfo>>();
- getExecutor(mFilename).executePrioritized(new Runnable() {
+ getExecutor(mDictName).executePrioritized(new Runnable() {
@Override
public void run() {
- if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
- 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);
- }
+ if (mBinaryDictionary == null) {
+ holder.set(null);
+ return;
+ }
+ final ArrayList<SuggestedWordInfo> binarySuggestion =
+ mBinaryDictionary.getSuggestionsWithSessionId(composer, prevWord,
+ proximityInfo, blockOffensiveWords, additionalFeaturesOptions,
+ sessionId);
+ holder.set(binarySuggestion);
+ if (mBinaryDictionary.isCorrupted()) {
+ removeBinaryDictionaryLocked();
}
}
});
@@ -456,11 +496,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
protected boolean isValidWordInner(final String word) {
- if (isRegenerating()) {
+ if (processingLargeTask()) {
return false;
}
final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>();
- getExecutor(mFilename).executePrioritized(new Runnable() {
+ getExecutor(mDictName).executePrioritized(new Runnable() {
@Override
public void run() {
holder.set(isValidWordLocked(word));
@@ -484,7 +524,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* dictionary exists, this method will generate one.
*/
protected void loadDictionary() {
- mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = SystemClock.uptimeMillis();
+ mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = System.currentTimeMillis();
reloadDictionaryIfRequired();
}
@@ -494,14 +534,23 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private void loadBinaryDictionary() {
if (DEBUG) {
- Log.d(TAG, "Loading binary dictionary: " + mFilename + " request="
- + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update="
- + mFilenameDictionaryUpdateController.mLastUpdateTime);
+ Log.d(TAG, "Loading binary dictionary: " + mDictName + " request="
+ + mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update="
+ + mDictNameDictionaryUpdateController.mLastUpdateTime);
+ }
+ 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();
+ final String filename = mDictFile.getAbsolutePath();
+ final long length = mDictFile.length();
// Build the new binary dictionary
final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0 /* offset */,
@@ -511,7 +560,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// swapping in the new one.
// TODO: Ensure multi-thread assignment of mBinaryDictionary.
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
- getExecutor(mFilename).executePrioritized(new Runnable() {
+ getExecutor(mDictName).executePrioritized(new Runnable() {
@Override
public void run() {
mBinaryDictionary = newBinaryDictionary;
@@ -533,29 +582,30 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private void writeBinaryDictionary() {
if (DEBUG) {
- Log.d(TAG, "Generating binary dictionary: " + mFilename + " request="
- + mFilenameDictionaryUpdateController.mLastUpdateRequestTime + " update="
- + mFilenameDictionaryUpdateController.mLastUpdateTime);
+ Log.d(TAG, "Generating binary dictionary: " + mDictName + " request="
+ + mDictNameDictionaryUpdateController.mLastUpdateRequestTime + " update="
+ + mDictNameDictionaryUpdateController.mLastUpdateTime);
}
if (needsToReloadBeforeWriting()) {
mDictionaryWriter.clear();
loadDictionaryAsync();
- mDictionaryWriter.write(mFilename, getHeaderAttributeMap());
+ mDictionaryWriter.write(mDictFile, 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();
- }
+ if (mBinaryDictionary == null || !isValidDictionary()
+ // TODO: remove the check below
+ || !matchesExpectedBinaryDictFormatVersionForThisType(
+ mBinaryDictionary.getFormatVersion())) {
+ if (mDictFile.exists() && !FileUtils.deleteRecursively(mDictFile)) {
+ Log.e(TAG, "Can't remove a file: " + mDictFile.getName());
}
+ BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(),
+ DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap());
} else {
- mDictionaryWriter.write(mFilename, getHeaderAttributeMap());
+ if (mBinaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) {
+ mBinaryDictionary.flushWithGC();
+ } else {
+ mBinaryDictionary.flush();
+ }
}
}
}
@@ -568,12 +618,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* the current binary dictionary from file.
*/
protected void setRequiresReload(final boolean requiresRebuild) {
- final long time = SystemClock.uptimeMillis();
+ final long time = System.currentTimeMillis();
mPerInstanceDictionaryUpdateController.mLastUpdateRequestTime = time;
- mFilenameDictionaryUpdateController.mLastUpdateRequestTime = time;
+ mDictNameDictionaryUpdateController.mLastUpdateRequestTime = time;
if (DEBUG) {
- Log.d(TAG, "Reload request: " + mFilename + ": request=" + time + " update="
- + mFilenameDictionaryUpdateController.mLastUpdateTime);
+ Log.d(TAG, "Reload request: " + mDictName + ": request=" + time + " update="
+ + mDictNameDictionaryUpdateController.mLastUpdateTime);
}
}
@@ -582,7 +632,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
public final void reloadDictionaryIfRequired() {
if (!isReloadRequired()) return;
- if (setIsRegeneratingIfNotRegenerating()) {
+ if (setProcessingLargeTaskIfNot()) {
reloadDictionary();
}
}
@@ -594,13 +644,14 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return mBinaryDictionary == null || mPerInstanceDictionaryUpdateController.isOutOfDate();
}
- private boolean isRegenerating() {
- return mFilenameDictionaryUpdateController.mIsRegenerating.get();
+ private boolean processingLargeTask() {
+ return mDictNameDictionaryUpdateController.mProcessingLargeTask.get();
}
- // Returns whether the dictionary can be regenerated.
- private boolean setIsRegeneratingIfNotRegenerating() {
- return mFilenameDictionaryUpdateController.mIsRegenerating.compareAndSet(
+ // Returns whether the dictionary is being used for a large task. If true, we should not use
+ // this dictionary for latency sensitive operations.
+ private boolean setProcessingLargeTaskIfNot() {
+ return mDictNameDictionaryUpdateController.mProcessingLargeTask.compareAndSet(
false /* expect */ , true /* update */);
}
@@ -611,13 +662,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
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() {
+ getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
try {
- final long time = SystemClock.uptimeMillis();
+ final long time = System.currentTimeMillis();
final boolean dictionaryFileExists = dictionaryFileExists();
- if (mFilenameDictionaryUpdateController.isOutOfDate()
+ if (mDictNameDictionaryUpdateController.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.
@@ -626,31 +677,44 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// 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;
+ mDictNameDictionaryUpdateController.mLastUpdateTime = time;
writeBinaryDictionary();
loadBinaryDictionary();
} else {
// If not, the reload request was unnecessary so revert
// LastUpdateRequestTime to LastUpdateTime.
- mFilenameDictionaryUpdateController.mLastUpdateRequestTime =
- mFilenameDictionaryUpdateController.mLastUpdateTime;
+ mDictNameDictionaryUpdateController.mLastUpdateRequestTime =
+ mDictNameDictionaryUpdateController.mLastUpdateTime;
}
} else if (mBinaryDictionary == null ||
mPerInstanceDictionaryUpdateController.mLastUpdateTime
- < mFilenameDictionaryUpdateController.mLastUpdateTime) {
+ < mDictNameDictionaryUpdateController.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();
- }
- mPerInstanceDictionaryUpdateController.mLastUpdateTime = time;
+ // If we just loaded the binary dictionary, then mBinaryDictionary is not
+ // up-to-date yet so it's useless to test it right away. Schedule the check
+ // for right after it's loaded instead.
+ getExecutor(mDictName).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ if (mBinaryDictionary != null && !(isValidDictionary()
+ // 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.
+ mDictNameDictionaryUpdateController.mLastUpdateTime = time;
+ writeBinaryDictionary();
+ loadBinaryDictionary();
+ }
+ mPerInstanceDictionaryUpdateController.mLastUpdateTime = time;
+ }
+ });
} finally {
- mFilenameDictionaryUpdateController.mIsRegenerating.set(false);
+ mDictNameDictionaryUpdateController.mProcessingLargeTask.set(false);
}
}
});
@@ -658,28 +722,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// 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.
- */
- protected void asyncLoadDictionaryToMemory() {
- getExecutor(mFilename).executePrioritized(new Runnable() {
- @Override
- public void run() {
- if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
- loadDictionaryAsync();
- }
- }
- });
+ return mDictFile.exists();
}
/**
* Generate binary dictionary using DictionaryWriter.
*/
- protected void asyncFlashAllBinaryDictionary() {
+ protected void asyncFlushBinaryDictionary() {
final Runnable newTask = new Runnable() {
@Override
public void run() {
@@ -687,50 +736,81 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
};
final Runnable oldTask = mUnfinishedFlushingTask.getAndSet(newTask);
- getExecutor(mFilename).replaceAndExecute(oldTask, newTask);
+ getExecutor(mDictName).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.
+ * For tracking whether the dictionary is out of date and the dictionary is used in a large
+ * task. 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 volatile AtomicBoolean mProcessingLargeTask = new AtomicBoolean();
public boolean isOutOfDate() {
return (mLastUpdateRequestTime > mLastUpdateTime);
}
}
- // TODO: Implement native binary methods once the dynamic dictionary implementation is done.
+ // TODO: Implement BinaryDictionary.isInDictionary().
@UsedForTesting
- public boolean isInDictionaryForTests(final String word) {
+ public boolean isInUnderlyingBinaryDictionaryForTests(final String word) {
final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>();
- getExecutor(mFilename).executePrioritized(new Runnable() {
+ 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));
- }
+ holder.set(mBinaryDictionary.isValidWord(word));
}
}
});
- return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
+ return holder.get(false, TIMEOUT_FOR_READ_OPS_FOR_TESTS_IN_MILLISECONDS);
}
@UsedForTesting
- public void shutdownExecutorForTests() {
- getExecutor(mFilename).shutdown();
+ public void waitAllTasksForTests() {
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ getExecutor(mDictName).execute(new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ });
+ 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();
+ getExecutor(mDictName).execute(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..9870faa98
--- /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 android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnShowListener;
+
+import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
+
+/**
+ * The dialog box that shows the important notice contents.
+ */
+public final class ImportantNoticeDialog extends AlertDialog implements OnShowListener,
+ OnClickListener, OnDismissListener {
+ public interface ImportantNoticeDialogListener {
+ public void onClickSettingsOfImportantNoticeDialog(final int nextVersion);
+ public void onDismissImportantNoticeDialog(final int nextVersion);
+ }
+
+ private final ImportantNoticeDialogListener mListener;
+ private final int mNextImportantNoticeVersion;
+
+ public ImportantNoticeDialog(
+ final Context context, final ImportantNoticeDialogListener listener) {
+ super(context, THEME_HOLO_DARK);
+ 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);
+ }
+ // Set listeners.
+ setOnShowListener(this);
+ setOnDismissListener(this);
+ }
+
+ private boolean shouldHaveSettingsButton() {
+ return mNextImportantNoticeVersion
+ == ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS;
+ }
+
+ @Override
+ public void onShow(final DialogInterface dialog) {
+ ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
+ }
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) {
+ mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion);
+ }
+ }
+
+ @Override
+ public void onDismiss(final DialogInterface dialog) {
+ mListener.onDismissImportantNoticeDialog(mNextImportantNoticeVersion);
+ }
+}
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..8546cebd5 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -42,7 +42,7 @@ public final class LastComposedWord {
public final int[] mPrimaryKeyCodes;
public final String mTypedWord;
- public final String mCommittedWord;
+ public final CharSequence mCommittedWord;
public final String mSeparatorString;
public final String mPrevWord;
public final int mCapitalizedMode;
@@ -58,7 +58,7 @@ public final class LastComposedWord {
// 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,
+ final String typedWord, final CharSequence committedWord, final String separatorString,
final String prevWord, final int capitalizedMode) {
mPrimaryKeyCodes = primaryKeyCodes;
if (inputPointers != null) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 77d07019f..44282a492 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,29 @@ 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.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.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
@@ -77,157 +67,85 @@ 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.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.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 */);
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();
+
+ // TODO[IL]: remove this member completely.
+ public CompletionInfo[] mApplicationSpecifiedCompletions;
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;
@@ -236,59 +154,56 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_REOPEN_DICTIONARIES = 5;
private static final int MSG_ON_END_BATCH_INPUT = 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);
+ final Resources res = getOwnerInstance().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);
}
@Override
public void handleMessage(final Message msg) {
- final LatinIME latinIme = getOuterInstance();
+ final LatinIME latinIme = getOwnerInstance();
final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
switch (msg.what) {
case MSG_UPDATE_SUGGESTION_STRIP:
- latinIme.updateSuggestionStrip();
+ latinIme.mInputLogic.performUpdateSuggestionStripSync(
+ latinIme.mSettings.getCurrent(), this /* handler */);
break;
case MSG_UPDATE_SHIFT_STATE:
switcher.updateShiftState();
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();
@@ -298,11 +213,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
postUpdateSuggestionStrip();
break;
case MSG_ON_END_BATCH_INPUT:
- latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj);
+ latinIme.mInputLogic.endBatchInputInternal(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);
+ }
break;
}
}
@@ -316,6 +239,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
public void postResumeSuggestions() {
+ if (!getOwnerInstance().mSettings.getCurrent().isSuggestionStripVisible()) {
+ return;
+ }
removeMessages(MSG_RESUME_SUGGESTIONS);
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
}
@@ -347,6 +273,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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,
final boolean dismissGestureFloatingPreviewText) {
removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
@@ -354,22 +287,13 @@ 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) {
@@ -401,7 +325,7 @@ 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.isInputViewShown()) {
latinIme.mKeyboardSwitcher.saveKeyboardState();
}
@@ -415,12 +339,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,7 +361,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mIsOrientationChanging = false;
mPendingSuccessiveImsCallback = true;
}
- final LatinIME latinIme = getOuterInstance();
+ final LatinIME latinIme = getOwnerInstance();
executePendingImsCallback(latinIme, editorInfo, restarting);
latinIme.onStartInputInternal(editorInfo, restarting);
}
@@ -453,7 +380,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK),
PENDING_IMS_CALLBACK_DURATION);
}
- final LatinIME latinIme = getOuterInstance();
+ final LatinIME latinIme = getOwnerInstance();
executePendingImsCallback(latinIme, editorInfo, restarting);
latinIme.onStartInputViewInternal(editorInfo, restarting);
mAppliedEditorInfo = editorInfo;
@@ -465,7 +392,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Typically this is the first onFinishInputView after orientation changed.
mHasPendingFinishInputView = true;
} else {
- final LatinIME latinIme = getOuterInstance();
+ final LatinIME latinIme = getOwnerInstance();
latinIme.onFinishInputViewInternal(finishingInput);
mAppliedEditorInfo = null;
}
@@ -476,7 +403,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Typically this is the first onFinishInput after orientation changed.
mHasPendingFinishInput = true;
} else {
- final LatinIME latinIme = getOuterInstance();
+ final LatinIME latinIme = getOwnerInstance();
executePendingImsCallback(latinIme, null, false);
latinIme.onFinishInputInternal();
}
@@ -536,7 +463,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardSwitcher.init(this);
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
- PersonalizationDictionarySessionRegister.init(this);
super.onCreate();
@@ -548,9 +474,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
initSuggest();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.getInstance().init(this, mKeyboardSwitcher, mSuggest);
+ ResearchLogger.getInstance().init(this, mKeyboardSwitcher);
}
- mDisplayOrientation = getResources().getConfiguration().orientation;
// Register to receive ringer mode change and network state change.
// Also receive installation and removal of a dictionary pack.
@@ -569,18 +494,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
- DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(this);
+ final IntentFilter dictDumpFilter = new IntentFilter();
+ dictDumpFilter.addAction(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
+ registerReceiver(mDictionaryDumpBroadcastReceiver, dictDumpFilter);
- mInputUpdater = new InputUpdater(this);
+ DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(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);
+ final EditorInfo editorInfo = getCurrentInputEditorInfo();
+ final InputAttributes inputAttributes = new InputAttributes(editorInfo, isFullscreenMode());
+ mSettings.loadSettings(this, 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
@@ -589,16 +516,56 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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.
- if (!mHandler.hasPendingReopenDictionaries()) {
- // May need to reset the contacts dictionary depending on the user settings.
- resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+ final SettingsValues currentSettingsValues = mSettings.getCurrent();
+ final Suggest suggest = mInputLogic.mSuggest;
+ if (!mHandler.hasPendingReopenDictionaries() && suggest != null) {
+ // May need to reset dictionaries depending on the user settings.
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+ suggest.mDictionaryFacilitator;
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ new DictionaryFacilitatorForSuggest(currentSettingsValues,
+ oldDictionaryFacilitator);
+ // Create Suggest instance with the new dictionary facilitator.
+ resetSuggest(new Suggest(suggest /* oldSuggest */, dictionaryFacilitator));
+ } else if (suggest == null) {
+ initSuggestForLocale(locale);
+ }
+ }
+
+ private void refreshPersonalizationDictionarySession() {
+ final Suggest suggest = mInputLogic.mSuggest;
+ 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);
+ if (suggest != null) {
+ suggest.mDictionaryFacilitator.clearUserHistoryDictionary();
+ }
+ }
+ if (!shouldKeepPersonalizationDictionaries) {
+ // Remove personalization dictionaries.
+ PersonalizationHelper.removeAllPersonalizationDictionaries(this);
+ PersonalizationDictionarySessionRegistrar.resetAll(this);
+ } else {
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ (suggest == null) ? null : suggest.mDictionaryFacilitator;
+ PersonalizationDictionarySessionRegistrar.init(this, dictionaryFacilitator);
}
}
// 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);
@@ -609,7 +576,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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,101 +585,51 @@ 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;
}
+ initSuggestForLocale(subtypeLocale);
+ }
- final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale,
- this /* SuggestInitializationListener */);
+ private void initSuggestForLocale(final Locale locale) {
final SettingsValues settingsValues = mSettings.getCurrent();
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+ (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator;
+ // Creates new dictionary facilitator for the new locale.
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ new DictionaryFacilitatorForSuggest(this /* context */, locale, settingsValues,
+ this /* DictionaryInitializationListener */, oldDictionaryFacilitator);
+ final Suggest newSuggest = new Suggest(locale, dictionaryFacilitator);
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();
+ resetSuggest(newSuggest);
}
- /**
- * Resets the contacts dictionary in mSuggest according to the user settings.
- *
- * 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
- */
- 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);
- }
+ /* package private */ void resetSuggestMainDict() {
+ final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+ mInputLogic.mSuggest.mDictionaryFacilitator;
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ new DictionaryFacilitatorForSuggest(this /* listener */, oldDictionaryFacilitator);
+ resetSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator));
}
- /* package private */ void resetSuggestMainDict() {
- final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
- mSuggest.resetMainDict(this, subtypeLocale, this /* SuggestInitializationListener */);
- mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
+ private void resetSuggest(final Suggest newSuggest) {
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator);
+ }
+ final Suggest oldSuggest = mInputLogic.mSuggest;
+ mInputLogic.mSuggest = newSuggest;
+ if (oldSuggest != null) oldSuggest.close();
+ refreshPersonalizationDictionarySession();
}
@Override
public void onDestroy() {
- final Suggest suggest = mSuggest;
+ final Suggest suggest = mInputLogic.mSuggest;
if (suggest != null) {
suggest.close();
- mSuggest = null;
+ mInputLogic.mSuggest = null;
}
mSettings.onDestroy();
unregisterReceiver(mReceiver);
@@ -721,30 +637,29 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
ResearchLogger.getInstance().onDestroy();
}
unregisterReceiver(mDictionaryPackInstallReceiver);
- PersonalizationDictionarySessionRegister.onDestroy(this);
+ unregisterReceiver(mDictionaryDumpBroadcastReceiver);
+ PersonalizationDictionarySessionRegistrar.close(this);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
- if (mInputUpdater != null) {
- mInputUpdater.quitLooper();
- }
super.onDestroy();
}
@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();
+ mInputLogic.mConnection.beginBatchEdit();
+ mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR);
+ mInputLogic.mConnection.finishComposingText();
+ mInputLogic.mConnection.endBatchEdit();
if (isShowingOptionDialog()) {
mOptionsDialog.dismiss();
}
}
- PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf);
+ PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf,
+ mInputLogic.mSuggest.mDictionaryFacilitator);
super.onConfigurationChanged(conf);
}
@@ -760,8 +675,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 +750,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) {
@@ -882,46 +790,45 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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;
+ Suggest suggest = mInputLogic.mSuggest;
if (null != suggest && null != currentLocale && !currentLocale.equals(suggest.mLocale)) {
initSuggest();
+ suggest = mInputLogic.mSuggest;
}
- 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 {
+ // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
+ // effort to work around this bug.
+ mInputLogic.mConnection.tryFixLyingCursorPosition();
if (isDifferentTextField) {
mHandler.postResumeSuggestions();
}
canReachInputConnection = true;
}
+ if (isDifferentTextField ||
+ !currentSettingsValues.hasSameOrientation(getResources().getConfiguration())) {
+ loadSettings();
+ suggest = mInputLogic.mSuggest;
+ }
if (isDifferentTextField) {
mainKeyboardView.closing();
- loadSettings();
currentSettingsValues = mSettings.getCurrent();
if (suggest != null && currentSettingsValues.mCorrectionEnabled) {
@@ -944,19 +851,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Space state must be updated before calling updateShiftState
switcher.updateShiftState();
}
- 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.
+ setNeutralSuggestionStripInternal(false /* needsInputViewShown */);
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
- mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable);
+ mainKeyboardView.setMainDictionaryAvailability(null != suggest
+ ? suggest.mDictionaryFacilitator.hasMainDictionary() : false);
mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
currentSettingsValues.mKeyPreviewPopupDismissDelay);
mainKeyboardView.setSlidingKeyInputPreviewEnabled(
@@ -966,76 +869,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 +898,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,101 +912,27 @@ 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();
+ if (isInputViewShown() &&
+ mInputLogic.onUpdateSelection(mSettings.getCurrent(), oldSelStart, oldSelEnd,
+ newSelStart, newSelEnd, composingSpanStart, composingSpanEnd)) {
mKeyboardSwitcher.updateShiftState();
}
- mExpectingUpdateSelection = false;
- // Make a note of the cursor position
- mLastSelectionStart = newSelStart;
- mLastSelectionEnd = newSelEnd;
mSubtypeState.currentSubtypeUsed();
}
@@ -1186,7 +946,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 +964,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);
}
@@ -1234,9 +998,11 @@ 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);
}
@@ -1248,42 +1014,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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 */,
+ true /* needsInputViewShown */);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
}
}
- private void setSuggestionStripShownInternal(final boolean shown,
+ private void setSuggestionStripShownInternal(final boolean isSuggestionStripVisible,
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);
- }
+ if (!onEvaluateInputViewShown() || !hasSuggestionStripView()) {
+ return;
+ }
+ final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes();
+ final boolean shouldShowSuggestions = isSuggestionStripVisible
+ && (needsInputViewShown ? inputViewShown : true);
+ if (shouldShowSuggestions) {
+ mSuggestionStripView.setVisibility(View.VISIBLE);
+ } else {
+ mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE);
}
- }
-
- private void setSuggestionStripShown(final boolean shown) {
- setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
}
private int getAdjustedBackingViewHeight() {
@@ -1317,7 +1072,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 +1108,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 +1132,36 @@ 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 void resetComposingState(final boolean alsoResetLastComposedWord) {
- mWordComposer.reset();
- if (alsoResetLastComposedWord)
- mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
- }
-
- 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.
+ // TODO[IL]: Remove this, pass the input logic to the keyboard switcher instead?
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);
+ return mInputLogic.getCurrentAutoCapsState(mSettings.getCurrent());
}
+ // Called from the KeyboardSwitcher which needs to know recaps state to display
+ // the right layout.
+ // TODO[IL]: Remove this, pass the input logic to the keyboard switcher instead?
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();
- }
+ return mInputLogic.getCurrentRecapitalizeState();
}
- 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;
- }
- return false;
+ public Locale getCurrentSubtypeLocale() {
+ return mSubtypeSwitcher.getCurrentSubtypeLocale();
}
- 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;
+ /**
+ * @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);
+ }
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1521,16 +1173,37 @@ 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(wordToEdit);
+ }
+
+ // 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();
}
- private void onSettingsKeyPressed() {
- if (isShowingOptionDialog()) return;
+ // Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
+ @Override
+ public void onDismissImportantNoticeDialog(final int nextVersion) {
+ setNeutralSuggestionStrip();
+ }
+
+ public void displaySettingsDialog() {
+ if (isShowingOptionDialog()) {
+ return;
+ }
showSubtypeSelectorAndSettings();
}
@@ -1552,12 +1225,8 @@ 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) {
mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
@@ -1566,394 +1235,68 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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 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;
- }
- 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);
} 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);
+ codeToSend = codePoint;
+ }
+ if (Constants.CODE_SHORTCUT == codePoint) {
+ mSubtypeSwitcher.switchToShortcutIME(this);
+ // Still call the *#onCodeInput methods for readability.
}
- mExpectingUpdateSelection = true;
- return didAutoCorrect;
+ mInputLogic.onCodeInput(codeToSend, keyX, keyY, mSettings.getCurrent(), mHandler,
+ mKeyboardSwitcher);
+ mKeyboardSwitcher.onCodeInput(codePoint);
}
// 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;
+ mInputLogic.onTextInput(mSettings.getCurrent(), rawText, mHandler);
mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT);
- mEnteredText = text;
}
@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(mSettings.getCurrent(), 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,102 +1307,6 @@ 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() {
@@ -2074,475 +1321,79 @@ 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();
+ // TODO[IL]: Define a clear interface for this
+ public 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();
- }
- }
- 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 (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 (currentSettings.mIsInternal) {
- LatinImeLoggerUtils.onSeparator((char)primaryCode, x, y);
- }
-
- 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 (mSuggestionStripView.isShowingAddToDictionaryHint()) {
+ return true;
}
- }
-
- // 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;
- }
-
- private boolean isSuggestionsStripVisible() {
final SettingsValues currentSettings = mSettings.getCurrent();
- if (mSuggestionStripView == null)
+ if (null == currentSettings) {
return false;
- if (mSuggestionStripView.isShowingAddToDictionaryHint())
+ }
+ if (ImportantNoticeUtils.shouldShowImportantNotice(this,
+ currentSettings.mInputAttributes)) {
return true;
- if (null == currentSettings)
- return false;
- if (!currentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
+ }
+ if (!currentSettings.isSuggestionStripVisible()) {
return false;
- if (currentSettings.isApplicationSpecifiedCompletionsOn())
+ }
+ if (currentSettings.isApplicationSpecifiedCompletionsOn()) {
return true;
- return currentSettings.isSuggestionsRequested(mDisplayOrientation);
+ }
+ return currentSettings.isSuggestionsRequested();
}
- private void clearSuggestionStrip() {
- setSuggestedWords(SuggestedWords.EMPTY, false);
- setAutoCorrectionIndicator(false);
+ @Override
+ public boolean hasSuggestionStripView() {
+ return null != mSuggestionStripView;
}
- private void setSuggestedWords(final SuggestedWords words, final boolean isAutoCorrection) {
- mSuggestedWords = words;
- if (mSuggestionStripView != null) {
- mSuggestionStripView.setSuggestions(words);
- mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection);
- }
+ @Override
+ public boolean isShowingAddToDictionaryHint() {
+ return hasSuggestionStripView() && mSuggestionStripView.isShowingAddToDictionaryHint();
}
- 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);
+ @Override
+ public void dismissAddToDictionaryHint() {
+ if (!hasSuggestionStripView()) {
+ return;
}
+ mSuggestionStripView.dismissAddToDictionaryHint();
}
- 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!");
- }
+ // TODO[IL]: Define a clear interface for this
+ public void setSuggestedWords(final SuggestedWords suggestedWords,
+ final boolean isSuggestionStripVisible, final boolean needsInputViewShown) {
+ mInputLogic.setSuggestedWords(suggestedWords);
+ if (!hasSuggestionStripView()) {
return;
}
-
- if (!mWordComposer.isComposingWord() && !currentSettings.mBigramPredictionEnabled) {
- setPunctuationSuggestions();
- return;
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ final boolean showSuggestions;
+ if (SuggestedWords.EMPTY == suggestedWords
+ || suggestedWords.isPunctuationSuggestions()
+ || !currentSettings.isSuggestionsRequested()) {
+ showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle(
+ currentSettings.mInputAttributes);
+ } else {
+ showSuggestions = true;
}
-
- 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);
+ if (showSuggestions) {
+ mSuggestionStripView.setSuggestions(suggestedWords,
+ SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype()));
}
+ mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect);
+ setSuggestionStripShownInternal(isSuggestionStripVisible, needsInputViewShown);
}
- 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;
+ final Suggest suggest = mInputLogic.mSuggest;
if (keyboard == null || suggest == null) {
callback.onGetSuggestedWords(SuggestedWords.EMPTY);
return;
@@ -2552,528 +1403,113 @@ 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));
- }
- });
+ 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);
+ }
+ }
+ }
+ suggest.getSuggestedWords(mInputLogic.mWordComposer,
+ mInputLogic.mWordComposer.getPreviousWordForSuggestion(),
+ keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive,
+ currentSettings.mCorrectionEnabled, additionalFeaturesOptions, sessionId,
+ sequenceNumber, callback);
}
- private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
- final SuggestedWords suggestedWords) {
+ // TODO[IL]: Move this to InputLogic
+ public SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
+ final SuggestedWords suggestedWords, final SuggestedWords previousSuggestedWords) {
// 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.
+ // replaced with the new one. However, 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()) {
+ || !hasSuggestionStripView() || 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;
+ final SuggestedWords punctuationList =
+ mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList;
+ final SuggestedWords oldSuggestedWords = previousSuggestedWords == punctuationList
+ ? 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 */);
}
- final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions =
- SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord,
- previousSuggestedWords);
- return new SuggestedWords(typedWordAndPreviousSuggestions,
- false /* typedWordValid */,
- false /* hasAutoCorrectionCandidate */,
- false /* isPunctuationSuggestions */,
- true /* isObsoleteSuggestions */,
- false /* isPrediction */);
}
- 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;
- }
- 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();
+ autoCorrection = sourceSuggestedWords.mTypedWord;
}
- 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(), true /* needsInputViewShown */);
}
+ // 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);
- }
+ mInputLogic.onPickSuggestionManually(mSettings.getCurrent(), index, suggestionInfo,
+ mHandler, mKeyboardSwitcher);
}
- 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 */);
- }
+ @Override
+ public void showAddToDictionaryHint(final String word) {
+ if (!hasSuggestionStripView()) {
+ return;
}
+ mSuggestionStripView.showAddToDictionaryHint(word);
}
- 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);
- }
- // 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();
+ // TODO[IL]: Define a clean interface for this
+ // This will show either an empty suggestion strip (if prediction is enabled) or
+ // punctuation suggestions (if it's disabled).
+ @Override
+ public void setNeutralSuggestionStrip() {
+ setNeutralSuggestionStripInternal(true /* needsInputViewShown */);
}
- // This essentially inserts a space, and that's it.
- public void promotePhantomSpace() {
+ private void setNeutralSuggestionStripInternal(final boolean needsInputViewShown) {
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(), needsInputViewShown);
}
// TODO: Make this private
@@ -3095,12 +1531,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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;
}
@@ -3154,9 +1590,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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)) {
+ if (mInputLogic.mEventInterpreter.onHardwareKeyEvent(event)) {
final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode();
- mCurrentlyPressedHardwareKeys.add(keyIdentifier);
+ mInputLogic.mCurrentlyPressedHardwareKeys.add(keyIdentifier);
return true;
}
return super.onKeyDown(keyCode, event);
@@ -3165,7 +1601,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@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);
@@ -3190,17 +1626,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 +1649,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 +1660,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,20 +1670,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
};
- final AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setItems(items, listener)
- .setTitle(title);
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(this).setItems(items, listener).setTitle(title);
showOptionDialog(builder.create());
}
- 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);
+ dialog.setCancelable(true /* cancelable */);
+ dialog.setCanceledOnTouchOutside(true /* cancelable */);
final Window window = dialog.getWindow();
final WindowManager.LayoutParams lp = window.getAttributes();
@@ -3264,31 +1698,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 DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+ mInputLogic.mSuggest.mDictionaryFacilitator;
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+ new DictionaryFacilitatorForSuggest(this, locale, mSettings.getCurrent(),
+ this /* listener */, oldDictionaryFacilitator);
+ resetSuggest(new Suggest(locale, dictionaryFacilitator));
}
- // 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) {
+ if (mInputLogic.mSuggest == null) {
+ initSuggest();
+ }
+ 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 +1750,13 @@ 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
}
}
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/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 673d1b4c2..30b20a335 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.
+ mExpectedSelStart = 0;
+ mExpectedSelEnd -= mExpectedSelStart;
}
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,31 @@ 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 if the input connection is no longer valid either when
+ * setting the selection or when retrieving the text cache at that point.
+ */
+ public boolean setSelection(final int start, final int end) {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
+ 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 +521,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 +534,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 +543,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 +557,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 +581,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 +593,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 +641,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 +662,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 +670,40 @@ 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) {
+ public boolean isCursorTouchingWord(final SpacingAndPunctuations spacingAndPunctuations) {
final int codePointBeforeCursor = getCodePointBeforeCursor();
- if (Constants.NOT_A_CODE != codePointBeforeCursor
- && !settingsValues.isWordSeparator(codePointBeforeCursor)
- && !settingsValues.isWordConnector(codePointBeforeCursor)) {
- return true;
+ if (Constants.NOT_A_CODE == codePointBeforeCursor
+ || spacingAndPunctuations.isWordSeparator(codePointBeforeCursor)
+ || spacingAndPunctuations.isWordConnector(codePointBeforeCursor)) {
+ return isCursorFollowedByWordCharacter(spacingAndPunctuations);
}
+ return true;
+ }
+
+ 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;
}
- return false;
+ final int codePointAfterCursor = Character.codePointAt(after, 0);
+ if (spacingAndPunctuations.isWordSeparator(codePointAfterCursor)
+ || spacingAndPunctuations.isWordConnector(codePointAfterCursor)) {
+ return false;
+ }
+ return true;
}
public void removeTrailingSpace() {
@@ -655,45 +719,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 +783,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 +819,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/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index cd9c89f04..935dd9667 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -32,12 +32,16 @@ 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.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;
@@ -56,23 +60,34 @@ public final class SubtypeSwitcher {
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 */);
+ 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);
static final class NeedsToDisplayLanguage {
private int mEnabledSubtypeCount;
@@ -213,6 +228,7 @@ public final class SubtypeSwitcher {
}
public boolean isShortcutImeEnabled() {
+ updateShortcutIME();
if (mShortcutInputMethodInfo == null) {
return false;
}
@@ -224,10 +240,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;
}
@@ -256,18 +275,49 @@ public final class SubtypeSwitcher {
return mNeedsToDisplayLanguage.getValue();
}
- private static Locale sForcedLocaleForTesting = null;
+ 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);
+ }
+ for (final InputMethodSubtype subtype : enabledSubtypesOfEnabledImes) {
+ if (!subtype.isAuxiliary() && !subtype.getLocale().isEmpty()
+ && !systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ 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 +329,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 +343,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..abf831a28 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -16,18 +16,11 @@
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.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.CollectionUtils;
@@ -35,9 +28,7 @@ import com.android.inputmethod.latin.utils.StringUtils;
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,150 +51,26 @@ 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;
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);
+ public Suggest(final Locale locale,
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
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 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);
+ mDictionaryFacilitator = dictionaryFacilitator;
}
- /**
- * 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);
+ // Creates instance with new dictionary facilitator.
+ public Suggest(final Suggest oldSuggst,
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
+ mLocale = oldSuggst.mLocale;
+ mAutoCorrectionThreshold = oldSuggst.mAutoCorrectionThreshold;
+ mDictionaryFacilitator = dictionaryFacilitator;
}
public void setAutoCorrectionThreshold(float threshold) {
@@ -240,7 +107,7 @@ public final class Suggest {
final OnGetSuggestedWordsCallback callback) {
final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
- MAX_SUGGESTIONS);
+ SuggestedWords.MAX_SUGGESTIONS);
final String typedWord = wordComposer.getTypedWord();
final String consideredWord = trailingSingleQuotesCount > 0
@@ -257,29 +124,40 @@ public final class Suggest {
} else {
wordComposerForLookup = wordComposer;
}
-
- for (final String key : mDictionaries.keySet()) {
- final Dictionary dictionary = mDictionaries.get(key);
- suggestionsSet.addAll(dictionary.getSuggestions(wordComposerForLookup,
- prevWordForBigram, proximityInfo, blockOffensiveWords,
- additionalFeaturesOptions));
+ final ArrayList<SuggestedWordInfo> rawSuggestions;
+ if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) {
+ rawSuggestions = CollectionUtils.newArrayList();
+ } else {
+ rawSuggestions = null;
}
-
+ mDictionaryFacilitator.getSuggestions(wordComposerForLookup, prevWordForBigram,
+ proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING,
+ suggestionsSet, rawSuggestions);
+ final String firstSuggestion;
final String whitelistedWord;
if (suggestionsSet.isEmpty()) {
- whitelistedWord = null;
- } else if (SuggestedWordInfo.KIND_WHITELIST != suggestionsSet.first().mKind) {
- whitelistedWord = null;
+ whitelistedWord = firstSuggestion = null;
} else {
- whitelistedWord = suggestionsSet.first().mWord;
+ final SuggestedWordInfo firstSuggestedWordInfo = suggestionsSet.first();
+ 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).
+ // 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()));
+ || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord(
+ consideredWord, wordComposer.isFirstCharCapitalized())
+ && !consideredWord.equals(firstSuggestion));
final boolean hasAutoCorrection;
// TODO: using isCorrectionEnabled here is not very good. It's probably useless, because
@@ -289,7 +167,8 @@ public final class Suggest {
// the word *would* have been auto-corrected.
if (!isCorrectionEnabled || !allowsToBeAutoCorrected || !wordComposer.isComposingWord()
|| suggestionsSet.isEmpty() || wordComposer.hasDigits()
- || wordComposer.isMostlyCaps() || wordComposer.isResumed() || !hasMainDictionary()
+ || wordComposer.isMostlyCaps() || wordComposer.isResumed()
+ || !mDictionaryFacilitator.hasMainDictionary()
|| SuggestedWordInfo.KIND_SHORTCUT == suggestionsSet.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
@@ -342,13 +221,12 @@ 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 */,
hasAutoCorrection, /* willAutoCorrect */
- false /* isPunctuationSuggestions */,
false /* isObsoleteSuggestions */,
!wordComposer.isComposingWord() /* isPrediction */, sequenceNumber));
}
@@ -361,16 +239,16 @@ public final class Suggest {
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));
+ SuggestedWords.MAX_SUGGESTIONS);
+ final ArrayList<SuggestedWordInfo> rawSuggestions;
+ if (ProductionFlag.INCLUDE_RAW_SUGGESTIONS) {
+ rawSuggestions = CollectionUtils.newArrayList();
+ } else {
+ rawSuggestions = null;
}
-
+ mDictionaryFacilitator.getSuggestions(wordComposer, prevWordForBigram, proximityInfo,
+ blockOffensiveWords, additionalFeaturesOptions, sessionId, suggestionsSet,
+ rawSuggestions);
for (SuggestedWordInfo wordInfo : suggestionsSet) {
LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict.mDictType);
}
@@ -407,10 +285,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));
}
@@ -432,7 +309,8 @@ public final class Suggest {
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);
}
@@ -483,11 +361,6 @@ public final class Suggest {
}
public void close() {
- final HashSet<Dictionary> dictionaries = CollectionUtils.newHashSet();
- dictionaries.addAll(mDictionaries.values());
- for (final Dictionary dictionary : dictionaries) {
- dictionary.close();
- }
- mMainDictionary = null;
+ mDictionaryFacilitator.close();
}
}
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 97c89dd4e..46df3e88c 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() ? 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());
}
@@ -150,7 +195,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);
@@ -278,17 +323,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 +355,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/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
index 3213c92c7..9c095e4b1 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
@@ -25,34 +25,26 @@ import java.util.ArrayList;
import java.util.Locale;
public final class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryDictionary {
- private boolean mClosed;
+ private final Object mLock = new Object();
public SynchronouslyLoadedContactsBinaryDictionary(final Context context, final Locale locale) {
super(context, locale);
}
@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);
+ synchronized (mLock) {
+ return super.getSuggestions(codes, prevWordForBigrams, proximityInfo,
+ blockOffensiveWords, additionalFeaturesOptions);
+ }
}
@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/SynchronouslyLoadedUserBinaryDictionary.java
index 6405b5e46..801fb5b89 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
@@ -22,30 +22,34 @@ import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.util.ArrayList;
+import java.util.Locale;
public final class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionary {
+ 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 */);
}
@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);
+ synchronized (mLock) {
+ return super.getSuggestions(codes, prevWordForBigrams, proximityInfo,
+ blockOffensiveWords, additionalFeaturesOptions);
+ }
}
@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/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 15b3d8d02..3e3cbf063 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;
@@ -33,6 +32,7 @@ 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;
@@ -74,25 +74,29 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
private ContentObserver mObserver;
final private String mLocale;
final private boolean mAlsoUseMoreRestrictiveLocales;
+ final public boolean mEnabled;
- 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) {
+ super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_USER,
+ false /* isUpdatable */, 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) {
@@ -112,7 +116,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
-
+ mEnabled = readIsEnabled();
loadDictionary();
}
@@ -190,7 +194,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
}
}
- public boolean isEnabled() {
+ private boolean readIsEnabled() {
final ContentResolver cr = mContext.getContentResolver();
final ContentProviderClient client = cr.acquireContentProviderClient(Words.CONTENT_URI);
if (client != null) {
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 039dadc66..125976932 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,8 +16,7 @@
package com.android.inputmethod.latin;
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
import com.android.inputmethod.latin.utils.StringUtils;
import java.util.Arrays;
@@ -48,6 +47,11 @@ public final class WordComposer {
// 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;
@@ -85,6 +89,7 @@ public final class WordComposer {
mIsBatchMode = false;
mCursorPositionWithinWord = 0;
mRejectedBatchModeSuggestion = null;
+ mPreviousWordForSuggestion = null;
refreshSize();
}
@@ -101,6 +106,7 @@ public final class WordComposer {
mIsBatchMode = source.mIsBatchMode;
mCursorPositionWithinWord = source.mCursorPositionWithinWord;
mRejectedBatchModeSuggestion = source.mRejectedBatchModeSuggestion;
+ mPreviousWordForSuggestion = source.mPreviousWordForSuggestion;
refreshSize();
}
@@ -118,6 +124,7 @@ public final class WordComposer {
mIsBatchMode = false;
mCursorPositionWithinWord = 0;
mRejectedBatchModeSuggestion = null;
+ mPreviousWordForSuggestion = null;
refreshSize();
}
@@ -178,7 +185,7 @@ public final class WordComposer {
// (See {@link #setBatchInputWord}).
if (!mIsBatchMode) {
// TODO: Set correct pointer id and time
- mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0);
+ mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0);
}
}
mIsFirstCharCapitalized = isFirstCharCapitalized(
@@ -266,33 +273,23 @@ public final class WordComposer {
}
/**
- * 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;
- }
- 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) {
+ add(codePoints[i], CoordinateUtils.xFromArray(coordinates, i),
+ CoordinateUtils.yFromArray(coordinates, i));
}
mIsResumed = true;
+ mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString();
}
/**
@@ -343,6 +340,10 @@ public final class WordComposer {
return mTypedWord.toString();
}
+ public String getPreviousWordForSuggestion() {
+ return mPreviousWordForSuggestion;
+ }
+
/**
* Whether or not the user typed a capital letter as the first letter in the word
* @return capitalization preference
@@ -388,18 +389,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,7 +437,8 @@ 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
@@ -451,6 +456,7 @@ public final class WordComposer {
mCapsCount = 0;
mDigitsCount = 0;
mIsBatchMode = false;
+ mPreviousWordForSuggestion = committedWord.toString();
mTypedWord.setLength(0);
mCodePointSize = 0;
mTrailingSingleQuotesCount = 0;
@@ -464,7 +470,15 @@ public final class WordComposer {
return lastComposedWord;
}
- public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) {
+ // 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) {
mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes;
mInputPointers.set(lastComposedWord.mInputPointers);
mTypedWord.setLength(0);
@@ -475,6 +489,7 @@ public final class WordComposer {
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..800f56597 100644
--- a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
@@ -26,7 +26,7 @@ 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.DictionaryInfoUtils;
import com.android.inputmethod.latin.utils.LocaleUtils;
@@ -51,7 +51,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());
}
@@ -99,7 +99,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()) {
@@ -143,7 +143,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 {
diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
index dc937fb25..e6fa1cdad 100644
--- a/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
+++ b/java/src/com/android/inputmethod/latin/define/ProductionFlag.java
@@ -29,4 +29,7 @@ public final class ProductionFlag {
public static final boolean USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG = false;
public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = 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..045d06f0e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -0,0 +1,1962 @@
+/*
+ * 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.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.inputmethod.compat.SuggestionSpanUtils;
+import com.android.inputmethod.event.EventInterpreter;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.Dictionary;
+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.
+ public int mSpaceState;
+ // Never null
+ public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
+ // TODO: mSuggest should be touched by a single thread.
+ public volatile Suggest mSuggest;
+ // The event interpreter should never be null.
+ public final EventInterpreter mEventInterpreter;
+
+ public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
+ public final WordComposer mWordComposer;
+ public final RichInputConnection mConnection;
+ public 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.
+ public boolean mIsAutoCorrectionIndicatorOn;
+
+ public InputLogic(final LatinIME latinIME,
+ final SuggestionStripViewAccessor suggestionStripViewAccessor) {
+ mLatinIME = latinIME;
+ mSuggestionStripViewAccessor = suggestionStripViewAccessor;
+ mWordComposer = new WordComposer();
+ mEventInterpreter = new EventInterpreter(latinIME);
+ 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();
+ mInputLogicHandler = new InputLogicHandler(mLatinIME, this);
+ }
+
+ /**
+ * Clean up the input logic after input is finished.
+ */
+ public void finishInput() {
+ if (mWordComposer.isComposingWord()) {
+ mConnection.finishComposingText();
+ }
+ resetComposingState(true /* alsoResetLastComposedWord */);
+ mInputLogicHandler.destroy();
+ mInputLogicHandler = InputLogicHandler.NULL_HANDLER;
+ }
+
+ /**
+ * 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 rawText the text to input.
+ */
+ public void onTextInput(final SettingsValues settingsValues, final String rawText,
+ // TODO: remove this argument
+ final LatinIME.UIHandler handler) {
+ 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.
+ */
+ // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener}
+ // interface
+ public void onPickSuggestionManually(final SettingsValues settingsValues,
+ final int index, final SuggestedWordInfo suggestionInfo,
+ // TODO: remove these two arguments
+ final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) {
+ 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 int primaryCode = suggestion.charAt(0);
+ onCodeInput(primaryCode,
+ Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
+ settingsValues, handler, keyboardSwitcher);
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_punctuationSuggestion(index, suggestion,
+ false /* isBatchMode */, suggestedWords.mIsPrediction);
+ }
+ return;
+ }
+
+ 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: stop relying on mApplicationSpecifiedCompletions. The SuggestionInfo object
+ // should contain a reference to the CompletionInfo instead.
+ if (settingsValues.isApplicationSpecifiedCompletionsOn()
+ && mLatinIME.mApplicationSpecifiedCompletions != null
+ && index >= 0 && index < mLatinIME.mApplicationSpecifiedCompletions.length) {
+ mSuggestedWords = SuggestedWords.EMPTY;
+ mSuggestionStripViewAccessor.setNeutralSuggestionStrip();
+ keyboardSwitcher.updateShiftState();
+ resetComposingState(true /* alsoResetLastComposedWord */);
+ final CompletionInfo completionInfo = mLatinIME.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);
+ 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;
+ keyboardSwitcher.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.
+ && !suggest.mDictionaryFacilitator.isValidWord(suggestion,
+ true /* ignoreCase */);
+
+ if (settingsValues.mIsInternal) {
+ LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE,
+ Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+ }
+ if (showingAddToDictionaryHint
+ && suggest.mDictionaryFacilitator.isUserDictionaryEnabled()) {
+ mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion);
+ } else {
+ // If we're not showing the "Touch again to save", then update the suggestion strip.
+ handler.postUpdateSuggestionStrip();
+ }
+ }
+
+ /**
+ * 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 settingsValues the current settings
+ * @param oldSelStart old selection start
+ * @param oldSelEnd old selection end
+ * @param newSelStart new selection start
+ * @param newSelEnd new selection end
+ * @param composingSpanStart composing span start
+ * @param composingSpanEnd composing span end
+ * @return whether the cursor has moved as a result of user interaction.
+ */
+ public boolean onUpdateSelection(final SettingsValues settingsValues,
+ final int oldSelStart, final int oldSelEnd,
+ final int newSelStart, final int newSelEnd,
+ final int composingSpanStart, final int composingSpanEnd) {
+ 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(settingsValues, 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 code the code to handle. It may be a code point, or an internal key code.
+ * @param x the x-coordinate where the user pressed the key, or NOT_A_COORDINATE.
+ * @param y the y-coordinate where the user pressed the key, or NOT_A_COORDINATE.
+ */
+ public void onCodeInput(final int code, final int x, final int y,
+ final SettingsValues settingsValues,
+ // TODO: remove these two arguments
+ final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) {
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_onCodeInput(code, x, y);
+ }
+ final long when = SystemClock.uptimeMillis();
+ if (code != Constants.CODE_DELETE
+ || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) {
+ mDeleteCount = 0;
+ }
+ mLastKeyTime = when;
+ mConnection.beginBatchEdit();
+ // 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 (code != Constants.CODE_SPACE) {
+ handler.cancelDoubleSpacePeriodTimer();
+ }
+
+ boolean didAutoCorrect = false;
+ switch (code) {
+ case Constants.CODE_DELETE:
+ handleBackspace(settingsValues, spaceState, handler, keyboardSwitcher);
+ LatinImeLogger.logOnDelete(x, y);
+ break;
+ case Constants.CODE_SHIFT:
+ performRecapitalization(settingsValues);
+ keyboardSwitcher.updateShiftState();
+ 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_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(settingsValues, Constants.CODE_ENTER,
+ x, y, spaceState, keyboardSwitcher, handler);
+ }
+ break;
+ case Constants.CODE_SHIFT_ENTER:
+ didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER,
+ x, y, spaceState, keyboardSwitcher, handler);
+ 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;
+ default:
+ didAutoCorrect = handleNonSpecialCharacter(settingsValues,
+ code, x, y, spaceState, keyboardSwitcher, handler);
+ break;
+ }
+ // Reset after any single keystroke, except shift, capslock, and symbol-shift
+ if (!didAutoCorrect && code != Constants.CODE_SHIFT
+ && code != Constants.CODE_CAPSLOCK
+ && code != Constants.CODE_SWITCH_ALPHA_SYMBOL)
+ mLastComposedWord.deactivate();
+ if (Constants.CODE_DELETE != code) {
+ mEnteredText = null;
+ }
+ mConnection.endBatchEdit();
+ }
+
+ 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);
+ }
+ }
+ 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(settingsValues, mConnection.getExpectedSelectionStart(),
+ mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */);
+ } 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(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.updateShiftState();
+ }
+ }
+ 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.updateShiftState();
+ mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
+ getActualCapsMode(settingsValues,
+ keyboardSwitcher.getKeyboardShiftMode()), commitParts[0]);
+ ++mAutoCommitSequenceNumber;
+ }
+ }
+ }
+ mInputLogicHandler.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber);
+ }
+
+ public void onEndBatchInput(final SettingsValues settingValues,
+ final InputPointers batchPointers) {
+ mInputLogicHandler.onEndBatchInput(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 settingsValues The current settings values.
+ * @param codePoint the code point associated with the key.
+ * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable.
+ * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable.
+ * @param spaceState the space state at start of the batch input.
+ * @return whether this caused an auto-correction to happen.
+ */
+ private boolean handleNonSpecialCharacter(final SettingsValues settingsValues,
+ final int codePoint, final int x, final int y, final int spaceState,
+ // TODO: remove these arguments
+ final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
+ mSpaceState = SpaceState.NONE;
+ final boolean didAutoCorrect;
+ if (settingsValues.isWordSeparator(codePoint)
+ || Character.getType(codePoint) == Character.OTHER_SYMBOL) {
+ didAutoCorrect = handleSeparator(settingsValues, codePoint,
+ Constants.SUGGESTION_STRIP_COORDINATE == x, spaceState, keyboardSwitcher,
+ handler);
+ if (settingsValues.mIsInternal) {
+ LatinImeLoggerUtils.onSeparator((char)codePoint, x, y);
+ }
+ } else {
+ didAutoCorrect = false;
+ if (SpaceState.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(settingsValues, mConnection.getExpectedSelectionStart(),
+ mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */);
+ } else {
+ commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR);
+ }
+ }
+ handleNonSeparator(settingsValues, codePoint, x, y, spaceState,
+ keyboardSwitcher, handler);
+ }
+ return didAutoCorrect;
+ }
+
+ /**
+ * Handle a non-separator.
+ * @param settingsValues The current settings values.
+ * @param codePoint the code point associated with the key.
+ * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable.
+ * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable.
+ * @param spaceState the space state at start of the batch input.
+ */
+ private void handleNonSeparator(final SettingsValues settingsValues,
+ final int codePoint, final int x, final int y, final int spaceState,
+ // TODO: Remove these arguments
+ final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
+ // 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 == spaceState && !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(settingsValues, 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.add(codePoint, x, y);
+ // If it's the first letter, make note of auto-caps state
+ if (mWordComposer.size() == 1) {
+ // 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(
+ getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()),
+ getNthPreviousWordForSuggestion(
+ settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */));
+ }
+ mConnection.setComposingText(getTextWithUnderline(
+ mWordComposer.getTypedWord()), 1);
+ } else {
+ final boolean swapWeakSpace = maybeStripSpace(settingsValues,
+ codePoint, spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x);
+
+ sendKeyCodePoint(settingsValues, codePoint);
+
+ if (swapWeakSpace) {
+ swapSwapperAndSpace(keyboardSwitcher);
+ mSpaceState = SpaceState.WEAK;
+ }
+ // In case the "add to dictionary" hint was still displayed.
+ mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
+ }
+ handler.postUpdateSuggestionStrip();
+ if (settingsValues.mIsInternal) {
+ LatinImeLoggerUtils.onNonSeparator((char)codePoint, x, y);
+ }
+ }
+
+ /**
+ * Handle input of a separator code point.
+ * @param settingsValues The current settings values.
+ * @param codePoint the code point associated with the key.
+ * @param isFromSuggestionStrip whether this code point comes from the suggestion strip.
+ * @param spaceState the space state at start of the batch input.
+ * @return whether this caused an auto-correction to happen.
+ */
+ private boolean handleSeparator(final SettingsValues settingsValues,
+ final int codePoint, final boolean isFromSuggestionStrip, final int spaceState,
+ // TODO: remove these arguments
+ final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
+ boolean didAutoCorrect = false;
+ // We avoid sending spaces in languages without spaces if we were composing.
+ final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint
+ && !settingsValues.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(settingsValues, mConnection.getExpectedSelectionStart(),
+ mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */);
+ }
+ // isComposingWord() may have changed since we stored wasComposing
+ if (mWordComposer.isComposingWord()) {
+ if (settingsValues.mCorrectionEnabled) {
+ final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
+ : StringUtils.newSingleCodePointString(codePoint);
+ commitCurrentAutoCorrection(settingsValues, separator, handler);
+ didAutoCorrect = true;
+ } else {
+ commitTyped(settingsValues, StringUtils.newSingleCodePointString(codePoint));
+ }
+ }
+
+ final boolean swapWeakSpace = maybeStripSpace(settingsValues, codePoint, spaceState,
+ isFromSuggestionStrip);
+
+ final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint
+ && mConnection.isInsideDoubleQuoteOrAfterDigit();
+
+ final boolean needsPrecedingSpace;
+ if (SpaceState.PHANTOM != spaceState) {
+ 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 = settingsValues.isUsuallyPrecededBySpace(codePoint);
+ }
+
+ if (needsPrecedingSpace) {
+ promotePhantomSpace(settingsValues);
+ }
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord());
+ }
+
+ if (!shouldAvoidSendingCode) {
+ sendKeyCodePoint(settingsValues, codePoint);
+ }
+
+ if (Constants.CODE_SPACE == codePoint) {
+ if (settingsValues.isSuggestionsRequested()) {
+ if (maybeDoubleSpacePeriod(settingsValues, handler)) {
+ keyboardSwitcher.updateShiftState();
+ mSpaceState = SpaceState.DOUBLE;
+ } else if (!mSuggestedWords.isPunctuationSuggestions()) {
+ mSpaceState = SpaceState.WEAK;
+ }
+ }
+
+ handler.startDoubleSpacePeriodTimer();
+ handler.postUpdateSuggestionStrip();
+ } else {
+ if (swapWeakSpace) {
+ swapSwapperAndSpace(keyboardSwitcher);
+ mSpaceState = SpaceState.SWAP_PUNCTUATION;
+ } else if ((SpaceState.PHANTOM == spaceState
+ && settingsValues.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();
+ }
+
+ keyboardSwitcher.updateShiftState();
+ return didAutoCorrect;
+ }
+
+ /**
+ * Handle a press on the backspace key.
+ * @param settingsValues The current settings values.
+ * @param spaceState The space state at start of this batch edit.
+ */
+ private void handleBackspace(final SettingsValues settingsValues, final int spaceState,
+ // TODO: remove these arguments
+ final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) {
+ mSpaceState = SpaceState.NONE;
+ final int deleteCountAtStart = mDeleteCount;
+ mDeleteCount++;
+
+ // 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.
+ handler.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(settingsValues, 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.deleteLast();
+ }
+ mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
+ handler.postUpdateSuggestionStrip();
+ if (!mWordComposer.isComposingWord()) {
+ // If we just removed the last character, auto-caps mode may have changed so we
+ // need to re-evaluate.
+ keyboardSwitcher.updateShiftState();
+ }
+ } else {
+ if (mLastComposedWord.canRevertCommit()) {
+ if (settingsValues.mIsInternal) {
+ LatinImeLoggerUtils.onAutoCorrectionCancellation();
+ }
+ revertCommit(settingsValues, handler);
+ 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 == spaceState) {
+ handler.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 (SpaceState.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 (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 (settingsValues.isBeforeJellyBean() ||
+ settingsValues.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 (settingsValues.isSuggestionStripVisible()
+ && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
+ && !mConnection.isCursorFollowedByWordCharacter(
+ settingsValues.mSpacingAndPunctuations)) {
+ restartSuggestionsOnWordTouchedByCursor(settingsValues,
+ true /* includeResumedWordInSuggestions */);
+ }
+ // We just removed at least one character. We need to update the auto-caps state.
+ keyboardSwitcher.updateShiftState();
+ }
+ }
+
+ /**
+ * 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.
+ */
+ // TODO: Remove this argument
+ private void swapSwapperAndSpace(final KeyboardSwitcher keyboardSwitcher) {
+ 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);
+ }
+ keyboardSwitcher.updateShiftState();
+ }
+ }
+
+ /*
+ * Strip a trailing space if necessary and returns whether it's a swap weak space situation.
+ * @param settingsValues The current settings values.
+ * @param codePoint The code point that is about to be inserted.
+ * @param spaceState The space state at start of this batch edit.
+ * @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 SettingsValues settingsValues,
+ final int code, final int spaceState, final boolean isFromSuggestionStrip) {
+ if (Constants.CODE_ENTER == code && SpaceState.SWAP_PUNCTUATION == spaceState) {
+ mConnection.removeTrailingSpace();
+ return false;
+ }
+ if ((SpaceState.WEAK == spaceState || SpaceState.SWAP_PUNCTUATION == spaceState)
+ && isFromSuggestionStrip) {
+ if (settingsValues.isUsuallyPrecededBySpace(code)) return false;
+ if (settingsValues.isUsuallyFollowedBySpace(code)) return true;
+ mConnection.removeTrailingSpace();
+ }
+ return false;
+ }
+
+ /**
+ * 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 settingsValues the current values of the settings.
+ * @return true if we applied the double-space-to-period transformation, false otherwise.
+ */
+ private boolean maybeDoubleSpacePeriod(final SettingsValues settingsValues,
+ // TODO: remove this argument
+ final LatinIME.UIHandler handler) {
+ if (!settingsValues.mUseDoubleSpacePeriod) return false;
+ if (!handler.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)) {
+ handler.cancelDoubleSpacePeriodTimer();
+ mConnection.deleteSurroundingText(2, 0);
+ final String textToInsert =
+ settingsValues.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 Suggest suggest = mSuggest;
+ if (suggest == null) return;
+
+ final boolean wasAutoCapitalized =
+ mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps();
+ final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
+ System.currentTimeMillis());
+ suggest.mDictionaryFacilitator.addToUserHistory(suggestion, wasAutoCapitalized, prevWord,
+ timeStampInSeconds);
+ }
+
+ public void performUpdateSuggestionStripSync(final SettingsValues settingsValues,
+ // TODO: Remove this argument
+ final LatinIME.UIHandler handler) {
+ handler.cancelUpdateSuggestionStrip();
+
+ // Check if we have a suggestion engine attached.
+ if (mSuggest == null || !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 SuggestedWords suggestedWordsWithMaybeOlderSuggestions =
+ mLatinIME.maybeRetrieveOlderSuggestions(
+ mWordComposer.getTypedWord(), suggestedWords,
+ mSuggestedWords);
+ holder.set(suggestedWordsWithMaybeOlderSuggestions);
+ }
+ }
+ );
+
+ // 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 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)) 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.
+ final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
+ null /* rawSuggestions */, typedWord,
+ true /* 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 settingsValues the current settings values.
+ */
+ private void revertCommit(final SettingsValues settingsValues,
+ // TODO: remove this argument
+ final LatinIME.UIHandler handler) {
+ 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)) {
+ if (mSuggest != null) {
+ 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(settingsValues.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(settingsValues.mLocale,
+ suggestions.toArray(new String[suggestions.size()]), 0 /* flags */),
+ 0 /* start */, lastCharIndex /* end */, 0 /* flags */);
+ }
+ if (settingsValues.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 (settingsValues.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.
+ handler.postUpdateSuggestionStrip();
+ }
+
+ /**
+ * 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 settingsValues the current values of the settings.
+ * @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 ?!
+ // TODO: remove all references to this in LatinIME and make this private
+ public void resetEntireInputState(final SettingsValues settingsValues,
+ 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.
+ */
+ // TODO: remove all references to this in LatinIME and make this private.
+ public void resetComposingState(final boolean alsoResetLastComposedWord) {
+ mWordComposer.reset();
+ if (alsoResetLastComposedWord) {
+ mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
+ }
+ }
+
+ /**
+ * 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: remove all references to this in LatinIME and make this private. Also, shouldn't
+ // this go in some *Utils class instead?
+ public 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.
+ */
+ 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.
+ */
+ // TODO: Make this private.
+ public 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 endBatchInputInternal(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.updateShiftState();
+ }
+
+ /**
+ * 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()) {
+ performUpdateSuggestionStripSync(settingsValues, handler);
+ }
+ 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.
+ */
+ // TODO: Make this private
+ public 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..b09e20591
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
@@ -0,0 +1,198 @@
+/*
+ * 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.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 destroy() {}
+ @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 onEndBatchInput(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 destroy() {
+ mNonUIThreadHandler.getLooper().quit();
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ /**
+ * 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 forEnd 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 forEnd) {
+ 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,
+ forEnd /* dismissGestureFloatingPreviewText */);
+ if (forEnd) {
+ mInBatchInput = false;
+ // The following call schedules onEndBatchInputAsyncInternal
+ // to be called on the UI thread.
+ mLatinIME.mHandler.onEndBatchInput(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 /* forEnd */);
+ }
+
+ /**
+ * Cancel a batch input.
+ *
+ * Note that as opposed to onEndBatchInput, 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;
+ }
+ }
+
+ /**
+ * Finish a batch input.
+ *
+ * This fetches suggestions, updates the suggestion strip and commits the first suggestion.
+ * It also dismisses 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 onEndBatchInput(final InputPointers batchPointers, final int sequenceNumber) {
+ updateBatchInput(batchPointers, sequenceNumber, true /* forEnd */);
+ }
+
+ 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
index fda97dafc..bc856f113 100644
--- a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
@@ -17,53 +17,19 @@
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.FileNotFoundException;
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;
- }
+ 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)
@@ -86,122 +52,53 @@ public abstract class AbstractDictDecoder implements DictDecoder {
}
/**
- * A utility class for reading a file header.
+ * 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.
*/
- 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();
+ private int checkHeader() {
+ try {
+ readHeader();
+ } catch (IOException e) {
+ return ERROR_CANNOT_READ;
+ } catch (UnsupportedFormatException e) {
+ return ERROR_WRONG_FORMAT;
}
+ return SUCCESS;
+ }
- protected static int readHeaderSize(final DictBuffer dictBuffer) {
- return dictBuffer.readInt();
- }
+ @Override
+ public boolean hasValidRawBinaryDictionary() {
+ return checkHeader() == SUCCESS;
+ }
- 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;
- }
+ // Placeholder implementations below. These are actually unused.
+ @Override
+ public void openDictBuffer() throws FileNotFoundException, IOException,
+ UnsupportedFormatException {
}
- /**
- * A utility class for reading a PtNode.
- */
- protected static class PtNodeReader {
- protected static int readPtNodeOptionFlags(final DictBuffer dictBuffer) {
- return dictBuffer.readUnsignedByte();
- }
+ @Override
+ public boolean isDictBufferOpen() {
+ return false;
+ }
- protected static int readParentAddress(final DictBuffer dictBuffer,
- final FormatOptions formatOptions) {
- if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
- return BinaryDictDecoderUtils.readSInt24(dictBuffer);
- } else {
- return FormatSpec.NO_PARENT_ADDRESS;
- }
- }
+ @Override
+ public PtNodeInfo readPtNode(final int ptNodePos) {
+ return null;
+ }
- 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;
- }
- }
- }
+ @Override
+ public void setPosition(int newPos) {
+ }
- // 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;
- }
+ @Override
+ public int getPosition() {
+ return 0;
+ }
- 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;
- }
+ @Override
+ public int readPtNodeCount() {
+ return 0;
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
index 216492b4d..b534ebeff 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
@@ -17,22 +17,12 @@
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.
@@ -51,8 +41,6 @@ public final class BinaryDictDecoderUtils {
// This utility class is not publicly instantiable.
}
- private static final int MAX_JUMPS = 12;
-
@UsedForTesting
public interface DictBuffer {
public int readUnsignedByte();
@@ -61,6 +49,7 @@ public final class BinaryDictDecoderUtils {
public int readInt();
public int position();
public void position(int newPosition);
+ @UsedForTesting
public void put(final byte b);
public int limit();
@UsedForTesting
@@ -200,8 +189,7 @@ public final class BinaryDictDecoderUtils {
* @param word the string to write.
* @return the size written, in bytes.
*/
- static int writeString(final byte[] buffer, final int origin,
- final String word) {
+ 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)) {
@@ -223,22 +211,28 @@ public final class BinaryDictDecoderUtils {
*
* This will also write the terminator byte.
*
- * @param buffer the OutputStream to write to.
+ * @param stream the OutputStream to write to.
* @param word the string to write.
+ * @return the size written, in bytes.
*/
- static void writeString(final OutputStream buffer, final String word) throws IOException {
+ 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);
- if (1 == getCharSize(codePoint)) {
- buffer.write((byte) codePoint);
+ final int charSize = getCharSize(codePoint);
+ if (1 == charSize) {
+ stream.write((byte) codePoint);
} else {
- buffer.write((byte) (0xFF & (codePoint >> 16)));
- buffer.write((byte) (0xFF & (codePoint >> 8)));
- buffer.write((byte) (0xFF & codePoint));
+ stream.write((byte) (0xFF & (codePoint >> 16)));
+ stream.write((byte) (0xFF & (codePoint >> 8)));
+ stream.write((byte) (0xFF & codePoint));
}
+ written += charSize;
}
- buffer.write(FormatSpec.PTNODE_CHARACTERS_TERMINATOR);
+ stream.write(FormatSpec.PTNODE_CHARACTERS_TERMINATOR);
+ written += FormatSpec.PTNODE_TERMINATOR_SIZE;
+ return written;
}
/**
@@ -275,50 +269,6 @@ public final class BinaryDictDecoderUtils {
}
}
- // 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.
*/
@@ -338,71 +288,34 @@ public final class BinaryDictDecoderUtils {
* @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.
*/
+ @UsedForTesting
/* package for tests */ static WeightedString getWordAtPosition(final DictDecoder dictDecoder,
- final int headerSize, final int pos, final FormatOptions formatOptions) {
+ final int headerSize, final int pos) {
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);
- }
-
+ result = getWordAtPositionWithoutParentAddress(dictDecoder, headerSize, pos);
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) {
+ final DictDecoder dictDecoder, final int headerSize, final int pos) {
dictDecoder.setPosition(headerSize);
final int count = dictDecoder.readPtNodeCount();
- int groupPos = headerSize + BinaryDictIOUtils.getPtNodeCountSize(count);
+ 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, options);
+ 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.mFrequency);
+ result = new WeightedString(builder.toString(), info.mProbabilityInfo);
break; // and return
}
if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) {
@@ -430,158 +343,6 @@ public final class BinaryDictDecoderUtils {
}
/**
- * 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) {
@@ -592,32 +353,14 @@ public final class BinaryDictDecoderUtils {
/**
* 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) {
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file);
+ if (dictDecoder == null) {
return false;
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
}
+ return dictDecoder.hasValidRawBinaryDictionary();
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
index f761829de..1593dea4f 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
@@ -16,10 +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.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;
@@ -121,18 +122,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 +146,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 +161,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 +230,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 +363,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 +374,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 +405,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 +439,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 +450,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 +471,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 +484,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 +580,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 +611,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 +652,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 +692,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 +707,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 +726,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 +747,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 +782,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 +852,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/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index d5516ef46..989ca4b2f 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -18,12 +18,8 @@ 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;
@@ -32,7 +28,6 @@ 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;
@@ -62,16 +57,15 @@ public final class BinaryDictIOUtils {
* Retrieves all node arrays without recursive call.
*/
private static void readUnigramsAndBigramsBinaryInner(final DictDecoder dictDecoder,
- final int headerSize, final Map<Integer, String> words,
+ final int bodyOffset, final Map<Integer, String> words,
final Map<Integer, Integer> frequencies,
- final Map<Integer, ArrayList<PendingAttribute>> bigrams,
- final FormatOptions formatOptions) {
+ 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(headerSize, 0);
+ Position initPos = new Position(bodyOffset, 0);
stack.push(initPos);
while (!stack.empty()) {
@@ -87,51 +81,36 @@ public final class BinaryDictIOUtils {
if (p.mNumOfPtNode == Position.NOT_READ_PTNODE_COUNT) {
p.mNumOfPtNode = dictDecoder.readPtNodeCount();
- p.mAddress += getPtNodeCountSize(p.mNumOfPtNode);
+ p.mAddress = dictDecoder.getPosition();
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];
+ final PtNodeInfo ptNodeInfo = dictDecoder.readPtNode(p.mAddress);
+ for (int i = 0; i < ptNodeInfo.mCharacters.length; ++i) {
+ pushedChars[index++] = ptNodeInfo.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 (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) {
- 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();
- }
+ stack.pop();
} else {
- // The Ptnode array has more PtNodes.
+ // The PtNode array has more PtNodes.
p.mAddress = dictDecoder.getPosition();
}
- if (!isMovedPtNode && hasChildrenAddress(info.mChildrenAddress)) {
- final Position childrenPos = new Position(info.mChildrenAddress, index);
+ if (hasChildrenAddress(ptNodeInfo.mChildrenAddress)) {
+ final Position childrenPos = new Position(ptNodeInfo.mChildrenAddress, index);
stack.push(childrenPos);
}
}
@@ -153,9 +132,9 @@ public final class BinaryDictIOUtils {
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);
+ final DictionaryHeader header = dictDecoder.readHeader();
+ readUnigramsAndBigramsBinaryInner(dictDecoder, header.mBodyOffset, words,
+ frequencies, bigrams);
}
/**
@@ -173,8 +152,7 @@ public final class BinaryDictIOUtils {
final String word) throws IOException, UnsupportedFormatException {
if (word == null) return FormatSpec.NOT_VALID_WORD;
dictDecoder.setPosition(0);
-
- final FileHeader header = dictDecoder.readHeader();
+ dictDecoder.readHeader();
int wordPos = 0;
final int wordLen = word.codePointCount(0, word.length());
for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) {
@@ -185,13 +163,7 @@ public final class BinaryDictIOUtils {
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;
+ final PtNodeInfo currentInfo = dictDecoder.readPtNode(ptNodePos);
boolean same = true;
for (int p = 0, j = word.offsetByCodePoints(0, wordPos);
p < currentInfo.mCharacters.length;
@@ -206,8 +178,7 @@ public final class BinaryDictIOUtils {
if (same) {
// found the PtNode matches the word.
if (wordPos + currentInfo.mCharacters.length == wordLen) {
- if (currentInfo.mFrequency == PtNode.NOT_A_TERMINAL
- || isDeletedNode) {
+ if (!currentInfo.isTerminal()) {
return FormatSpec.NOT_VALID_WORD;
} else {
return ptNodePos;
@@ -222,255 +193,33 @@ public final class BinaryDictIOUtils {
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;
- }
+ 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.
+ * Writes a PtNodeCount 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
+ * @param ptNodeCount the count.
+ * @return the size written in bytes.
*/
- static int writeNodes(final OutputStream destination, final PtNodeInfo[] infos)
+ @UsedForTesting
+ static int writePtNodeCount(final OutputStream destination, final int ptNodeCount)
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.");
+ 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);
}
- for (final PtNodeInfo info : infos) size += writePtNode(destination, info);
- writeSInt24ToStream(destination, FormatSpec.NO_FORWARD_LINK_ADDRESS);
- return size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
+ final int encodedPtNodeCount = (countSize == 2) ?
+ (ptNodeCount | FormatSpec.LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG) : ptNodeCount;
+ BinaryDictEncoderUtils.writeUIntToStream(destination, encodedPtNodeCount, countSize);
+ return countSize;
}
private static final int HEADER_READING_BUFFER_SIZE = 16384;
@@ -482,8 +231,9 @@ public final class BinaryDictIOUtils {
* @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.
+ * @return the header of the specified dictionary file.
*/
- private static FileHeader getDictionaryFileHeader(
+ private static DictionaryHeader getDictionaryFileHeader(
final File file, final long offset, final long length)
throws FileNotFoundException, IOException, UnsupportedFormatException {
final byte[] buffer = new byte[HEADER_READING_BUFFER_SIZE];
@@ -503,13 +253,16 @@ public final class BinaryDictIOUtils {
}
}
);
+ if (dictDecoder == null) {
+ return null;
+ }
return dictDecoder.readHeader();
}
- public static FileHeader getDictionaryFileHeaderOrNull(final File file, final long offset,
+ public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file, final long offset,
final long length) {
try {
- final FileHeader header = getDictionaryFileHeader(file, offset, length);
+ final DictionaryHeader header = getDictionaryFileHeader(file, offset, length);
return header;
} catch (UnsupportedFormatException e) {
return null;
@@ -526,30 +279,6 @@ public final class BinaryDictIOUtils {
}
/**
- * 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.
@@ -566,9 +295,7 @@ public final class BinaryDictIOUtils {
}
}
- static int getChildrenAddressSize(final int optionFlags,
- final FormatOptions formatOptions) {
- if (formatOptions.mSupportsDynamicUpdate) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
+ static int getChildrenAddressSize(final int optionFlags) {
switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) {
case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE:
return 1;
@@ -589,6 +316,7 @@ public final class BinaryDictIOUtils {
* @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)
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
index 3dbeee099..a3b28a702 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
+++ b/java/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/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
index ea5d492d8..a5dc45691 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
@@ -32,7 +32,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/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..b99e281da
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.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.makedict;
+
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
+
+/**
+ * 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 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..c7635eff9 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -19,7 +19,6 @@ 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;
@@ -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,80 +309,20 @@ 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.
- */
- 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);
- }
-
- // 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);
- }
- }
-
- /**
* Returns new dictionary decoder.
*
* @param dictFile the dictionary file.
@@ -415,7 +333,7 @@ public final class FormatSpec {
if (dictFile.isDirectory()) {
return new Ver4DictDecoder(dictFile, bufferType);
} else if (dictFile.isFile()) {
- return new Ver3DictDecoder(dictFile, bufferType);
+ return new Ver2DictDecoder(dictFile, bufferType);
}
return null;
}
@@ -425,7 +343,7 @@ public final class FormatSpec {
if (dictFile.isDirectory()) {
return new Ver4DictDecoder(dictFile, factory);
} else if (dictFile.isFile()) {
- return new Ver3DictDecoder(dictFile, factory);
+ return new Ver2DictDecoder(dictFile, factory);
}
return null;
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 3bb218bea..8f73b27b5 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -31,7 +31,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 +61,72 @@ 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.
+ * A string with a probability.
*
* 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) {
+ 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;
- mFrequency = frequency;
+ mProbabilityInfo = probabilityInfo;
+ }
+
+ 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, mFrequency });
+ return Arrays.hashCode(new Object[] { mWord, mProbabilityInfo});
}
@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;
+ final WeightedString w = (WeightedString)o;
+ return mWord.equals(w.mWord) && mProbabilityInfo.equals(w.mProbabilityInfo);
}
}
/**
- * 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 +142,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 +155,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 +179,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 +219,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 +276,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 +291,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 +308,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);
}
}
}
@@ -303,14 +324,9 @@ 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) {
+ public DictionaryOptions(final HashMap<String, String> attributes) {
mAttributes = attributes;
- mGermanUmlautProcessing = germanUmlautProcessing;
- mFrenchLigatureProcessing = frenchLigatureProcessing;
}
@Override
public String toString() { // Convenience method
@@ -339,14 +355,6 @@ public final class FusionDictionary implements Iterable<Word> {
}
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();
}
}
@@ -392,13 +400,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 +419,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 +444,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 +474,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 +510,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 +521,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 +537,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 +547,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 +556,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 +628,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 +713,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 +747,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 +763,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 +791,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/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..9dcd63f0c
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/ProbabilityInfo.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.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;
+
+ 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/PtNodeInfo.java b/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
index 188de7a0f..f52117c6c 100644
--- a/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
+++ b/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
@@ -29,24 +29,26 @@ public final class PtNodeInfo {
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/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/Ver2DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
new file mode 100644
index 000000000..bf776cfc5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java
@@ -0,0 +1,316 @@
+/*
+ * 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.makedict.FusionDictionary.WeightedString;
+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;
+ // TODO: Remove mBufferFactory and mDictBuffer from this class members because they are now
+ // used only for testing.
+ private final DictionaryBufferFactory mBufferFactory;
+ protected DictBuffer mDictBuffer;
+
+ /* package */ Ver2DictDecoder(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 */ Ver2DictDecoder(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 DictionaryHeader readHeader() throws 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 = 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/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
index 5da34534e..e247f0121 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java
@@ -16,6 +16,7 @@
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;
@@ -31,16 +32,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 +52,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 +72,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 +95,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 +107,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 +139,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 +160,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 +181,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 +211,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 +230,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/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
index 734223ec2..afe82317e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
@@ -17,21 +17,15 @@
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.BinaryDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.utils.CollectionUtils;
-
-import android.util.Log;
+import com.android.inputmethod.latin.utils.FileUtils;
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.
@@ -40,304 +34,83 @@ import java.util.Arrays;
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;
+ final File mDictDirectory;
@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();
- }
+ this(dictDirectory, null /* factory */);
}
@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);
+ 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;
}
- 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;
+ 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;
}
- 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 + ")");
+ 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);
}
- } 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();
+ // Insert bigrams into the fusion dictionary.
+ for (final WordProperty wordProperty : wordProperties) {
+ if (wordProperty.mBigrams == null) {
+ continue;
}
- throw e;
- } catch (UnsupportedFormatException e) {
- Log.e(TAG, "The dictionary " + mDictDirectory.getName() + " is broken.", e);
- if (deleteDictIfBroken) {
- deleteDictFiles();
+ final String word0 = wordProperty.mWord;
+ for (final WeightedString bigram : wordProperty.mBigrams) {
+ fusionDict.setBigram(word0, bigram.mWord, bigram.mProbabilityInfo);
}
- 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);
+ binaryDictionary.close();
+ return fusionDict;
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
index 8d5b48a9b..1050d1b0e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
@@ -1,5 +1,4 @@
/*
-/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,21 +17,15 @@
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.BinaryDictionary;
+import com.android.inputmethod.latin.Dictionary;
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.utils.LocaleUtils;
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.
@@ -40,244 +33,19 @@ import java.util.Iterator;
@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;
- }
- }
-
+ // 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(final FusionDictionary dict, final FormatOptions formatOptions)
+ 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 : "
@@ -286,190 +54,74 @@ public class Ver4DictEncoder implements DictEncoder {
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++;
+ if (!BinaryDictionary.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();
}
}
-
- 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.");
+ 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();
+ }
+ }
}
- mTrieOutStream.write(mTrieBuf);
-
- MakedictLog.i("Done");
- close();
+ binaryDict.flushWithGC();
+ binaryDict.close();
}
@Override
public void setPosition(int position) {
- if (mTrieBuf == null || position < 0 || position >- mTrieBuf.length) return;
- mTriePos = position;
}
@Override
public int getPosition() {
- return mTriePos;
+ return 0;
}
@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);
+ public void writePtNode(PtNode ptNode, FusionDictionary dict) {
}
}
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/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..1fc61e10a
--- /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.makedict.FusionDictionary.WeightedString;
+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;
+
+ 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..8f7378c58 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
@@ -17,26 +17,20 @@
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;
+import java.util.concurrent.TimeUnit;
/**
* This class is a base class of a dictionary that supports decaying for the personalized language
@@ -44,9 +38,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,52 +46,42 @@ 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 final String mDictName;
- 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, true /* isUpdatable */, dictFile);
mLocale = locale;
- mFileName = fileName;
- mPrefs = sp;
- if (mLocale != null && mLocale.length() > 1) {
- asyncLoadDictionaryToMemory();
+ mDictName = dictName;
+ 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();
}
@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);
+ attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
+ DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
+ attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY,
+ DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
+ 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())));
return attributeMap;
}
@@ -113,6 +95,18 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
return false;
}
+ public void addMultipleDictionaryEntriesToDictionary(
+ final ArrayList<LanguageModelParam> languageModelParams,
+ final ExpandableBinaryDictionary.AddMultipleDictionaryEntriesCallback callback) {
+ if (languageModelParams == null || languageModelParams.isEmpty()) {
+ if (callback != null) {
+ callback.onFinished();
+ }
+ return;
+ }
+ addMultipleDictionaryEntriesDynamically(languageModelParams, callback);
+ }
+
/**
* Pair will be added to the decaying dictionary.
*
@@ -121,104 +115,28 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
* 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) {
+ public void addToDictionary(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 = 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 */);
+ final int frequency = isValid ?
+ FREQUENCY_FOR_WORDS_IN_DICTS : FREQUENCY_FOR_WORDS_NOT_IN_DICTS;
+ 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) {
- addBigramDynamically(word0, word1, frequency, isValid);
+ addBigramDynamically(word0, word1, frequency, timestamp);
}
}
- 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);
+ // Never loaded to memory in Java side.
}
@UsedForTesting
@@ -226,7 +144,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
// Clear the node structure on memory
clear();
// Then flush the cleared state of the dictionary on disk.
- asyncFlashAllBinaryDictionary();
+ asyncFlushBinaryDictionary();
}
/* package */ void decayIfNeeded() {
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..d6c0dc0dc 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java
@@ -19,19 +19,26 @@ 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;
+
+public class PersonalizationDictionarySessionRegistrar {
+ public static void init(final Context context,
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
+ }
+
+ public static void onConfigurationChanged(final Context context, final Configuration conf,
+ final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
}
- 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..5ae2fb6f8 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -17,13 +17,15 @@
package com.android.inputmethod.latin.personalization;
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;
public class PersonalizationHelper {
@@ -31,21 +33,16 @@ public class PersonalizationHelper {
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,8 +52,9 @@ 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;
}
}
@@ -73,59 +71,71 @@ public class PersonalizationHelper {
}
}
- 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 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.clearAndFlushDictionary();
}
- 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..504e9b2f3 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -16,25 +16,37 @@
package com.android.inputmethod.latin.personalization;
+import android.content.Context;
+
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);
+ }
+
+ public void cancelAddingUserHistory(final String word0, final String word1) {
+ removeBigramDynamically(word0, word1);
}
- private static String getDictionaryFileName(final String locale) {
- return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
+ @Override
+ public boolean isValidWord(final String word) {
+ // Strings out of this dictionary should not be considered existing words.
+ return false;
}
}
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..6dae6206c 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,6 +42,8 @@ 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;
@@ -111,7 +111,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 +287,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) {
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index da1fb73fe..c87dd1589 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 {
@@ -39,9 +44,20 @@ public final class DebugSettings extends PreferenceFragment
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";
+
private static final boolean SHOW_STATISTICS_LOGGING = false;
private boolean mServiceNeedsRestart = false;
@@ -85,11 +101,64 @@ 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();
+ 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 +181,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 +201,92 @@ public final class DebugSettings extends PreferenceFragment
mDebugMode.setSummary(version);
}
}
+
+ 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..b51c765f0 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,6 +66,7 @@ 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";
@@ -96,6 +96,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 +108,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 +132,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 +152,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 +185,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);
}
@@ -229,16 +236,15 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
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);
@@ -299,19 +305,27 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
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(
+ 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 +334,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) {
@@ -377,21 +390,13 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
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);
- }
-
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 +404,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..bb5547fc9 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));
}
@@ -243,20 +237,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 +286,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())]);
+ 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 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]);
- }
-
- 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 +317,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,
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index f331c78e5..77968f79a 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,22 @@ 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;
// 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 +84,9 @@ 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) {
@@ -148,6 +128,7 @@ 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);
@@ -173,86 +154,55 @@ 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));
+ mUseOnlyPersonalizationDictionaryForDebug = prefs.getBoolean(
+ DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false);
+ 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 +210,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 +237,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 =
@@ -374,17 +312,103 @@ 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 mUseOnlyPersonalizationDictionaryForDebug = ");
+ sb.append("" + mUseOnlyPersonalizationDictionaryForDebug);
+ 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..5954758aa
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -0,0 +1,119 @@
+/*
+ * 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.KeyboardTextsSet;
+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 KeyboardTextsSet textsSet = new KeyboardTextsSet();
+ textsSet.setLocale(locale);
+ final String[] suggestPuncsSpec = MoreKeySpec.splitKeySpecs(
+ textsSet.resolveTextReference(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..dae36f7dd 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -383,6 +383,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 +430,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..3947019ca 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,11 +314,15 @@ 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,
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..b7a5a4026 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -49,6 +49,7 @@ 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,
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/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index acd47450b..a104baa08 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,17 @@ 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 = 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;
@@ -205,13 +206,13 @@ 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 word = mSuggestedWords.getLabel(index);
final String 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..8ea712835 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,6 +90,7 @@ 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();
@@ -100,10 +102,6 @@ final class SuggestionStripLayoutHelper {
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,7 +117,8 @@ 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);
@@ -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,9 +199,9 @@ final class SuggestionStripLayoutHelper {
if (indexInSuggestedWords >= suggestedWords.size()) {
return null;
}
- final String word = suggestedWords.getWord(indexInSuggestedWords);
+ final String word = suggestedWords.getLabel(indexInSuggestedWords);
final boolean isAutoCorrect = indexInSuggestedWords == 1
- && suggestedWords.willAutoCorrect();
+ && suggestedWords.mWillAutoCorrect;
final boolean isTypedWordValid = indexInSuggestedWords == 0
&& suggestedWords.mTypedWordValid;
if (!isAutoCorrect && !isTypedWordValid) {
@@ -229,7 +225,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 {
@@ -254,7 +250,7 @@ final class SuggestionStripLayoutHelper {
final boolean isSuggested = (indexInSuggestedWords != SuggestedWords.INDEX_OF_TYPED_WORD);
final int color;
- if (positionInStrip == mCenterPositionInStrip && suggestedWords.willAutoCorrect()) {
+ if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) {
color = mColorAutoCorrect;
} else if (positionInStrip == mCenterPositionInStrip && suggestedWords.mTypedWordValid) {
color = mColorValidTypedWord;
@@ -268,8 +264,8 @@ final class SuggestionStripLayoutHelper {
// 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;
}
}
@@ -292,54 +288,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;
}
/**
@@ -439,9 +446,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 +461,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 int stripWidth,
+ final String importantNoticeTitle) {
+ final TextView titleView = (TextView)importantNoticeStrip.findViewById(
+ R.id.important_notice_title);
+ final int width = stripWidth - 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 +531,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..4ef562d8f 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,6 +30,7 @@ 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;
@@ -35,13 +40,16 @@ 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 +58,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 +80,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 +146,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 +175,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 +189,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 +206,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,23 +226,55 @@ 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;
+ }
+ final int width = getWidth();
+ if (width <= 0) {
+ return false;
+ }
+ final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle(
+ getContext());
+ if (TextUtils.isEmpty(importantNoticeTitle)) {
+ return false;
+ }
+ mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, width, 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();
}
};
@@ -192,10 +292,18 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
@Override
public void onCancelMoreKeysPanel(final MoreKeysPanel panel) {
- mMoreSuggestionsView.dismissMoreKeysPanel();
+ dismissMoreSuggestionsPanel();
}
};
+ public boolean isShowingMoreSuggestionPanel() {
+ return mMoreSuggestionsView.isShowingInParent();
+ }
+
+ public void dismissMoreSuggestionsPanel() {
+ mMoreSuggestionsView.dismissMoreKeysPanel();
+ }
+
@Override
public boolean onLongClick(final View view) {
AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
@@ -216,7 +324,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
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 +335,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 +364,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 +404,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..60f1c7a4e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
@@ -0,0 +1,31 @@
+/*
+ * 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 boolean hasSuggestionStripView();
+ 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..ef1d0f42c 100644
--- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
@@ -17,21 +17,25 @@
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.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() {
@@ -43,6 +47,11 @@ public final class AdditionalSubtypeUtils {
}
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 +88,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 +96,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 +147,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..37c173f96 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) {
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..bb7ae2f9b
--- /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.WordProperty;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+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/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 021bf0825..a15556511 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -20,13 +20,17 @@ 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.annotations.UsedForTesting;
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.settings.SpacingAndPunctuations;
import java.io.File;
import java.util.ArrayList;
@@ -278,14 +282,23 @@ public class DictionaryInfoUtils {
BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale.getLanguage().toString();
}
- public static FileHeader getDictionaryFileHeaderOrNull(final File file) {
+ public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file) {
return BinaryDictIOUtils.getDictionaryFileHeaderOrNull(file, 0, file.length());
}
+ /**
+ * 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 = BinaryDictIOUtils.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 +341,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 +368,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/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..ca8bef397
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.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.latin.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+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;
+ }
+ return hasNewImportantNotice(context) && !isInSystemSetupWizard(context);
+ }
+
+ 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..a1d641508
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java
@@ -0,0 +1,171 @@
+/*
+ * 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 = 10;
+ private static final int BIGRAM_PROBABILITY_FOR_VALID_WORD = 0;
+ private static final int BIGRAM_PROBABILITY_FOR_OOV_WORD = 0;
+
+ 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);
+ 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.mLocale;
+ 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..b10d08af3 100644
--- a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
+++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
@@ -137,6 +137,7 @@ public class PrioritizedSerialExecutor {
public void shutdown() {
synchronized(mLock) {
mIsShutdown = true;
+ 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/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/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index a36548392..e7932b5a6 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)) {
@@ -163,19 +173,56 @@ public final class StringUtils {
private static final int[] EMPTY_CODEPOINTS = {};
public static int[] toCodePointArray(final String string) {
+ return toCodePointArray(string, 0, string.length());
+ }
+
+ /**
+ * Converts a range of a string to an array of code points.
+ * @param string 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 String string,
+ final int startIndex, final int endIndex) {
final int length = string.length();
if (length <= 0) {
return EMPTY_CODEPOINTS;
}
- final int[] codePoints = new int[string.codePointCount(0, length)];
+ final int[] codePoints = new int[string.codePointCount(startIndex, endIndex)];
int destIndex = 0;
- for (int index = 0; index < length; index = string.offsetByCodePoints(index, 1)) {
+ for (int index = startIndex; index < endIndex;
+ index = string.offsetByCodePoints(index, 1)) {
codePoints[destIndex] = string.codePointAt(index);
destIndex++;
}
return codePoints;
}
+ 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 +286,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 +368,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 +407,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 +460,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 +475,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 +492,19 @@ 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) {
- }
- }
- return Collections.<Object>emptyList();
+ 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 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();
- }
- writer.endArray();
- return sw.toString();
- } catch (IOException e) {
- } finally {
- try {
- if (writer != null) {
- writer.close();
- }
- } catch (IOException e) {
- }
- }
- return "";
+ 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;
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 102a41b4e..b3871bfb4 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -28,6 +28,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.DictionaryFactory;
import com.android.inputmethod.latin.R;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
@@ -197,7 +198,9 @@ 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
+ // de_CH swiss T Deutsch (Schweiz)
// zz qwerty F No language (QWERTY) in system locale
// fr qwertz T Français (QWERTZ)
// de qwerty T Deutsch (QWERTY)
@@ -298,7 +301,9 @@ public final class SubtypeLocaleUtils {
// 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)
+ // fr_CH swiss F Fr Français Français (Suisse)
// de qwertz F De Deutsch Deutsch
+ // de_CH swiss T De Deutsch Deutsch (Schweiz)
// zz qwerty F QWERTY QWERTY
// fr qwertz T Fr Français Français
// de qwerty T De Deutsch Deutsch
@@ -330,4 +335,24 @@ public final class SubtypeLocaleUtils {
final Locale locale = getSubtypeLocale(subtype);
return StringUtils.capitalizeFirstCodePoint(locale.getLanguage(), locale);
}
+
+ // 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);
+ }
+
+ public static boolean isRtlLanguage(final Locale locale) {
+ final String language = locale.getLanguage();
+ return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0;
+ }
+
+ public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
+ return isRtlLanguage(getSubtypeLocale(subtype));
+ }
}
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..9b1d8c535 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,8 @@ 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.hasMainDictionary())
+ && 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 +166,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 +177,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..b1f54c0b4 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,7 +1360,7 @@ 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());
}