aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dictionaries/en_GB_wordlist.combined.gzbin859901 -> 859921 bytes
-rw-r--r--dictionaries/en_US_wordlist.combined.gzbin876974 -> 876982 bytes
-rw-r--r--dictionaries/en_wordlist.combined.gzbin908339 -> 908355 bytes
-rw-r--r--dictionaries/fr_wordlist.combined.gzbin1106515 -> 1106532 bytes
-rw-r--r--dictionaries/iw_wordlist.combined.gzbin0 -> 465922 bytes
-rw-r--r--dictionaries/pt_BR_wordlist.combined.gzbin878432 -> 878475 bytes
-rw-r--r--dictionaries/pt_PT_wordlist.combined.gzbin1105829 -> 1105946 bytes
-rw-r--r--dictionaries/ru_wordlist.combined.gzbin1384773 -> 1384804 bytes
-rw-r--r--java/res/color/emoji_tab_label_color_gb.xml33
-rw-r--r--java/res/color/emoji_tab_label_color_ics.xml33
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_active_holo.9.pngbin462 -> 463 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.pngbin435 -> 463 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.pngbin547 -> 578 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.pngbin587 -> 639 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.pngbin553 -> 537 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.pngbin668 -> 655 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.pngbin707 -> 670 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.pngbin1785 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.pngbin1701 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.pngbin468 -> 474 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.pngbin547 -> 517 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.pngbin2389 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.pngbin2409 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.pngbin2211 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.pngbin282 -> 272 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_dark.pngbin1858 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_nature_light_activated.pngbin0 -> 1850 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_nature_light_normal.pngbin0 -> 1800 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_objects_light_activated.pngbin0 -> 1744 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_objects_light_normal.pngbin0 -> 1581 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_light_activated.pngbin0 -> 1767 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_light_normal.png (renamed from java/res/drawable-hdpi/ic_emoji_light.png)bin1820 -> 1820 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_light_activated.pngbin0 -> 1418 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_light_normal.pngbin0 -> 1341 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recent_light_activated.pngbin0 -> 1667 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recent_light_normal.pngbin0 -> 1703 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_symbols_light_activated.pngbin0 -> 1087 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_symbols_light_normal.pngbin0 -> 1053 bytes
-rw-r--r--java/res/drawable-hdpi/ic_ime_switcher_dark.pngbin0 -> 947 bytes
-rw-r--r--java/res/drawable-hdpi/ic_settings_language.pngbin986 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/ic_subtype_keyboard.pngbin812 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/ic_subtype_mic_dark.pngbin0 -> 1005 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_background.9.pngbin207 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_background_gb.9.png (renamed from java/res/drawable-hdpi/keyboard_dark_background.9.png)bin210 -> 210 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.pngbin2080 -> 2138 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_left_background_holo.9.pngbin1990 -> 2105 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_holo.9.pngbin2152 -> 2164 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_more_background_holo.9.pngbin2256 -> 2225 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_right_background_holo.9.pngbin1993 -> 2061 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_holo.9.pngbin2163 -> 2133 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png (renamed from java/res/drawable-hdpi/keyboard_popup_panel_background.9.png)bin1204 -> 1204 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.pngbin856 -> 874 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png (renamed from java/res/drawable-hdpi/keyboard_suggest_strip.9.png)bin248 -> 248 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.pngbin160 -> 156 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_delete.pngbin2314 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_label_mic.pngbin905 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_mic.pngbin1410 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_return.pngbin1111 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_search.pngbin1612 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_settings.pngbin729 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_shift.pngbin1474 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_shift_locked.pngbin1115 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_space.pngbin358 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_tab.pngbin1008 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_bkeyboard_voice_off.pngbin1587 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_delete.pngbin4003 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_delete_holo.pngbin1248 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_delete_holo_dark.pngbin0 -> 1024 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_label_mic.pngbin1417 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_label_mic_holo.pngbin771 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_language_switch.pngbin1788 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_language_switch_dark.pngbin0 -> 1773 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_mic.pngbin3893 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.pngbin0 -> 778 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_return.pngbin4024 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_return_holo.pngbin1216 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_return_holo_dark.pngbin0 -> 1011 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_search.pngbin4248 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_search_holo.pngbin1607 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_search_holo_dark.pngbin0 -> 1220 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_settings.pngbin4015 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_settings_holo.pngbin787 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.pngbin0 -> 889 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift.pngbin3740 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift_holo.pngbin1290 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift_holo_dark.pngbin0 -> 936 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift_locked.pngbin3686 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.pngbin1036 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_shift_locked_holo_dark.pngbin0 -> 730 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_space_holo.pngbin630 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_space_holo_dark.pngbin0 -> 593 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png (renamed from java/res/drawable-hdpi/sym_keyboard_space_led.9.png)bin557 -> 557 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_tab.pngbin3792 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_tab_holo.pngbin1142 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_tab_holo_dark.pngbin0 -> 937 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_voice_holo_dark.png (renamed from java/res/drawable-hdpi/sym_keyboard_voice_holo.png)bin1889 -> 1889 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_voice_off_holo_dark.png (renamed from java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png)bin1741 -> 1741 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_zwj_holo.pngbin973 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_zwj_holo_dark.pngbin0 -> 973 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_zwnj_holo.pngbin961 -> 0 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_zwnj_holo_dark.pngbin0 -> 975 bytes
-rw-r--r--java/res/drawable-hdpi/tab_selected.9.pngbin0 -> 145 bytes
-rw-r--r--java/res/drawable-hdpi/tab_unselected.9.pngbin0 -> 150 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_active_holo.9.pngbin345 -> 355 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.pngbin334 -> 355 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.pngbin407 -> 428 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.pngbin411 -> 453 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.pngbin394 -> 380 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.pngbin505 -> 468 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.pngbin489 -> 458 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.pngbin1553 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.pngbin1461 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.pngbin332 -> 339 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.pngbin381 -> 368 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.pngbin2389 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.pngbin2409 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.pngbin2212 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.pngbin236 -> 222 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_dark.pngbin1182 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_nature_light_activated.pngbin0 -> 1213 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_nature_light_normal.pngbin0 -> 1130 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_objects_light_activated.pngbin0 -> 1193 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_objects_light_normal.pngbin0 -> 1092 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_light_activated.pngbin0 -> 1170 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_light_normal.png (renamed from java/res/drawable-mdpi/ic_emoji_light.png)bin1132 -> 1132 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_light_activated.pngbin0 -> 1032 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_light_normal.pngbin0 -> 963 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recent_light_activated.pngbin0 -> 1105 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recent_light_normal.pngbin0 -> 1106 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_symbols_light_activated.pngbin0 -> 805 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_symbols_light_normal.pngbin0 -> 775 bytes
-rw-r--r--java/res/drawable-mdpi/ic_ime_switcher_dark.pngbin0 -> 784 bytes
-rw-r--r--java/res/drawable-mdpi/ic_settings_language.pngbin756 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/ic_subtype_keyboard.pngbin644 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_background.9.pngbin214 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_background_gb.9.png (renamed from java/res/drawable-mdpi/keyboard_dark_background.9.png)bin196 -> 196 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.pngbin1313 -> 1383 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_left_background_holo.9.pngbin1297 -> 1305 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_holo.9.pngbin1437 -> 1425 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.pngbin1457 -> 1454 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_right_background_holo.9.pngbin1288 -> 1314 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_holo.9.pngbin1423 -> 1427 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png (renamed from java/res/drawable-mdpi/keyboard_popup_panel_background.9.png)bin1726 -> 1726 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.pngbin571 -> 590 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png (renamed from java/res/drawable-mdpi/keyboard_suggest_strip.9.png)bin205 -> 205 bytes
-rw-r--r--java/res/drawable-mdpi/suggestions_strip_divider.pngbin264 -> 324 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_delete.pngbin800 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_label_mic.pngbin539 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_mic.pngbin838 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_return.pngbin834 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_search.pngbin1042 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_settings.pngbin729 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_shift.pngbin998 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_shift_locked.pngbin787 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_space.pngbin411 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_tab.pngbin627 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_bkeyboard_voice_off.pngbin1587 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_delete.pngbin3432 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_delete_holo.pngbin813 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_delete_holo_dark.pngbin0 -> 773 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_label_mic.pngbin542 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_label_mic_holo.pngbin576 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.pngbin0 -> 498 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_language_switch.pngbin1113 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_language_switch_dark.pngbin0 -> 1121 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_mic.pngbin3439 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.pngbin0 -> 590 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_mic_holo_light.pngbin0 -> 525 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_return.pngbin3380 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_return_holo.pngbin870 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_return_holo_dark.pngbin0 -> 796 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_search.pngbin3535 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_search_holo.pngbin991 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_search_holo_dark.pngbin0 -> 861 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_settings.pngbin3448 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_settings_holo.pngbin585 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.pngbin0 -> 708 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift.pngbin3217 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift_holo.pngbin940 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift_holo_dark.pngbin0 -> 756 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift_locked.pngbin3188 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.pngbin850 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_shift_locked_holo_dark.pngbin0 -> 668 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_smiley_holo_dark.pngbin0 -> 897 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_space_holo.pngbin505 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_space_holo_dark.pngbin0 -> 505 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png (renamed from java/res/drawable-mdpi/sym_keyboard_space_led.9.png)bin365 -> 365 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_tab.pngbin3269 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_tab_holo.pngbin801 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_tab_holo_dark.pngbin0 -> 752 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_voice_holo_dark.png (renamed from java/res/drawable-mdpi/sym_keyboard_voice_holo.png)bin1166 -> 1166 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_voice_off_holo_dark.png (renamed from java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png)bin1105 -> 1105 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_zwj_holo.pngbin733 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_zwj_holo_dark.pngbin0 -> 746 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_zwnj_holo.pngbin704 -> 0 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_zwnj_holo_dark.pngbin0 -> 721 bytes
-rw-r--r--java/res/drawable-mdpi/tab_selected.9.pngbin0 -> 140 bytes
-rw-r--r--java/res/drawable-mdpi/tab_unselected.9.pngbin0 -> 138 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_active_holo.9.pngbin601 -> 589 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.pngbin568 -> 589 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.pngbin722 -> 732 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.pngbin745 -> 787 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.pngbin737 -> 657 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.pngbin953 -> 848 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.pngbin945 -> 867 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_normal.9.pngbin1441 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_pressed.9.pngbin1869 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.pngbin591 -> 594 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.pngbin668 -> 634 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal_off_stone.9.pngbin2833 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal_on_stone.9.pngbin2867 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_normal_stone.9.pngbin2658 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_holo.9.pngbin351 -> 323 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_dark.pngbin2631 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_nature_light_activated.pngbin0 -> 2437 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_nature_light_normal.pngbin0 -> 2371 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_objects_light_activated.pngbin0 -> 2319 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_objects_light_normal.pngbin0 -> 2074 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_light_activated.pngbin0 -> 2519 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_light_normal.png (renamed from java/res/drawable-xhdpi/ic_emoji_light.png)bin2526 -> 2526 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_light_activated.pngbin0 -> 1828 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_light_normal.pngbin0 -> 1667 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recent_light_activated.pngbin0 -> 2459 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recent_light_normal.pngbin0 -> 2346 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_symbols_light_activated.pngbin0 -> 1457 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_symbols_light_normal.pngbin0 -> 1267 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_ime_switcher_dark.pngbin0 -> 1276 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_settings_language.pngbin1267 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_subtype_keyboard.pngbin1056 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_subtype_mic_dark.pngbin0 -> 1259 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_background.9.pngbin222 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_background_gb.9.png (renamed from java/res/drawable-xhdpi/keyboard_dark_background.9.png)bin241 -> 241 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_background_holo.9.pngbin2916 -> 3326 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_left_background_holo.9.pngbin2873 -> 3169 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_holo.9.pngbin3176 -> 3374 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_more_background_holo.9.pngbin3184 -> 3525 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_right_background_holo.9.pngbin2818 -> 3218 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_holo.9.pngbin3102 -> 3424 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png (renamed from java/res/drawable-xhdpi/keyboard_popup_panel_background.9.png)bin1365 -> 1365 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.pngbin1178 -> 1249 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png (renamed from java/res/drawable-xhdpi/keyboard_suggest_strip.9.png)bin289 -> 289 bytes
-rw-r--r--java/res/drawable-xhdpi/suggestions_strip_divider.pngbin267 -> 330 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_delete.pngbin2413 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_label_mic.pngbin2112 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_mic.pngbin2090 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_return.pngbin2018 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_search.pngbin2889 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_settings.pngbin2539 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_shift.pngbin2640 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_shift_locked.pngbin2076 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_space.pngbin1072 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_tab.pngbin1544 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_bkeyboard_voice_off.pngbin1137 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_delete.pngbin4589 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_delete_holo.pngbin1584 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_delete_holo_dark.pngbin0 -> 1318 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_label_mic.pngbin2086 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_label_mic_holo.pngbin929 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_language_switch.pngbin2512 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_language_switch_dark.pngbin0 -> 2505 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_mic.pngbin4487 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.pngbin0 -> 942 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_return.pngbin4559 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_return_holo.pngbin1452 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_return_holo_dark.pngbin0 -> 1206 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_search.pngbin4990 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_search_holo.pngbin2070 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_search_holo_dark.pngbin0 -> 1576 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_settings.pngbin4639 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_settings_holo.pngbin1062 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.pngbin0 -> 1309 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift.pngbin4186 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift_holo.pngbin1592 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift_holo_dark.pngbin0 -> 1090 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift_locked.pngbin4119 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo.pngbin1295 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo_dark.pngbin0 -> 860 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_smiley_holo_dark.pngbin0 -> 1851 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_space_holo.pngbin675 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_space_holo_dark.pngbin0 -> 646 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png (renamed from java/res/drawable-xhdpi/sym_keyboard_space_led.9.png)bin617 -> 617 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_tab.pngbin4157 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_tab_holo.pngbin1336 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_tab_holo_dark.pngbin0 -> 1179 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_voice_holo_dark.png (renamed from java/res/drawable-xhdpi/sym_keyboard_voice_holo.png)bin2393 -> 2393 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_voice_off_holo_dark.png (renamed from java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png)bin2196 -> 2196 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_zwj_holo.pngbin1185 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_zwj_holo_dark.pngbin0 -> 1184 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_zwnj_holo.pngbin1148 -> 0 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_zwnj_holo_dark.pngbin0 -> 1171 bytes
-rw-r--r--java/res/drawable-xhdpi/tab_selected.9.pngbin0 -> 148 bytes
-rw-r--r--java/res/drawable-xhdpi/tab_unselected.9.pngbin0 -> 155 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_active_holo.9.pngbin1805 -> 1718 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_holo.9.pngbin1693 -> 1718 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_holo.9.pngbin1913 -> 1905 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_holo.9.pngbin2039 -> 1998 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_holo.9.pngbin1863 -> 1861 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_holo.9.pngbin2196 -> 2073 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_holo.9.pngbin2210 -> 2091 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_light_normal_holo.9.pngbin1775 -> 1787 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_holo.9.pngbin1840 -> 1799 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_holo.9.pngbin1293 -> 1261 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_nature_light_activated.pngbin0 -> 3150 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_nature_light_normal.pngbin0 -> 2999 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_objects_light_activated.pngbin0 -> 2831 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_objects_light_normal.pngbin0 -> 2656 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_light_activated.pngbin0 -> 3118 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_light_normal.pngbin0 -> 3097 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_light_activated.pngbin0 -> 2256 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_light_normal.pngbin0 -> 2169 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recent_light_activated.pngbin0 -> 3152 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recent_light_normal.pngbin0 -> 2943 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_symbols_light_activated.pngbin0 -> 1939 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_symbols_light_normal.pngbin0 -> 1784 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_ime_switcher_dark.pngbin0 -> 1309 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_subtype_keyboard.pngbin1218 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_subtype_mic_dark.pngbin0 -> 1846 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_background_holo.9.pngbin5212 -> 7452 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_holo.9.pngbin4941 -> 7089 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_holo.9.pngbin5188 -> 7197 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_holo.9.pngbin5373 -> 5450 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_holo.9.pngbin4964 -> 7023 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_holo.9.pngbin5118 -> 7153 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_popup_panel_background_holo.9.pngbin2712 -> 2722 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_delete_holo.pngbin2860 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_delete_holo_dark.pngbin0 -> 1729 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_label_mic_holo.pngbin615 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_language_switch.pngbin3031 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_language_switch_dark.pngbin0 -> 3251 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.pngbin0 -> 1566 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_return_holo.pngbin2788 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_return_holo_dark.pngbin0 -> 1717 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_search_holo.pngbin4210 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_search_holo_dark.pngbin0 -> 2208 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_settings_holo.pngbin1455 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.pngbin0 -> 1471 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_shift_holo.pngbin2855 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_shift_holo_dark.pngbin0 -> 1427 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo.pngbin2346 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo_dark.pngbin0 -> 1367 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_smiley_holo_dark.pngbin0 -> 2571 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_space_holo.pngbin1499 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_space_holo_dark.pngbin0 -> 1186 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_tab_holo.pngbin2671 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_tab_holo_dark.pngbin0 -> 1577 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_voice_holo_dark.png (renamed from java/res/drawable-xxhdpi/sym_keyboard_voice_holo.png)bin3102 -> 3102 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo_dark.png (renamed from java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo.png)bin2749 -> 2749 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_zwj_holo.pngbin1436 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_zwj_holo_dark.pngbin0 -> 1589 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo.pngbin1452 -> 0 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo_dark.pngbin0 -> 1591 bytes
-rw-r--r--java/res/drawable-xxhdpi/tab_selected.9.pngbin0 -> 1030 bytes
-rw-r--r--java/res/drawable-xxhdpi/tab_unselected.9.pngbin0 -> 1048 bytes
-rw-r--r--java/res/drawable/btn_keyboard_key.xml37
-rw-r--r--java/res/drawable/btn_keyboard_key3.xml37
-rw-r--r--java/res/drawable/btn_keyboard_key_functional_gb.xml22
-rw-r--r--java/res/drawable/btn_keyboard_key_functional_ics.xml22
-rw-r--r--java/res/drawable/btn_keyboard_key_gb.xml (renamed from java/res/drawable/btn_keyboard_key_gingerbread.xml)0
-rw-r--r--java/res/drawable/btn_keyboard_key_popup_gb.xml (renamed from java/res/drawable/btn_keyboard_key_popup.xml)0
-rw-r--r--java/res/drawable/btn_keyboard_key_stone.xml49
-rw-r--r--java/res/drawable/btn_suggestion_gb.xml (renamed from java/res/drawable/btn_suggestion.xml)0
-rw-r--r--java/res/drawable/ic_emoji_nature_light.xml33
-rw-r--r--java/res/drawable/ic_emoji_objects_light.xml32
-rw-r--r--java/res/drawable/ic_emoji_people_light.xml32
-rw-r--r--java/res/drawable/ic_emoji_places_light.xml32
-rw-r--r--java/res/drawable/ic_emoji_recent_light.xml32
-rw-r--r--java/res/drawable/ic_emoji_symbols_light.xml32
-rw-r--r--java/res/drawable/keyboard_key_feedback_gb.xml (renamed from java/res/drawable/keyboard_key_feedback.xml)0
-rw-r--r--java/res/layout/emoji_keyboard_page.xml33
-rw-r--r--java/res/layout/emoji_keyboard_tab_icon.xml (renamed from java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml)14
-rw-r--r--java/res/layout/emoji_keyboard_tab_label.xml (renamed from java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml)14
-rw-r--r--java/res/layout/emoji_keyboard_view.xml110
-rw-r--r--java/res/layout/hint_add_to_dictionary.xml2
-rw-r--r--java/res/layout/input_view.xml49
-rw-r--r--java/res/layout/key_preview_gb.xml (renamed from java/res/layout/key_preview.xml)2
-rw-r--r--java/res/layout/more_keys_keyboard.xml22
-rw-r--r--java/res/layout/more_suggestions.xml28
-rw-r--r--java/res/layout/suggestion_info.xml2
-rw-r--r--java/res/layout/suggestion_word.xml2
-rw-r--r--java/res/raw/main_en.dictbin1069840 -> 1069840 bytes
-rw-r--r--java/res/raw/main_fr.dictbin1329175 -> 1329186 bytes
-rw-r--r--java/res/raw/main_pt_br.dictbin1091988 -> 1092045 bytes
-rw-r--r--java/res/raw/main_ru.dictbin2229294 -> 2229294 bytes
-rw-r--r--java/res/values-af/strings.xml2
-rw-r--r--java/res/values-am/strings.xml2
-rw-r--r--java/res/values-ar/strings.xml2
-rw-r--r--java/res/values-az-rAZ/strings-appname.xml27
-rw-r--r--java/res/values-az-rAZ/strings.xml244
-rw-r--r--java/res/values-az/strings-appname.xml27
-rw-r--r--java/res/values-az/strings.xml242
-rw-r--r--java/res/values-be/strings.xml4
-rw-r--r--java/res/values-bg/strings.xml2
-rw-r--r--java/res/values-ca/strings.xml2
-rw-r--r--java/res/values-cs/strings.xml2
-rw-r--r--java/res/values-da/strings.xml2
-rw-r--r--java/res/values-de/strings.xml2
-rw-r--r--java/res/values-el/strings.xml2
-rw-r--r--java/res/values-en-rGB/strings.xml16
-rw-r--r--java/res/values-en-rIN/strings-appname.xml27
-rw-r--r--java/res/values-en-rIN/strings.xml244
-rw-r--r--java/res/values-es-rUS/strings.xml2
-rw-r--r--java/res/values-es/strings.xml2
-rw-r--r--java/res/values-et-rEE/strings-appname.xml27
-rw-r--r--java/res/values-et-rEE/strings.xml244
-rw-r--r--java/res/values-fa/strings.xml6
-rw-r--r--java/res/values-fi/strings.xml88
-rw-r--r--java/res/values-fr-rCA/donottranslate.xml31
-rw-r--r--java/res/values-fr-rCA/strings-appname.xml27
-rw-r--r--java/res/values-fr-rCA/strings.xml253
-rw-r--r--java/res/values-fr/strings.xml2
-rw-r--r--java/res/values-hi/strings.xml52
-rw-r--r--java/res/values-hr/strings.xml2
-rw-r--r--java/res/values-hu/strings.xml2
-rw-r--r--java/res/values-hy-rAM/strings-appname.xml27
-rw-r--r--java/res/values-hy-rAM/strings.xml244
-rw-r--r--java/res/values-hy/donottranslate.xml29
-rw-r--r--java/res/values-hy/strings-appname.xml27
-rw-r--r--java/res/values-hy/strings.xml242
-rw-r--r--java/res/values-in/strings.xml2
-rw-r--r--java/res/values-it/strings.xml2
-rw-r--r--java/res/values-iw/strings.xml38
-rw-r--r--java/res/values-ja/strings.xml2
-rw-r--r--java/res/values-ka-rGE/strings-appname.xml27
-rw-r--r--java/res/values-ka-rGE/strings.xml244
-rw-r--r--java/res/values-ka/strings-appname.xml27
-rw-r--r--java/res/values-km-rKH/strings-appname.xml27
-rw-r--r--java/res/values-km-rKH/strings.xml244
-rw-r--r--java/res/values-km/donottranslate.xml23
-rw-r--r--java/res/values-km/strings-appname.xml27
-rw-r--r--java/res/values-km/strings.xml242
-rw-r--r--java/res/values-ko/strings.xml2
-rw-r--r--java/res/values-land/dimens.xml21
-rw-r--r--java/res/values-lo-rLA/strings-appname.xml27
-rw-r--r--java/res/values-lo-rLA/strings.xml244
-rw-r--r--java/res/values-lo/donottranslate.xml23
-rw-r--r--java/res/values-lo/strings-appname.xml27
-rw-r--r--java/res/values-lo/strings.xml242
-rw-r--r--java/res/values-lt/strings.xml2
-rw-r--r--java/res/values-lv/strings.xml2
-rw-r--r--java/res/values-mn-rMN/strings-appname.xml27
-rw-r--r--java/res/values-mn-rMN/strings.xml244
-rw-r--r--java/res/values-ms-rMY/strings-appname.xml27
-rw-r--r--java/res/values-ms-rMY/strings.xml244
-rw-r--r--java/res/values-nb/strings.xml2
-rw-r--r--java/res/values-ne-rNP/strings-appname.xml27
-rw-r--r--java/res/values-ne-rNP/strings.xml244
-rw-r--r--java/res/values-ne/strings-appname.xml27
-rw-r--r--java/res/values-ne/strings.xml242
-rw-r--r--java/res/values-nl/strings.xml2
-rw-r--r--java/res/values-pl/strings.xml2
-rw-r--r--java/res/values-pt-rPT/strings.xml4
-rw-r--r--java/res/values-pt/strings.xml4
-rw-r--r--java/res/values-rm/strings.xml4
-rw-r--r--java/res/values-ro/strings.xml18
-rw-r--r--java/res/values-ru/strings.xml2
-rw-r--r--java/res/values-si-rLK/strings-appname.xml27
-rw-r--r--java/res/values-si-rLK/strings.xml244
-rw-r--r--java/res/values-si/strings-appname.xml27
-rw-r--r--java/res/values-si/strings.xml242
-rw-r--r--java/res/values-sk/strings.xml2
-rw-r--r--java/res/values-sl/strings.xml2
-rw-r--r--java/res/values-sr/strings.xml2
-rw-r--r--java/res/values-sv/strings.xml2
-rw-r--r--java/res/values-sw/strings.xml2
-rw-r--r--java/res/values-sw600dp-land/dimens.xml20
-rw-r--r--java/res/values-sw600dp/config.xml2
-rw-r--r--java/res/values-sw600dp/dimens.xml24
-rw-r--r--java/res/values-sw600dp/touch-position-correction.xml4
-rw-r--r--java/res/values-sw768dp-land/dimens.xml18
-rw-r--r--java/res/values-sw768dp/config.xml2
-rw-r--r--java/res/values-sw768dp/dimens.xml23
-rw-r--r--java/res/values-th/donottranslate.xml23
-rw-r--r--java/res/values-th/strings.xml2
-rw-r--r--java/res/values-tl/strings.xml2
-rw-r--r--java/res/values-tr/strings.xml2
-rw-r--r--java/res/values-uk/strings.xml2
-rw-r--r--java/res/values-v18/emoji-categories.xml909
-rw-r--r--java/res/values-v19/emoji-categories.xml909
-rw-r--r--java/res/values-vi/strings.xml2
-rw-r--r--java/res/values-zh-rCN/strings.xml2
-rw-r--r--java/res/values-zh-rHK/strings-appname.xml27
-rw-r--r--java/res/values-zh-rHK/strings.xml244
-rw-r--r--java/res/values-zh-rTW/strings.xml36
-rw-r--r--java/res/values-zu/strings.xml2
-rw-r--r--java/res/values/attrs.xml70
-rw-r--r--java/res/values/colors.xml87
-rw-r--r--java/res/values/config-additional-features.xml24
-rw-r--r--java/res/values/config.xml2
-rw-r--r--java/res/values/dimens.xml28
-rw-r--r--java/res/values/donottranslate.xml60
-rw-r--r--java/res/values/emoji-categories.xml127
-rw-r--r--java/res/values/keyboard-icons-black.xml44
-rw-r--r--java/res/values/keyboard-icons-ics.xml41
-rw-r--r--java/res/values/keyboard-icons-white.xml40
-rw-r--r--java/res/values/keypress-vibration-durations.xml4
-rw-r--r--java/res/values/setup-styles.xml30
-rw-r--r--java/res/values/strings.xml6
-rw-r--r--java/res/values/styles.xml415
-rw-r--r--java/res/values/themes-basic-highcontrast.xml29
-rw-r--r--java/res/values/themes-basic.xml29
-rw-r--r--java/res/values/themes-common.xml131
-rw-r--r--java/res/values/themes-gb.xml146
-rw-r--r--java/res/values/themes-gingerbread.xml29
-rw-r--r--java/res/values/themes-ics.xml166
-rw-r--r--java/res/values/themes-stone-bold.xml29
-rw-r--r--java/res/values/themes-stone.xml29
-rw-r--r--java/res/values/touch-position-correction.xml4
-rw-r--r--java/res/xml-sw600dp/key_apostrophe.xml49
-rw-r--r--java/res/xml-sw600dp/key_dash.xml49
-rw-r--r--java/res/xml-sw600dp/key_f1.xml5
-rw-r--r--java/res/xml-sw600dp/key_f2.xml45
-rw-r--r--java/res/xml-sw600dp/key_space_5kw.xml (renamed from java/res/xml-sw600dp/key_space.xml)0
-rw-r--r--java/res/xml-sw600dp/key_space_symbols.xml (renamed from java/res/xml/kbd_thai_symbols.xml)7
-rw-r--r--java/res/xml-sw600dp/key_styles_common.xml3
-rw-r--r--java/res/xml-sw600dp/keys_comma_period.xml46
-rw-r--r--java/res/xml-sw600dp/keys_exclamation_question.xml28
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty2_right3.xml32
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty3_right2.xml23
-rw-r--r--java/res/xml-sw600dp/keys_pcqwerty4_right3.xml44
-rw-r--r--java/res/xml-sw600dp/row_dvorak4.xml9
-rw-r--r--java/res/xml-sw600dp/row_hebrew4.xml44
-rw-r--r--java/res/xml-sw600dp/row_pcqwerty5.xml22
-rw-r--r--java/res/xml-sw600dp/row_qwerty4.xml6
-rw-r--r--java/res/xml-sw600dp/row_symbols4.xml48
-rw-r--r--java/res/xml-sw600dp/row_symbols_shift4.xml40
-rw-r--r--java/res/xml-sw600dp/rowkeys_pcqwerty1.xml172
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols2.xml75
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols3.xml57
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols_shift1.xml56
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols_shift2.xml52
-rw-r--r--java/res/xml-sw600dp/rowkeys_symbols_shift3.xml46
-rw-r--r--java/res/xml-sw600dp/rows_10_10_7_symbols_shift.xml60
-rw-r--r--java/res/xml-sw600dp/rows_armenian_phonetic.xml (renamed from java/res/xml-sw768dp/rows_colemak.xml)38
-rw-r--r--java/res/xml-sw600dp/rows_azerty.xml2
-rw-r--r--java/res/xml-sw600dp/rows_bulgarian.xml2
-rw-r--r--java/res/xml-sw600dp/rows_bulgarian_bds.xml2
-rw-r--r--java/res/xml-sw600dp/rows_colemak.xml2
-rw-r--r--java/res/xml-sw600dp/rows_east_slavic.xml2
-rw-r--r--java/res/xml-sw600dp/rows_georgian.xml2
-rw-r--r--java/res/xml-sw600dp/rows_greek.xml2
-rw-r--r--java/res/xml-sw600dp/rows_hebrew.xml2
-rw-r--r--java/res/xml-sw600dp/rows_hindi.xml2
-rw-r--r--java/res/xml-sw600dp/rows_khmer.xml (renamed from java/res/xml-sw768dp/rows_azerty.xml)46
-rw-r--r--java/res/xml-sw600dp/rows_lao.xml (renamed from java/res/xml-sw768dp/rows_georgian.xml)48
-rw-r--r--java/res/xml-sw600dp/rows_mongolian.xml2
-rw-r--r--java/res/xml-sw600dp/rows_nepali_romanized.xml (renamed from java/res/xml-sw600dp/rows_10_10_7_symbols.xml)25
-rw-r--r--java/res/xml-sw600dp/rows_nepali_traditional.xml (renamed from java/res/xml-sw768dp/rows_farsi.xml)30
-rw-r--r--java/res/xml-sw600dp/rows_nordic.xml2
-rw-r--r--java/res/xml-sw600dp/rows_pcqwerty.xml19
-rw-r--r--java/res/xml-sw600dp/rows_qwerty.xml2
-rw-r--r--java/res/xml-sw600dp/rows_qwertz.xml2
-rw-r--r--java/res/xml-sw600dp/rows_south_slavic.xml2
-rw-r--r--java/res/xml-sw600dp/rows_spanish.xml2
-rw-r--r--java/res/xml-sw600dp/rows_symbols.xml15
-rw-r--r--java/res/xml-sw600dp/rows_symbols_shift.xml17
-rw-r--r--java/res/xml-sw600dp/rows_thai.xml13
-rw-r--r--java/res/xml-sw768dp-land/kbd_phone_symbols.xml31
-rw-r--r--java/res/xml-sw768dp/kbd_number.xml28
-rw-r--r--java/res/xml-sw768dp/kbd_phone.xml28
-rw-r--r--java/res/xml-sw768dp/kbd_phone_symbols.xml29
-rw-r--r--java/res/xml-sw768dp/key_space.xml63
-rw-r--r--java/res/xml-sw768dp/key_styles_common.xml186
-rw-r--r--java/res/xml-sw768dp/row_dvorak4.xml51
-rw-r--r--java/res/xml-sw768dp/row_hebrew4.xml49
-rw-r--r--java/res/xml-sw768dp/row_pcqwerty5.xml59
-rw-r--r--java/res/xml-sw768dp/row_qwerty4.xml51
-rw-r--r--java/res/xml-sw768dp/row_symbols4.xml48
-rw-r--r--java/res/xml-sw768dp/row_symbols_shift4.xml38
-rw-r--r--java/res/xml-sw768dp/rows_10_10_7_symbols.xml69
-rw-r--r--java/res/xml-sw768dp/rows_10_10_7_symbols_shift.xml69
-rw-r--r--java/res/xml-sw768dp/rows_bulgarian.xml68
-rw-r--r--java/res/xml-sw768dp/rows_bulgarian_bds.xml68
-rw-r--r--java/res/xml-sw768dp/rows_dvorak.xml66
-rw-r--r--java/res/xml-sw768dp/rows_east_slavic.xml70
-rw-r--r--java/res/xml-sw768dp/rows_greek.xml70
-rw-r--r--java/res/xml-sw768dp/rows_hebrew.xml61
-rw-r--r--java/res/xml-sw768dp/rows_hindi.xml68
-rw-r--r--java/res/xml-sw768dp/rows_mongolian.xml68
-rw-r--r--java/res/xml-sw768dp/rows_nordic.xml71
-rw-r--r--java/res/xml-sw768dp/rows_number_normal.xml175
-rw-r--r--java/res/xml-sw768dp/rows_number_password.xml79
-rw-r--r--java/res/xml-sw768dp/rows_pcqwerty.xml71
-rw-r--r--java/res/xml-sw768dp/rows_pcqwerty_symbols.xml67
-rw-r--r--java/res/xml-sw768dp/rows_phone.xml138
-rw-r--r--java/res/xml-sw768dp/rows_qwerty.xml68
-rw-r--r--java/res/xml-sw768dp/rows_qwertz.xml68
-rw-r--r--java/res/xml-sw768dp/rows_south_slavic.xml68
-rw-r--r--java/res/xml-sw768dp/rows_spanish.xml69
-rw-r--r--java/res/xml-sw768dp/rows_symbols.xml68
-rw-r--r--java/res/xml-sw768dp/rows_symbols_shift.xml68
-rw-r--r--java/res/xml-sw768dp/rows_thai.xml74
-rw-r--r--java/res/xml-sw768dp/rows_thai_symbols.xml76
-rw-r--r--java/res/xml-sw768dp/rows_thai_symbols_shift.xml76
-rw-r--r--java/res/xml-v16/key_devanagari_sign_anusvara.xml (renamed from java/res/xml-v16/key_hindi3_shift_left.xml)10
-rw-r--r--java/res/xml-v16/key_devanagari_sign_candrabindu.xml48
-rw-r--r--java/res/xml-v16/key_devanagari_sign_nukta.xml (renamed from java/res/xml-v16/key_hindi3_right.xml)27
-rw-r--r--java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml (renamed from java/res/xml-v16/keys_hindi3_left2.xml)8
-rw-r--r--java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml55
-rw-r--r--java/res/xml-v16/keys_hindi1_left5.xml75
-rw-r--r--java/res/xml-v16/keys_hindi2_left5.xml59
-rw-r--r--java/res/xml-v16/keystyle_devanagari_sign_virama.xml (renamed from java/res/xml-v16/key_hindi3_shift_right.xml)13
-rw-r--r--java/res/xml-v16/keystyle_devanagari_sign_visarga.xml (renamed from java/res/xml-v16/key_hindi1_shift.xml)7
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml49
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml56
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml48
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_e.xml57
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml48
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml48
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml50
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml49
-rw-r--r--java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml49
-rw-r--r--java/res/xml/kbd_armenian_phonetic.xml (renamed from java/res/xml-sw768dp/kbd_thai_symbols_shift.xml)4
-rw-r--r--java/res/xml/kbd_emoji_category1.xml (renamed from java/res/xml-sw768dp-land/kbd_phone.xml)15
-rw-r--r--java/res/xml/kbd_emoji_category2.xml (renamed from java/res/xml-sw768dp-land/kbd_number.xml)15
-rw-r--r--java/res/xml/kbd_emoji_category3.xml (renamed from java/res/xml-sw600dp/kbd_10_10_7_symbols.xml)12
-rw-r--r--java/res/xml/kbd_emoji_category4.xml (renamed from java/res/xml-sw600dp/kbd_10_10_7_symbols_shift.xml)12
-rw-r--r--java/res/xml/kbd_emoji_category5.xml31
-rw-r--r--java/res/xml/kbd_emoji_category6.xml32
-rw-r--r--java/res/xml/kbd_emoji_recents.xml32
-rw-r--r--java/res/xml/kbd_khmer.xml (renamed from java/res/xml-sw768dp/kbd_thai_symbols.xml)4
-rw-r--r--java/res/xml/kbd_lao.xml (renamed from java/res/xml/kbd_pcqwerty_symbols.xml)4
-rw-r--r--java/res/xml/kbd_nepali_romanized.xml (renamed from java/res/xml/kbd_thai_symbols_shift.xml)5
-rw-r--r--java/res/xml/kbd_nepali_traditional.xml (renamed from java/res/xml/kbd_10_10_7_symbols_shift.xml)5
-rw-r--r--java/res/xml/key_armenian_sha.xml28
-rw-r--r--java/res/xml/key_armenian_xeh.xml28
-rw-r--r--java/res/xml/key_devanagari_sign_anusvara.xml (renamed from java/res/xml/key_hindi3_shift_left.xml)12
-rw-r--r--java/res/xml/key_devanagari_sign_candrabindu.xml (renamed from java/res/xml/key_hindi3_right.xml)30
-rw-r--r--java/res/xml/key_devanagari_sign_nukta.xml52
-rw-r--r--java/res/xml/key_devanagari_vowel_sign_candra_o.xml (renamed from java/res/xml/keys_hindi3_left2.xml)10
-rw-r--r--java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml58
-rw-r--r--java/res/xml/key_f2.xml (renamed from java/res/xml-sw768dp/key_settings.xml)9
-rw-r--r--java/res/xml/key_nepali_traditional_period.xml49
-rw-r--r--java/res/xml/key_space_3kw.xml (renamed from java/res/xml-sw768dp/key_shortcut.xml)15
-rw-r--r--java/res/xml/key_space_5kw.xml (renamed from java/res/xml/key_space.xml)4
-rw-r--r--java/res/xml/key_space_symbols.xml (renamed from java/res/xml/kbd_10_10_7_symbols.xml)7
-rw-r--r--java/res/xml/key_styles_common.xml48
-rw-r--r--java/res/xml/key_styles_currency.xml10
-rw-r--r--java/res/xml/key_symbols_period.xml47
-rw-r--r--java/res/xml/keyboard_layout_set_armenian_phonetic.xml42
-rw-r--r--java/res/xml/keyboard_layout_set_azerty.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_colemak.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_dvorak.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_emoji.xml44
-rw-r--r--java/res/xml/keyboard_layout_set_hebrew.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_khmer.xml58
-rw-r--r--java/res/xml/keyboard_layout_set_lao.xml58
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_romanized.xml58
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_traditional.xml58
-rw-r--r--java/res/xml/keyboard_layout_set_pcqwerty.xml6
-rw-r--r--java/res/xml/keyboard_layout_set_spanish.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_thai.xml4
-rw-r--r--java/res/xml/keys_comma_period.xml103
-rw-r--r--java/res/xml/keys_hindi1_left5.xml85
-rw-r--r--java/res/xml/keys_hindi2_left5.xml69
-rw-r--r--java/res/xml/keys_less_greater.xml4
-rw-r--r--java/res/xml/keys_pcqwerty2_right3.xml13
-rw-r--r--java/res/xml/keys_pcqwerty3_right2.xml7
-rw-r--r--java/res/xml/keys_pcqwerty4_right3.xml13
-rw-r--r--java/res/xml/keys_pcqwerty_symbols2.xml59
-rw-r--r--java/res/xml/keys_pcqwerty_symbols3.xml54
-rw-r--r--java/res/xml/keys_pcqwerty_symbols4.xml49
-rw-r--r--java/res/xml/keystyle_devanagari_sign_virama.xml (renamed from java/res/xml/key_hindi3_shift_right.xml)17
-rw-r--r--java/res/xml/keystyle_devanagari_sign_visarga.xml (renamed from java/res/xml/key_hindi1_shift.xml)7
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_aa.xml52
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_ai.xml59
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_au.xml50
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_e.xml59
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_i.xml51
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_ii.xml51
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_o.xml53
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_u.xml52
-rw-r--r--java/res/xml/keystyle_devanagari_vowel_sign_uu.xml52
-rw-r--r--java/res/xml/method.xml295
-rw-r--r--java/res/xml/prefs.xml8
-rw-r--r--java/res/xml/row_dvorak4.xml2
-rw-r--r--java/res/xml/row_pcqwerty5.xml55
-rw-r--r--java/res/xml/row_qwerty4.xml17
-rw-r--r--java/res/xml/row_symbols4.xml59
-rw-r--r--java/res/xml/row_symbols_shift4.xml35
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic1.xml84
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic2.xml66
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic3.xml (renamed from java/res/xml-sw768dp/rowkeys_thai_digits.xml)42
-rw-r--r--java/res/xml/rowkeys_armenian_phonetic4.xml52
-rw-r--r--java/res/xml/rowkeys_hindi1.xml60
-rw-r--r--java/res/xml/rowkeys_hindi2.xml36
-rw-r--r--java/res/xml/rowkeys_hindi3.xml26
-rw-r--r--java/res/xml/rowkeys_khmer1.xml194
-rw-r--r--java/res/xml/rowkeys_khmer2.xml144
-rw-r--r--java/res/xml/rowkeys_khmer3.xml138
-rw-r--r--java/res/xml/rowkeys_khmer4.xml113
-rw-r--r--java/res/xml/rowkeys_lao1.xml164
-rw-r--r--java/res/xml/rowkeys_lao2.xml127
-rw-r--r--java/res/xml/rowkeys_lao3.xml110
-rw-r--r--java/res/xml/rowkeys_lao4.xml103
-rw-r--r--java/res/xml/rowkeys_nepali_romanized1.xml177
-rw-r--r--java/res/xml/rowkeys_nepali_romanized2.xml126
-rw-r--r--java/res/xml/rowkeys_nepali_romanized3.xml114
-rw-r--r--java/res/xml/rowkeys_nepali_traditional1.xml175
-rw-r--r--java/res/xml/rowkeys_nepali_traditional2.xml139
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_left6.xml83
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_right3.xml65
-rw-r--r--java/res/xml/rowkeys_nepali_traditional3_right5.xml91
-rw-r--r--java/res/xml/rowkeys_pcqwerty1.xml120
-rw-r--r--java/res/xml/rowkeys_pcqwerty1_shift.xml (renamed from java/res/xml/keys_pcqwerty_symbols1.xml)25
-rw-r--r--java/res/xml/rowkeys_pcqwerty2.xml20
-rw-r--r--java/res/xml/rowkeys_pcqwerty3.xml18
-rw-r--r--java/res/xml/rowkeys_pcqwerty4.xml18
-rw-r--r--java/res/xml/rowkeys_symbols2.xml3
-rw-r--r--java/res/xml/rowkeys_symbols3.xml9
-rw-r--r--java/res/xml/rowkeys_symbols_shift1.xml18
-rw-r--r--java/res/xml/rowkeys_symbols_shift2.xml16
-rw-r--r--java/res/xml/rowkeys_symbols_shift3.xml20
-rw-r--r--java/res/xml/rows_armenian_phonetic.xml (renamed from java/res/xml-sw600dp/rows_pcqwerty_symbols.xml)43
-rw-r--r--java/res/xml/rows_khmer.xml56
-rw-r--r--java/res/xml/rows_lao.xml56
-rw-r--r--java/res/xml/rows_nepali_romanized.xml (renamed from java/res/xml-sw768dp/rows_arabic.xml)35
-rw-r--r--java/res/xml/rows_nepali_traditional.xml (renamed from java/res/xml/rows_pcqwerty_symbols.xml)32
-rw-r--r--java/res/xml/rows_pcqwerty.xml15
-rw-r--r--java/res/xml/rows_symbols.xml14
-rw-r--r--java/res/xml/rows_symbols_shift.xml12
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java4
-rw-r--r--java/src/com/android/inputmethod/compat/ActivityManagerCompatUtils.java46
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java67
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java768
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java90
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java13
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java50
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java55
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java13
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java85
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java223
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java25
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java131
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java107
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java39
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java251
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java212
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java66
-rw-r--r--java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java24
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java132
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java36
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java16
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java31
-rw-r--r--java/src/com/android/inputmethod/latin/DicTraverseSession.java10
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java67
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryCollection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryWriter.java15
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java604
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java147
-rw-r--r--java/src/com/android/inputmethod/latin/InputPointers.java11
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java750
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java75
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java30
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java86
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java62
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java9
-rw-r--r--java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java9
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java40
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoder.java819
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java624
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoder.java993
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java958
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java378
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java136
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictDecoder.java394
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictEncoder.java38
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java373
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java218
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java357
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java (renamed from java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java)6
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/SparseTable.java150
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java234
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java255
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java266
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java294
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java231
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java183
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java402
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java32
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java9
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java55
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java (renamed from java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java)50
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java11
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java9
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryPredictionDictionary.java13
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java2
-rw-r--r--java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java3
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java55
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsFragment.java20
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java52
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java14
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java2
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java2
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java37
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java4
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java8
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java71
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java (renamed from java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java)6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java11
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CollectionUtils.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java10
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java108
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java147
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java9
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java110
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java109
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java1
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TextRange.java4
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java48
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java12
-rw-r--r--java/src/com/android/inputmethod/research/JsonUtils.java2
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java2
-rw-r--r--native/jni/Android.mk18
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp133
-rw-r--r--native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp7
-rw-r--r--native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp (renamed from native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.cpp)12
-rw-r--r--native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h (renamed from native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.h)8
-rw-r--r--native/jni/jni_common.cpp6
-rw-r--r--native/jni/src/defines.h8
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h23
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h61
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_utils.cpp9
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp5
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_nodes_cache.h51
-rw-r--r--native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h4
-rw-r--r--native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h44
-rw-r--r--native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp31
-rw-r--r--native/jni/src/suggest/core/dictionary/bigram_dictionary.h2
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp21
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.h8
-rw-r--r--native/jni/src/suggest/core/dictionary/multi_bigram_map.h28
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_state.cpp5
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_state.h14
-rw-r--r--native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h15
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.cpp14
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.h23
-rw-r--r--native/jni/src/suggest/core/suggest.cpp42
-rw-r--r--native/jni/src/suggest/core/suggest.h2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h15
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp182
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h (renamed from native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h)78
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp62
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp336
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h81
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/binary_format.h470
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp10
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp149
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h178
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp83
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h69
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp313
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h45
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp215
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h286
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp41
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h29
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp511
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h128
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp147
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h76
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp116
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h80
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp215
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h117
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.cpp108
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.h76
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp326
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h36
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp86
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h93
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h123
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp20
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h22
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp103
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h103
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.cpp3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h133
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp107
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h50
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp26
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h6
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h (renamed from native/jni/src/suggest/policyimpl/dictionary/utils/mmaped_buffer.h)55
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h (renamed from native/jni/src/suggest/core/dictionary/probability_utils.h)2
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.h9
-rw-r--r--native/jni/src/utils/autocorrection_threshold_utils.cpp7
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java5
-rw-r--r--tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java628
-rw-r--r--tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java55
-rw-r--r--tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java18
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTests.java50
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java105
-rw-r--r--tests/src/com/android/inputmethod/latin/InputPointersTests.java16
-rw-r--r--tests/src/com/android/inputmethod/latin/InputTestsBase.java21
-rw-r--r--tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java42
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java415
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java193
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java65
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java160
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java (renamed from tests/src/com/android/inputmethod/latin/makedict/BinaryDictReaderTests.java)60
-rw-r--r--tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java167
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java73
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutorTests.java105
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java14
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/SpannableStringUtilsTests.java58
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java24
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java4
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java36
-rw-r--r--tools/dicttool/Android.mk2
-rw-r--r--tools/dicttool/NativeLib.mk2
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java16
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java4
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java39
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java8
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java16
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java4
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java6
-rw-r--r--tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java31
-rw-r--r--tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java11
-rw-r--r--tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java10
-rw-r--r--tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml40
-rw-r--r--tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml7
-rw-r--r--tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml29
-rw-r--r--tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml28
-rw-r--r--tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml63
-rw-r--r--tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values/donottranslate-more-keys.xml19
944 files changed, 29560 insertions, 11848 deletions
diff --git a/dictionaries/en_GB_wordlist.combined.gz b/dictionaries/en_GB_wordlist.combined.gz
index d28ef485b..afef676b2 100644
--- a/dictionaries/en_GB_wordlist.combined.gz
+++ b/dictionaries/en_GB_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/en_US_wordlist.combined.gz b/dictionaries/en_US_wordlist.combined.gz
index b656f880d..eafbc9d30 100644
--- a/dictionaries/en_US_wordlist.combined.gz
+++ b/dictionaries/en_US_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/en_wordlist.combined.gz b/dictionaries/en_wordlist.combined.gz
index 8aa40e944..9cbca0b41 100644
--- a/dictionaries/en_wordlist.combined.gz
+++ b/dictionaries/en_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/fr_wordlist.combined.gz b/dictionaries/fr_wordlist.combined.gz
index 0763b627c..1815e4732 100644
--- a/dictionaries/fr_wordlist.combined.gz
+++ b/dictionaries/fr_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/iw_wordlist.combined.gz b/dictionaries/iw_wordlist.combined.gz
new file mode 100644
index 000000000..36b047894
--- /dev/null
+++ b/dictionaries/iw_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/pt_BR_wordlist.combined.gz b/dictionaries/pt_BR_wordlist.combined.gz
index 0dd847244..876eb71c2 100644
--- a/dictionaries/pt_BR_wordlist.combined.gz
+++ b/dictionaries/pt_BR_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/pt_PT_wordlist.combined.gz b/dictionaries/pt_PT_wordlist.combined.gz
index 00d50d0c5..406869059 100644
--- a/dictionaries/pt_PT_wordlist.combined.gz
+++ b/dictionaries/pt_PT_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/ru_wordlist.combined.gz b/dictionaries/ru_wordlist.combined.gz
index 1c85d66eb..572314db6 100644
--- a/dictionaries/ru_wordlist.combined.gz
+++ b/dictionaries/ru_wordlist.combined.gz
Binary files differ
diff --git a/java/res/color/emoji_tab_label_color_gb.xml b/java/res/color/emoji_tab_label_color_gb.xml
new file mode 100644
index 000000000..e1d2f715e
--- /dev/null
+++ b/java/res/color/emoji_tab_label_color_gb.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:color="@color/key_text_color_gb" />
+ <item
+ android:state_pressed="true"
+ android:color="@color/key_text_color_gb" />
+ <item
+ android:state_selected="true"
+ android:color="@color/key_text_color_gb" />
+ <item
+ android:color="@color/key_text_inactivated_color_gb" />
+</selector>
diff --git a/java/res/color/emoji_tab_label_color_ics.xml b/java/res/color/emoji_tab_label_color_ics.xml
new file mode 100644
index 000000000..36e1d3020
--- /dev/null
+++ b/java/res/color/emoji_tab_label_color_ics.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:color="@color/key_text_color_ics" />
+ <item
+ android:state_pressed="true"
+ android:color="@color/key_text_color_ics" />
+ <item
+ android:state_selected="true"
+ android:color="@color/key_text_color_ics" />
+ <item
+ android:color="@color/key_text_inactivated_color_ics" />
+</selector>
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_active_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_active_holo.9.png
index 9aa8db60e..fa2cb8542 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_active_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_active_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
index 5e6a9d6a4..fa2cb8542 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
index a3ba2230d..b1af23b6c 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
index 9f4587b4a..814e40235 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
index 7ec33dd20..90abe3940 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
index 655bc01b1..48eeb3f54 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
index 138e915d9..71e0683cd 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png
deleted file mode 100644
index 116329016..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png
deleted file mode 100644
index 207c90d6c..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_fulltrans_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
index baff85873..6da273b09 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
index 5612c51a1..6768241a7 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png
deleted file mode 100644
index cdd6c8b79..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal_off_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png
deleted file mode 100644
index d8421746a..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal_on_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png b/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png
deleted file mode 100644
index 671d4e5d6..000000000
--- a/java/res/drawable-hdpi/btn_keyboard_key_normal_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png
index c2e8b3779..10f8e97e4 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_dark.png b/java/res/drawable-hdpi/ic_emoji_dark.png
deleted file mode 100644
index a9f18cde0..000000000
--- a/java/res/drawable-hdpi/ic_emoji_dark.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_nature_light_activated.png b/java/res/drawable-hdpi/ic_emoji_nature_light_activated.png
new file mode 100644
index 000000000..5525df2f7
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_nature_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_nature_light_normal.png b/java/res/drawable-hdpi/ic_emoji_nature_light_normal.png
new file mode 100644
index 000000000..34e16b9de
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_nature_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_objects_light_activated.png b/java/res/drawable-hdpi/ic_emoji_objects_light_activated.png
new file mode 100644
index 000000000..c3c7ec1b8
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_objects_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_objects_light_normal.png b/java/res/drawable-hdpi/ic_emoji_objects_light_normal.png
new file mode 100644
index 000000000..f012d7707
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_objects_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_people_light_activated.png b/java/res/drawable-hdpi/ic_emoji_people_light_activated.png
new file mode 100644
index 000000000..cfacbc2e7
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_people_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_light.png b/java/res/drawable-hdpi/ic_emoji_people_light_normal.png
index 2e3638bf3..c54dbc1f5 100644
--- a/java/res/drawable-hdpi/ic_emoji_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_people_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_light_activated.png b/java/res/drawable-hdpi/ic_emoji_places_light_activated.png
new file mode 100644
index 000000000..959dfdfd5
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_places_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_light_normal.png b/java/res/drawable-hdpi/ic_emoji_places_light_normal.png
new file mode 100644
index 000000000..fc0d9711d
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_places_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recent_light_activated.png b/java/res/drawable-hdpi/ic_emoji_recent_light_activated.png
new file mode 100644
index 000000000..de570a185
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_recent_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recent_light_normal.png b/java/res/drawable-hdpi/ic_emoji_recent_light_normal.png
new file mode 100644
index 000000000..b2562088d
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_recent_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_symbols_light_activated.png b/java/res/drawable-hdpi/ic_emoji_symbols_light_activated.png
new file mode 100644
index 000000000..af1fd27ec
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_symbols_light_activated.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_symbols_light_normal.png b/java/res/drawable-hdpi/ic_emoji_symbols_light_normal.png
new file mode 100644
index 000000000..02b84d51b
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_emoji_symbols_light_normal.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_ime_switcher_dark.png b/java/res/drawable-hdpi/ic_ime_switcher_dark.png
new file mode 100644
index 000000000..7506af5a3
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_ime_switcher_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_settings_language.png b/java/res/drawable-hdpi/ic_settings_language.png
deleted file mode 100644
index f635b2e7a..000000000
--- a/java/res/drawable-hdpi/ic_settings_language.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_subtype_keyboard.png b/java/res/drawable-hdpi/ic_subtype_keyboard.png
deleted file mode 100644
index 484305655..000000000
--- a/java/res/drawable-hdpi/ic_subtype_keyboard.png
+++ /dev/null
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
new file mode 100644
index 000000000..eacbcd255
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_subtype_mic_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_background.9.png b/java/res/drawable-hdpi/keyboard_background.9.png
deleted file mode 100644
index d57463fb6..000000000
--- a/java/res/drawable-hdpi/keyboard_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_dark_background.9.png b/java/res/drawable-hdpi/keyboard_background_gb.9.png
index fa3d449f7..fa3d449f7 100644
--- a/java/res/drawable-hdpi/keyboard_dark_background.9.png
+++ b/java/res/drawable-hdpi/keyboard_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png
index 28b406a5c..50ed568ff 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_holo.9.png
index e42cd88dc..9fa6d0003 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_left_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_holo.9.png
index 160344073..c73269b7e 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_holo.9.png
index a40d4277c..fffd4021e 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_holo.9.png
index 1f6807376..61c23c19b 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_right_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_holo.9.png
index ec53593d9..827d74363 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png
index baff80950..baff80950 100644
--- a/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png
+++ b/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
index 53d7b6fb3..dc2fc7dfc 100644
--- a/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png
index 7cab5a899..7cab5a899 100644
--- a/java/res/drawable-hdpi/keyboard_suggest_strip.9.png
+++ b/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
index e173beb73..32f426402 100644
--- a/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_delete.png b/java/res/drawable-hdpi/sym_bkeyboard_delete.png
deleted file mode 100644
index 1d24cc85c..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_label_mic.png b/java/res/drawable-hdpi/sym_bkeyboard_label_mic.png
deleted file mode 100644
index 25702cf73..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_mic.png b/java/res/drawable-hdpi/sym_bkeyboard_mic.png
deleted file mode 100644
index 512f46080..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_return.png b/java/res/drawable-hdpi/sym_bkeyboard_return.png
deleted file mode 100644
index 426e1599e..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_search.png b/java/res/drawable-hdpi/sym_bkeyboard_search.png
deleted file mode 100644
index 1b6f884fa..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_settings.png b/java/res/drawable-hdpi/sym_bkeyboard_settings.png
deleted file mode 100644
index 08ba18f28..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_shift.png b/java/res/drawable-hdpi/sym_bkeyboard_shift.png
deleted file mode 100644
index 5a22dd309..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png b/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png
deleted file mode 100644
index 566449126..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_space.png b/java/res/drawable-hdpi/sym_bkeyboard_space.png
deleted file mode 100644
index cd0ebe2f4..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_space.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_tab.png b/java/res/drawable-hdpi/sym_bkeyboard_tab.png
deleted file mode 100644
index 3466e1271..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_voice_off.png b/java/res/drawable-hdpi/sym_bkeyboard_voice_off.png
deleted file mode 100644
index 081a13096..000000000
--- a/java/res/drawable-hdpi/sym_bkeyboard_voice_off.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_delete.png b/java/res/drawable-hdpi/sym_keyboard_delete.png
deleted file mode 100644
index 0591b82cd..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_delete_holo.png b/java/res/drawable-hdpi/sym_keyboard_delete_holo.png
deleted file mode 100644
index d3e108846..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_delete_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_delete_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_delete_holo_dark.png
new file mode 100644
index 000000000..d2d3560a3
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_delete_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_label_mic.png b/java/res/drawable-hdpi/sym_keyboard_label_mic.png
deleted file mode 100644
index 4e0a8ed8e..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_label_mic_holo.png b/java/res/drawable-hdpi/sym_keyboard_label_mic_holo.png
deleted file mode 100644
index f8df44741..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_label_mic_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_language_switch.png b/java/res/drawable-hdpi/sym_keyboard_language_switch.png
deleted file mode 100644
index 7b980a0c8..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_language_switch.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_language_switch_dark.png b/java/res/drawable-hdpi/sym_keyboard_language_switch_dark.png
new file mode 100644
index 000000000..78d3a1fc5
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_language_switch_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_mic.png b/java/res/drawable-hdpi/sym_keyboard_mic.png
deleted file mode 100644
index 520a40f09..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png
new file mode 100644
index 000000000..3c5469403
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_return.png b/java/res/drawable-hdpi/sym_keyboard_return.png
deleted file mode 100644
index 9743c7f2f..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_return_holo.png b/java/res/drawable-hdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index 8978934b8..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_return_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_return_holo_dark.png
new file mode 100644
index 000000000..60d893cf3
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_return_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_search.png b/java/res/drawable-hdpi/sym_keyboard_search.png
deleted file mode 100644
index 8cd28c64a..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_search_holo.png b/java/res/drawable-hdpi/sym_keyboard_search_holo.png
deleted file mode 100644
index b987a20f1..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_search_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_search_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_search_holo_dark.png
new file mode 100644
index 000000000..fa0d1bde1
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_search_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_settings.png b/java/res/drawable-hdpi/sym_keyboard_settings.png
deleted file mode 100644
index 1e5bf939e..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_settings_holo.png b/java/res/drawable-hdpi/sym_keyboard_settings_holo.png
deleted file mode 100644
index 5af09ad8c..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_settings_holo.png
+++ /dev/null
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
new file mode 100644
index 000000000..c76008ab3
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_settings_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift.png b/java/res/drawable-hdpi/sym_keyboard_shift.png
deleted file mode 100644
index 8e3d0320c..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_holo.png b/java/res/drawable-hdpi/sym_keyboard_shift_holo.png
deleted file mode 100644
index c58f9ab5c..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_shift_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_shift_holo_dark.png
new file mode 100644
index 000000000..544b7e141
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_shift_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_locked.png b/java/res/drawable-hdpi/sym_keyboard_shift_locked.png
deleted file mode 100644
index d345634a6..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png
deleted file mode 100644
index 7a5c03713..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo_dark.png
new file mode 100644
index 000000000..9b1d6a015
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_holo.png b/java/res/drawable-hdpi/sym_keyboard_space_holo.png
deleted file mode 100644
index e8bc3902d..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_space_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_space_holo_dark.png
new file mode 100644
index 000000000..12e27ade7
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_space_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_led.9.png b/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png
index c76f64b94..c76f64b94 100644
--- a/java/res/drawable-hdpi/sym_keyboard_space_led.9.png
+++ b/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_tab.png b/java/res/drawable-hdpi/sym_keyboard_tab.png
deleted file mode 100644
index 3d1c5c0ea..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_tab_holo.png b/java/res/drawable-hdpi/sym_keyboard_tab_holo.png
deleted file mode 100644
index 8d10d057c..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_tab_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_tab_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_tab_holo_dark.png
new file mode 100644
index 000000000..2e5f811f3
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_tab_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_voice_holo.png b/java/res/drawable-hdpi/sym_keyboard_voice_holo_dark.png
index 8a6336a57..8a6336a57 100644
--- a/java/res/drawable-hdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-hdpi/sym_keyboard_voice_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-hdpi/sym_keyboard_voice_off_holo_dark.png
index edf1379ab..edf1379ab 100644
--- a/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-hdpi/sym_keyboard_voice_off_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_zwj_holo.png b/java/res/drawable-hdpi/sym_keyboard_zwj_holo.png
deleted file mode 100644
index 5fa30ceb8..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_zwj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_zwj_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_zwj_holo_dark.png
new file mode 100644
index 000000000..9f9bc173b
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_zwj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_zwnj_holo.png b/java/res/drawable-hdpi/sym_keyboard_zwnj_holo.png
deleted file mode 100644
index 91367f3d2..000000000
--- a/java/res/drawable-hdpi/sym_keyboard_zwnj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_zwnj_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_zwnj_holo_dark.png
new file mode 100644
index 000000000..f0f832e13
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_zwnj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/tab_selected.9.png b/java/res/drawable-hdpi/tab_selected.9.png
new file mode 100644
index 000000000..84e63df17
--- /dev/null
+++ b/java/res/drawable-hdpi/tab_selected.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/tab_unselected.9.png b/java/res/drawable-hdpi/tab_unselected.9.png
new file mode 100644
index 000000000..bbcfb2c64
--- /dev/null
+++ b/java/res/drawable-hdpi/tab_unselected.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_active_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_active_holo.9.png
index e810c7789..8e9a34957 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_active_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_active_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
index d449d7600..8e9a34957 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
index fa24d5987..58a316fba 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
index f3fc64114..b7b2dca43 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
index 8f340d355..4a92b80dd 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
index 53ea5f894..72125a065 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
index 69c84e7ec..82413d4cc 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png
deleted file mode 100644
index 4b1a78cfb..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png
deleted file mode 100644
index 697683e29..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_fulltrans_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
index 976083fdf..2915588bf 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
index c39dd4a94..049385984 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png
deleted file mode 100644
index cdd6c8b79..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal_off_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png
deleted file mode 100644
index d8421746a..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal_on_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png b/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png
deleted file mode 100644
index 73cf35df0..000000000
--- a/java/res/drawable-mdpi/btn_keyboard_key_normal_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png
index 93a6e7921..ee0aae28b 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_dark.png b/java/res/drawable-mdpi/ic_emoji_dark.png
deleted file mode 100644
index d0047a437..000000000
--- a/java/res/drawable-mdpi/ic_emoji_dark.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_nature_light_activated.png b/java/res/drawable-mdpi/ic_emoji_nature_light_activated.png
new file mode 100644
index 000000000..d4c8d8da8
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_nature_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_nature_light_normal.png b/java/res/drawable-mdpi/ic_emoji_nature_light_normal.png
new file mode 100644
index 000000000..1555aa7a9
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_nature_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_objects_light_activated.png b/java/res/drawable-mdpi/ic_emoji_objects_light_activated.png
new file mode 100644
index 000000000..081dc66c2
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_objects_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_objects_light_normal.png b/java/res/drawable-mdpi/ic_emoji_objects_light_normal.png
new file mode 100644
index 000000000..58e6f6e75
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_objects_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_people_light_activated.png b/java/res/drawable-mdpi/ic_emoji_people_light_activated.png
new file mode 100644
index 000000000..067ad5496
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_people_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_light.png b/java/res/drawable-mdpi/ic_emoji_people_light_normal.png
index a3195041a..d835d4ec7 100644
--- a/java/res/drawable-mdpi/ic_emoji_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_people_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_light_activated.png b/java/res/drawable-mdpi/ic_emoji_places_light_activated.png
new file mode 100644
index 000000000..1aecec598
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_places_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_light_normal.png b/java/res/drawable-mdpi/ic_emoji_places_light_normal.png
new file mode 100644
index 000000000..c70e484e1
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_places_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recent_light_activated.png b/java/res/drawable-mdpi/ic_emoji_recent_light_activated.png
new file mode 100644
index 000000000..8009e932f
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_recent_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recent_light_normal.png b/java/res/drawable-mdpi/ic_emoji_recent_light_normal.png
new file mode 100644
index 000000000..c2e598dfb
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_recent_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_symbols_light_activated.png b/java/res/drawable-mdpi/ic_emoji_symbols_light_activated.png
new file mode 100644
index 000000000..caea87191
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_symbols_light_activated.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_symbols_light_normal.png b/java/res/drawable-mdpi/ic_emoji_symbols_light_normal.png
new file mode 100644
index 000000000..0edada626
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_emoji_symbols_light_normal.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_ime_switcher_dark.png b/java/res/drawable-mdpi/ic_ime_switcher_dark.png
new file mode 100644
index 000000000..152f65300
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_ime_switcher_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_settings_language.png b/java/res/drawable-mdpi/ic_settings_language.png
deleted file mode 100644
index f8aca679b..000000000
--- a/java/res/drawable-mdpi/ic_settings_language.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_subtype_keyboard.png b/java/res/drawable-mdpi/ic_subtype_keyboard.png
deleted file mode 100644
index d28efc106..000000000
--- a/java/res/drawable-mdpi/ic_subtype_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background.9.png b/java/res/drawable-mdpi/keyboard_background.9.png
deleted file mode 100644
index 2bd4b628d..000000000
--- a/java/res/drawable-mdpi/keyboard_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_dark_background.9.png b/java/res/drawable-mdpi/keyboard_background_gb.9.png
index 4f81704c4..4f81704c4 100644
--- a/java/res/drawable-mdpi/keyboard_dark_background.9.png
+++ b/java/res/drawable-mdpi/keyboard_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png
index 7a9f640d1..564f5460c 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_holo.9.png
index 5b06f09bb..427c87061 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_left_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_holo.9.png
index fd992d6f4..ea757296d 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png
index 128dcd6ad..1911c429f 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_holo.9.png
index 0b08d1747..cdef116d2 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_right_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_holo.9.png
index cf0b33c1d..dea5d076c 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png
index 0d9ab97f0..0d9ab97f0 100644
--- a/java/res/drawable-mdpi/keyboard_popup_panel_background.9.png
+++ b/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
index 61988a8e1..441edc30b 100644
--- a/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png
index fa6c0feff..fa6c0feff 100644
--- a/java/res/drawable-mdpi/keyboard_suggest_strip.9.png
+++ b/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/suggestions_strip_divider.png b/java/res/drawable-mdpi/suggestions_strip_divider.png
index 2dbe2f94b..21e904939 100644
--- a/java/res/drawable-mdpi/suggestions_strip_divider.png
+++ b/java/res/drawable-mdpi/suggestions_strip_divider.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_delete.png b/java/res/drawable-mdpi/sym_bkeyboard_delete.png
deleted file mode 100644
index 1a5ff439e..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_label_mic.png b/java/res/drawable-mdpi/sym_bkeyboard_label_mic.png
deleted file mode 100644
index 7f0b1355f..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_mic.png b/java/res/drawable-mdpi/sym_bkeyboard_mic.png
deleted file mode 100644
index a6cb1cc01..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_return.png b/java/res/drawable-mdpi/sym_bkeyboard_return.png
deleted file mode 100644
index e76225d0f..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_search.png b/java/res/drawable-mdpi/sym_bkeyboard_search.png
deleted file mode 100644
index 1f180155d..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_settings.png b/java/res/drawable-mdpi/sym_bkeyboard_settings.png
deleted file mode 100644
index 08ba18f28..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_shift.png b/java/res/drawable-mdpi/sym_bkeyboard_shift.png
deleted file mode 100644
index c981188dd..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png b/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png
deleted file mode 100644
index b8cebd060..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_space.png b/java/res/drawable-mdpi/sym_bkeyboard_space.png
deleted file mode 100644
index 4da7ee86e..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_space.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_tab.png b/java/res/drawable-mdpi/sym_bkeyboard_tab.png
deleted file mode 100644
index 2cb991cbf..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_voice_off.png b/java/res/drawable-mdpi/sym_bkeyboard_voice_off.png
deleted file mode 100644
index 081a13096..000000000
--- a/java/res/drawable-mdpi/sym_bkeyboard_voice_off.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_delete.png b/java/res/drawable-mdpi/sym_keyboard_delete.png
deleted file mode 100644
index 1b0f3f836..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_delete_holo.png b/java/res/drawable-mdpi/sym_keyboard_delete_holo.png
deleted file mode 100644
index 86be35185..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_delete_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_delete_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_delete_holo_dark.png
new file mode 100644
index 000000000..edd9d164e
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_delete_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_label_mic.png b/java/res/drawable-mdpi/sym_keyboard_label_mic.png
deleted file mode 100644
index a354d5321..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_label_mic_holo.png b/java/res/drawable-mdpi/sym_keyboard_label_mic_holo.png
deleted file mode 100644
index 15606e95f..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_label_mic_holo.png
+++ /dev/null
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
new file mode 100644
index 000000000..537f39b02
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_label_mic_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_language_switch.png b/java/res/drawable-mdpi/sym_keyboard_language_switch.png
deleted file mode 100644
index f840a631d..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_language_switch.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_language_switch_dark.png b/java/res/drawable-mdpi/sym_keyboard_language_switch_dark.png
new file mode 100644
index 000000000..828929bc8
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_language_switch_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_mic.png b/java/res/drawable-mdpi/sym_keyboard_mic.png
deleted file mode 100644
index e926b3fa6..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png
new file mode 100644
index 000000000..5e58866a7
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png
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
new file mode 100644
index 000000000..84a63dc7f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_mic_holo_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_return.png b/java/res/drawable-mdpi/sym_keyboard_return.png
deleted file mode 100644
index 0c10f004a..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_return_holo.png b/java/res/drawable-mdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index bfcb91328..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_return_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_return_holo_dark.png
new file mode 100644
index 000000000..e10103caf
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_return_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_search.png b/java/res/drawable-mdpi/sym_keyboard_search.png
deleted file mode 100644
index 614f85f5e..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_search_holo.png b/java/res/drawable-mdpi/sym_keyboard_search_holo.png
deleted file mode 100644
index dd3c83a84..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_search_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_search_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_search_holo_dark.png
new file mode 100644
index 000000000..290cde41b
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_search_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_settings.png b/java/res/drawable-mdpi/sym_keyboard_settings.png
deleted file mode 100644
index ad7618fa0..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_settings_holo.png b/java/res/drawable-mdpi/sym_keyboard_settings_holo.png
deleted file mode 100644
index 36c8c9623..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_settings_holo.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
new file mode 100644
index 000000000..a76a976c5
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_settings_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift.png b/java/res/drawable-mdpi/sym_keyboard_shift.png
deleted file mode 100644
index 5109b0471..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_holo.png b/java/res/drawable-mdpi/sym_keyboard_shift_holo.png
deleted file mode 100644
index 621946455..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_shift_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_shift_holo_dark.png
new file mode 100644
index 000000000..37375d935
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_shift_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_locked.png b/java/res/drawable-mdpi/sym_keyboard_shift_locked.png
deleted file mode 100644
index 244179c2d..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png
deleted file mode 100644
index fb3a020d8..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo_dark.png
new file mode 100644
index 000000000..3654868dc
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_smiley_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_smiley_holo_dark.png
new file mode 100644
index 000000000..71272bb88
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_smiley_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_holo.png b/java/res/drawable-mdpi/sym_keyboard_space_holo.png
deleted file mode 100644
index 1f787d573..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_space_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_space_holo_dark.png
new file mode 100644
index 000000000..a38f99496
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_space_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_led.9.png b/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png
index 1c1ca2cc7..1c1ca2cc7 100644
--- a/java/res/drawable-mdpi/sym_keyboard_space_led.9.png
+++ b/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_tab.png b/java/res/drawable-mdpi/sym_keyboard_tab.png
deleted file mode 100644
index eddb9a592..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_tab_holo.png b/java/res/drawable-mdpi/sym_keyboard_tab_holo.png
deleted file mode 100644
index 8d20153ee..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_tab_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_tab_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_tab_holo_dark.png
new file mode 100644
index 000000000..f883807f2
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_tab_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_voice_holo.png b/java/res/drawable-mdpi/sym_keyboard_voice_holo_dark.png
index 0795fcc9b..0795fcc9b 100644
--- a/java/res/drawable-mdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-mdpi/sym_keyboard_voice_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-mdpi/sym_keyboard_voice_off_holo_dark.png
index f76da5797..f76da5797 100644
--- a/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-mdpi/sym_keyboard_voice_off_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_zwj_holo.png b/java/res/drawable-mdpi/sym_keyboard_zwj_holo.png
deleted file mode 100644
index 70370d83d..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_zwj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_zwj_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_zwj_holo_dark.png
new file mode 100644
index 000000000..8957e282b
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_zwj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_zwnj_holo.png b/java/res/drawable-mdpi/sym_keyboard_zwnj_holo.png
deleted file mode 100644
index a69eade17..000000000
--- a/java/res/drawable-mdpi/sym_keyboard_zwnj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_zwnj_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_zwnj_holo_dark.png
new file mode 100644
index 000000000..5f49e64aa
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_zwnj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/tab_selected.9.png b/java/res/drawable-mdpi/tab_selected.9.png
new file mode 100644
index 000000000..4b00f350a
--- /dev/null
+++ b/java/res/drawable-mdpi/tab_selected.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/tab_unselected.9.png b/java/res/drawable-mdpi/tab_unselected.9.png
new file mode 100644
index 000000000..bb45ab960
--- /dev/null
+++ b/java/res/drawable-mdpi/tab_unselected.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_active_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_active_holo.9.png
index d990c0258..a2f6ac0e2 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_active_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_active_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png
index d2cd029bb..a2f6ac0e2 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
index bca39cf17..2f00fc623 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
index ab8fb2e86..20251a000 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png
index 3871689ef..84d173967 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
index 912506368..ee4490eac 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
index 35ce67fdc..e8124776c 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_normal.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_normal.9.png
deleted file mode 100644
index f7e32f764..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_pressed.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_pressed.9.png
deleted file mode 100644
index df3b5ba2d..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_fulltrans_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png
index b26f1d27a..0ef4a4b5f 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png
index c23a4b225..f770962c3 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal_off_stone.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal_off_stone.9.png
deleted file mode 100644
index dec219304..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_off_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal_on_stone.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal_on_stone.9.png
deleted file mode 100644
index 3c77b3ccd..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_on_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_normal_stone.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_normal_stone.9.png
deleted file mode 100644
index 5cdfc4201..000000000
--- a/java/res/drawable-xhdpi/btn_keyboard_key_normal_stone.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_holo.9.png
index 0c7bfdace..891d00024 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_holo.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_dark.png b/java/res/drawable-xhdpi/ic_emoji_dark.png
deleted file mode 100644
index 22daec22e..000000000
--- a/java/res/drawable-xhdpi/ic_emoji_dark.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_nature_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_nature_light_activated.png
new file mode 100644
index 000000000..3e6744343
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_nature_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_nature_light_normal.png b/java/res/drawable-xhdpi/ic_emoji_nature_light_normal.png
new file mode 100644
index 000000000..5344a9ee9
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_nature_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_objects_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_objects_light_activated.png
new file mode 100644
index 000000000..75695d43d
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_objects_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_objects_light_normal.png b/java/res/drawable-xhdpi/ic_emoji_objects_light_normal.png
new file mode 100644
index 000000000..2adb186e6
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_objects_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_people_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_people_light_activated.png
new file mode 100644
index 000000000..e6baa2e59
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_people_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_light.png b/java/res/drawable-xhdpi/ic_emoji_people_light_normal.png
index 21bc9090d..c26aa4efb 100644
--- a/java/res/drawable-xhdpi/ic_emoji_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_people_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_places_light_activated.png
new file mode 100644
index 000000000..eaa3b86cf
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_places_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_light_normal.png b/java/res/drawable-xhdpi/ic_emoji_places_light_normal.png
new file mode 100644
index 000000000..d6e1eaa35
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_places_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recent_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_recent_light_activated.png
new file mode 100644
index 000000000..06003b82d
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_recent_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recent_light_normal.png b/java/res/drawable-xhdpi/ic_emoji_recent_light_normal.png
new file mode 100644
index 000000000..da2effedb
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_recent_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_symbols_light_activated.png b/java/res/drawable-xhdpi/ic_emoji_symbols_light_activated.png
new file mode 100644
index 000000000..438fde2b4
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_symbols_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_symbols_light_normal.png b/java/res/drawable-xhdpi/ic_emoji_symbols_light_normal.png
new file mode 100644
index 000000000..757863233
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_emoji_symbols_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_ime_switcher_dark.png b/java/res/drawable-xhdpi/ic_ime_switcher_dark.png
new file mode 100644
index 000000000..c567077e5
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_ime_switcher_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_settings_language.png b/java/res/drawable-xhdpi/ic_settings_language.png
deleted file mode 100644
index 2c42db3aa..000000000
--- a/java/res/drawable-xhdpi/ic_settings_language.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_subtype_keyboard.png b/java/res/drawable-xhdpi/ic_subtype_keyboard.png
deleted file mode 100644
index a79bb3458..000000000
--- a/java/res/drawable-xhdpi/ic_subtype_keyboard.png
+++ /dev/null
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
new file mode 100644
index 000000000..17581ba89
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_subtype_mic_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_background.9.png b/java/res/drawable-xhdpi/keyboard_background.9.png
deleted file mode 100644
index 263996322..000000000
--- a/java/res/drawable-xhdpi/keyboard_background.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_dark_background.9.png b/java/res/drawable-xhdpi/keyboard_background_gb.9.png
index 27b7a108c..27b7a108c 100644
--- a/java/res/drawable-xhdpi/keyboard_dark_background.9.png
+++ b/java/res/drawable-xhdpi/keyboard_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_holo.9.png
index d999127f2..e8c65f677 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_holo.9.png
index c4d694136..543bc763e 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_holo.9.png
index 5429c1785..ec42aadb6 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_holo.9.png
index 5135a0869..319e9d7cf 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_holo.9.png
index 19a77a29f..052032be7 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_holo.9.png
index ae2ffff8e..c7e9d1c9e 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png
index 79f7ab00a..79f7ab00a 100644
--- a/java/res/drawable-xhdpi/keyboard_popup_panel_background.9.png
+++ b/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png
index 1dee699f4..dde1856e3 100644
--- a/java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png
index 1b568df03..1b568df03 100644
--- a/java/res/drawable-xhdpi/keyboard_suggest_strip.9.png
+++ b/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/suggestions_strip_divider.png b/java/res/drawable-xhdpi/suggestions_strip_divider.png
index 0d8b98437..4101ebc59 100644
--- a/java/res/drawable-xhdpi/suggestions_strip_divider.png
+++ b/java/res/drawable-xhdpi/suggestions_strip_divider.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_delete.png b/java/res/drawable-xhdpi/sym_bkeyboard_delete.png
deleted file mode 100644
index b84ee76dc..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_label_mic.png b/java/res/drawable-xhdpi/sym_bkeyboard_label_mic.png
deleted file mode 100644
index 9bd1d65b4..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_mic.png b/java/res/drawable-xhdpi/sym_bkeyboard_mic.png
deleted file mode 100644
index 8c3f11dd4..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_return.png b/java/res/drawable-xhdpi/sym_bkeyboard_return.png
deleted file mode 100644
index 1632ecd8e..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_search.png b/java/res/drawable-xhdpi/sym_bkeyboard_search.png
deleted file mode 100644
index 69d8b22d1..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_settings.png b/java/res/drawable-xhdpi/sym_bkeyboard_settings.png
deleted file mode 100644
index 050154a3a..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_shift.png b/java/res/drawable-xhdpi/sym_bkeyboard_shift.png
deleted file mode 100644
index d15d11a50..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_shift_locked.png b/java/res/drawable-xhdpi/sym_bkeyboard_shift_locked.png
deleted file mode 100644
index 83b287fea..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_space.png b/java/res/drawable-xhdpi/sym_bkeyboard_space.png
deleted file mode 100644
index 5ca62c7b7..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_space.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_tab.png b/java/res/drawable-xhdpi/sym_bkeyboard_tab.png
deleted file mode 100644
index 6ca199755..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_bkeyboard_voice_off.png b/java/res/drawable-xhdpi/sym_bkeyboard_voice_off.png
deleted file mode 100644
index fc6a4eb59..000000000
--- a/java/res/drawable-xhdpi/sym_bkeyboard_voice_off.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_delete.png b/java/res/drawable-xhdpi/sym_keyboard_delete.png
deleted file mode 100644
index 3c0b8b186..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_delete.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_delete_holo.png b/java/res/drawable-xhdpi/sym_keyboard_delete_holo.png
deleted file mode 100644
index 354c09ee6..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_delete_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_delete_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_delete_holo_dark.png
new file mode 100644
index 000000000..e3e37d5ff
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_delete_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_label_mic.png b/java/res/drawable-xhdpi/sym_keyboard_label_mic.png
deleted file mode 100644
index 49810a02f..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_label_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_label_mic_holo.png b/java/res/drawable-xhdpi/sym_keyboard_label_mic_holo.png
deleted file mode 100644
index 8eeb179f5..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_label_mic_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_language_switch.png b/java/res/drawable-xhdpi/sym_keyboard_language_switch.png
deleted file mode 100644
index 6c2fb53ec..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_language_switch.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_language_switch_dark.png b/java/res/drawable-xhdpi/sym_keyboard_language_switch_dark.png
new file mode 100644
index 000000000..b8687f550
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_language_switch_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_mic.png b/java/res/drawable-xhdpi/sym_keyboard_mic.png
deleted file mode 100644
index 1323b6d1e..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png
new file mode 100644
index 000000000..566ba1fcd
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_return.png b/java/res/drawable-xhdpi/sym_keyboard_return.png
deleted file mode 100644
index ad061227e..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_return.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_return_holo.png b/java/res/drawable-xhdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index ba424adfd..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_return_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_return_holo_dark.png
new file mode 100644
index 000000000..7b7ad1747
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_return_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_search.png b/java/res/drawable-xhdpi/sym_keyboard_search.png
deleted file mode 100644
index aa785a221..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_search.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_search_holo.png b/java/res/drawable-xhdpi/sym_keyboard_search_holo.png
deleted file mode 100644
index f2fb2a2b5..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_search_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_search_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_search_holo_dark.png
new file mode 100644
index 000000000..36b1646bb
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_search_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_settings.png b/java/res/drawable-xhdpi/sym_keyboard_settings.png
deleted file mode 100644
index 50704255d..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_settings.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_settings_holo.png b/java/res/drawable-xhdpi/sym_keyboard_settings_holo.png
deleted file mode 100644
index 99ee97dbf..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_settings_holo.png
+++ /dev/null
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
new file mode 100644
index 000000000..05eaffe2e
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_settings_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift.png b/java/res/drawable-xhdpi/sym_keyboard_shift.png
deleted file mode 100644
index 290170619..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_shift.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift_holo.png b/java/res/drawable-xhdpi/sym_keyboard_shift_holo.png
deleted file mode 100644
index 1046b4545..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_shift_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_shift_holo_dark.png
new file mode 100644
index 000000000..5ab549114
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_shift_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift_locked.png b/java/res/drawable-xhdpi/sym_keyboard_shift_locked.png
deleted file mode 100644
index a5deb60e9..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_shift_locked.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo.png
deleted file mode 100644
index 6acb565d9..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo_dark.png
new file mode 100644
index 000000000..b820eaabb
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_shift_locked_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_smiley_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_smiley_holo_dark.png
new file mode 100644
index 000000000..686831fd3
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_smiley_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_holo.png b/java/res/drawable-xhdpi/sym_keyboard_space_holo.png
deleted file mode 100644
index 504a3ed45..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_space_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_space_holo_dark.png
new file mode 100644
index 000000000..7114b740f
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_space_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_led.9.png b/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png
index 6525fefab..6525fefab 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_space_led.9.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_tab.png b/java/res/drawable-xhdpi/sym_keyboard_tab.png
deleted file mode 100644
index 0ef2ab5b9..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_tab.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_tab_holo.png b/java/res/drawable-xhdpi/sym_keyboard_tab_holo.png
deleted file mode 100644
index ff380eeab..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_tab_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_tab_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_tab_holo_dark.png
new file mode 100644
index 000000000..73ebfe525
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_tab_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png b/java/res/drawable-xhdpi/sym_keyboard_voice_holo_dark.png
index b2bb9b803..b2bb9b803 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_voice_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo_dark.png
index 23e75bfe7..23e75bfe7 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_zwj_holo.png b/java/res/drawable-xhdpi/sym_keyboard_zwj_holo.png
deleted file mode 100644
index 26694274e..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_zwj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_zwj_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_zwj_holo_dark.png
new file mode 100644
index 000000000..2f9607add
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_zwj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo.png b/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo.png
deleted file mode 100644
index 75a22b65f..000000000
--- a/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo_dark.png
new file mode 100644
index 000000000..ab07f7549
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_zwnj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/tab_selected.9.png b/java/res/drawable-xhdpi/tab_selected.9.png
new file mode 100644
index 000000000..95e5f4341
--- /dev/null
+++ b/java/res/drawable-xhdpi/tab_selected.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/tab_unselected.9.png b/java/res/drawable-xhdpi/tab_unselected.9.png
new file mode 100644
index 000000000..8cede8d5e
--- /dev/null
+++ b/java/res/drawable-xhdpi/tab_unselected.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_active_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_active_holo.9.png
index 680421eaf..17f0a7a58 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_active_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_active_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_holo.9.png
index ae2675053..17f0a7a58 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
index c92a669f9..b0e815eb2 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
index 40f5011c0..97f96258e 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_holo.9.png
index 6ff6319d3..dfb16a76b 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
index 818ea70fd..bf1d34686 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
index a476d2a9e..962277165 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_light_normal_holo.9.png
index 9c280a655..4ddfdcb6c 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_light_normal_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_holo.9.png
index 3c17c5eec..17144b673 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_holo.9.png
index 6d2af5942..0cbb2ec84 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_holo.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_nature_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_nature_light_activated.png
new file mode 100644
index 000000000..470fd695c
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_nature_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_nature_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_nature_light_normal.png
new file mode 100644
index 000000000..a7fde0ec5
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_nature_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_objects_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_objects_light_activated.png
new file mode 100644
index 000000000..c582b704a
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_objects_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_objects_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_objects_light_normal.png
new file mode 100644
index 000000000..acc95d725
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_objects_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_people_light_activated.png
new file mode 100644
index 000000000..5973ac355
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_people_light_normal.png
new file mode 100644
index 000000000..22e06f808
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_places_light_activated.png
new file mode 100644
index 000000000..690e95fd5
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_places_light_normal.png
new file mode 100644
index 000000000..ced4b08cf
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recent_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_recent_light_activated.png
new file mode 100644
index 000000000..25e847ef3
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_recent_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recent_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_recent_light_normal.png
new file mode 100644
index 000000000..c86368d73
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_recent_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_symbols_light_activated.png b/java/res/drawable-xxhdpi/ic_emoji_symbols_light_activated.png
new file mode 100644
index 000000000..29dfc7118
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_symbols_light_activated.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_symbols_light_normal.png b/java/res/drawable-xxhdpi/ic_emoji_symbols_light_normal.png
new file mode 100644
index 000000000..0570567cf
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_emoji_symbols_light_normal.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_ime_switcher_dark.png b/java/res/drawable-xxhdpi/ic_ime_switcher_dark.png
new file mode 100644
index 000000000..f99f7d0c7
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_ime_switcher_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_subtype_keyboard.png b/java/res/drawable-xxhdpi/ic_subtype_keyboard.png
deleted file mode 100644
index 0bb4283b0..000000000
--- a/java/res/drawable-xxhdpi/ic_subtype_keyboard.png
+++ /dev/null
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
new file mode 100644
index 000000000..811103a56
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_subtype_mic_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_holo.9.png
index bd1ef3cd9..11eee94f3 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_holo.9.png
index 65af4b569..2079e0462 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_holo.9.png
index ac6750dcb..c4178d9a8 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_holo.9.png
index cea7c05f6..121411a06 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_holo.9.png
index 520fa7c6b..d3d8733fd 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_holo.9.png
index eee221758..d7ec8bcb2 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_holo.9.png
index 721c24400..ca576deaf 100644
--- a/java/res/drawable-xxhdpi/keyboard_popup_panel_background_holo.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_delete_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_delete_holo.png
deleted file mode 100644
index be3cb7ce7..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_delete_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_delete_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_delete_holo_dark.png
new file mode 100644
index 000000000..92be79241
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_delete_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_label_mic_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_label_mic_holo.png
deleted file mode 100644
index b6d4477bd..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_label_mic_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_language_switch.png b/java/res/drawable-xxhdpi/sym_keyboard_language_switch.png
deleted file mode 100644
index 7cd0684a0..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_language_switch.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_language_switch_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_language_switch_dark.png
new file mode 100644
index 000000000..88b55bb37
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_language_switch_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png
new file mode 100644
index 000000000..f55af308c
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_return_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index 7d9580796..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_return_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_return_holo_dark.png
new file mode 100644
index 000000000..46ee50eba
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_return_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_search_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_search_holo.png
deleted file mode 100644
index 6b09d8e57..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_search_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_search_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_search_holo_dark.png
new file mode 100644
index 000000000..f518748ce
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_search_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_settings_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_settings_holo.png
deleted file mode 100644
index 7041bb6ce..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_settings_holo.png
+++ /dev/null
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
new file mode 100644
index 000000000..e4358463b
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_settings_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_shift_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_shift_holo.png
deleted file mode 100644
index 2b4fbbba6..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_shift_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_shift_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_shift_holo_dark.png
new file mode 100644
index 000000000..523286e6e
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_shift_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo.png
deleted file mode 100644
index 91c8603fd..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo_dark.png
new file mode 100644
index 000000000..87926d9a6
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_shift_locked_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_smiley_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_smiley_holo_dark.png
new file mode 100644
index 000000000..04b721617
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_smiley_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_space_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_space_holo.png
deleted file mode 100644
index 65aa5ea9b..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_space_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_space_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_space_holo_dark.png
new file mode 100644
index 000000000..1dab1f431
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_space_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_tab_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_tab_holo.png
deleted file mode 100644
index 1f4ae3df7..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_tab_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_tab_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_tab_holo_dark.png
new file mode 100644
index 000000000..6eb3eb0b3
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_tab_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_voice_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_voice_holo_dark.png
index f04cadf6f..f04cadf6f 100644
--- a/java/res/drawable-xxhdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-xxhdpi/sym_keyboard_voice_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo_dark.png
index e74d523bc..e74d523bc 100644
--- a/java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-xxhdpi/sym_keyboard_voice_off_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo.png
deleted file mode 100644
index 85289b2a3..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo_dark.png
new file mode 100644
index 000000000..5e225b837
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_zwj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo.png b/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo.png
deleted file mode 100644
index e610678b1..000000000
--- a/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo_dark.png
new file mode 100644
index 000000000..cdfc0295b
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_zwnj_holo_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/tab_selected.9.png b/java/res/drawable-xxhdpi/tab_selected.9.png
new file mode 100644
index 000000000..e5efc5828
--- /dev/null
+++ b/java/res/drawable-xxhdpi/tab_selected.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/tab_unselected.9.png b/java/res/drawable-xxhdpi/tab_unselected.9.png
new file mode 100644
index 000000000..389188695
--- /dev/null
+++ b/java/res/drawable-xxhdpi/tab_unselected.9.png
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_key.xml b/java/res/drawable/btn_keyboard_key.xml
deleted file mode 100644
index 112ac2636..000000000
--- a/java/res/drawable/btn_keyboard_key.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Toggle keys. Use checkable/checked state. -->
- <item android:state_checkable="true" android:state_checked="true"
- android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_pressed_on" />
- <item android:state_checkable="true" android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_pressed_off" />
- <item android:state_checkable="true" android:state_checked="true"
- android:drawable="@drawable/btn_keyboard_key_normal_on" />
- <item android:state_checkable="true"
- android:drawable="@drawable/btn_keyboard_key_normal_off" />
-
- <!-- Empty background keys. -->
- <item android:state_empty="true"
- android:drawable="@drawable/transparent" />
-
- <!-- Normal keys. -->
- <item android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_pressed" />
- <item android:drawable="@drawable/btn_keyboard_key_normal" />
-</selector>
diff --git a/java/res/drawable/btn_keyboard_key3.xml b/java/res/drawable/btn_keyboard_key3.xml
deleted file mode 100644
index 080b1f326..000000000
--- a/java/res/drawable/btn_keyboard_key3.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Toggle keys. Use checkable/checked state. -->
- <item android:state_checkable="true" android:state_checked="true"
- android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_pressed_on" />
- <item android:state_checkable="true" android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_normal" />
- <item android:state_checkable="true" android:state_checked="true"
- android:drawable="@drawable/btn_keyboard_key_normal_on" />
- <item android:state_checkable="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
-
- <!-- Empty background keys. -->
- <item android:state_empty="true"
- android:drawable="@drawable/transparent" />
-
- <!-- Normal keys. -->
- <item android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_normal" />
- <item android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
-</selector>
diff --git a/java/res/drawable/btn_keyboard_key_functional_gb.xml b/java/res/drawable/btn_keyboard_key_functional_gb.xml
new file mode 100644
index 000000000..431359c20
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_functional_gb.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Functional keys. -->
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_dark_pressed" />
+ <item android:drawable="@drawable/btn_keyboard_key_dark_normal" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_functional_ics.xml b/java/res/drawable/btn_keyboard_key_functional_ics.xml
new file mode 100644
index 000000000..5dcde5fa9
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_functional_ics.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Functional keys. -->
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_dark_pressed_holo" />
+ <item android:drawable="@drawable/btn_keyboard_key_dark_normal_holo" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_gingerbread.xml b/java/res/drawable/btn_keyboard_key_gb.xml
index 3fc253e85..3fc253e85 100644
--- a/java/res/drawable/btn_keyboard_key_gingerbread.xml
+++ b/java/res/drawable/btn_keyboard_key_gb.xml
diff --git a/java/res/drawable/btn_keyboard_key_popup.xml b/java/res/drawable/btn_keyboard_key_popup_gb.xml
index 9e3670d22..9e3670d22 100644
--- a/java/res/drawable/btn_keyboard_key_popup.xml
+++ b/java/res/drawable/btn_keyboard_key_popup_gb.xml
diff --git a/java/res/drawable/btn_keyboard_key_stone.xml b/java/res/drawable/btn_keyboard_key_stone.xml
deleted file mode 100644
index 70a2ad444..000000000
--- a/java/res/drawable/btn_keyboard_key_stone.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Functional keys. -->
- <item android:state_single="true" android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
- <item android:state_single="true"
- android:drawable="@drawable/btn_keyboard_key_normal_stone" />
-
- <!-- Action keys. -->
- <item android:state_active="true" android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
- <item android:state_active="true"
- android:drawable="@drawable/btn_keyboard_key_normal_stone" />
-
- <!-- Toggle keys. Use checkable/checked state. -->
- <item android:state_checkable="true" android:state_checked="true"
- android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_normal_on_stone" />
- <item android:state_checkable="true" android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_normal_off_stone" />
- <item android:state_checkable="true" android:state_checked="true"
- android:drawable="@drawable/btn_keyboard_key_normal_on_stone" />
- <item android:state_checkable="true"
- android:drawable="@drawable/btn_keyboard_key_normal_off_stone" />
-
- <!-- Empty background keys. -->
- <item android:state_empty="true"
- android:drawable="@drawable/transparent" />
-
- <!-- Normal keys. -->
- <item android:state_pressed="true"
- android:drawable="@drawable/btn_keyboard_key_fulltrans_pressed" />
- <item android:drawable="@drawable/btn_keyboard_key_normal_stone" />
-</selector>
diff --git a/java/res/drawable/btn_suggestion.xml b/java/res/drawable/btn_suggestion_gb.xml
index cde12fe55..cde12fe55 100644
--- a/java/res/drawable/btn_suggestion.xml
+++ b/java/res/drawable/btn_suggestion_gb.xml
diff --git a/java/res/drawable/ic_emoji_nature_light.xml b/java/res/drawable/ic_emoji_nature_light.xml
new file mode 100644
index 000000000..543409e03
--- /dev/null
+++ b/java/res/drawable/ic_emoji_nature_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_nature_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_nature_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_nature_light_activated" />
+ <item
+ android:drawable="@drawable/ic_emoji_nature_light_normal" />
+</selector>
diff --git a/java/res/drawable/ic_emoji_objects_light.xml b/java/res/drawable/ic_emoji_objects_light.xml
new file mode 100644
index 000000000..4096e695b
--- /dev/null
+++ b/java/res/drawable/ic_emoji_objects_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_objects_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_objects_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_objects_light_activated" />
+ <item android:drawable="@drawable/ic_emoji_objects_light_normal" />
+</selector>
diff --git a/java/res/drawable/ic_emoji_people_light.xml b/java/res/drawable/ic_emoji_people_light.xml
new file mode 100644
index 000000000..ea9e406a4
--- /dev/null
+++ b/java/res/drawable/ic_emoji_people_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_people_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_people_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_people_light_activated" />
+ <item android:drawable="@drawable/ic_emoji_people_light_normal" />
+</selector>
diff --git a/java/res/drawable/ic_emoji_places_light.xml b/java/res/drawable/ic_emoji_places_light.xml
new file mode 100644
index 000000000..312cad9c3
--- /dev/null
+++ b/java/res/drawable/ic_emoji_places_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_places_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_places_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_places_light_activated" />
+ <item android:drawable="@drawable/ic_emoji_places_light_normal" />
+</selector>
diff --git a/java/res/drawable/ic_emoji_recent_light.xml b/java/res/drawable/ic_emoji_recent_light.xml
new file mode 100644
index 000000000..8c2123f83
--- /dev/null
+++ b/java/res/drawable/ic_emoji_recent_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_recent_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_recent_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_recent_light_activated" />
+ <item android:drawable="@drawable/ic_emoji_recent_light_normal" />
+</selector>
diff --git a/java/res/drawable/ic_emoji_symbols_light.xml b/java/res/drawable/ic_emoji_symbols_light.xml
new file mode 100644
index 000000000..79aaf0fc5
--- /dev/null
+++ b/java/res/drawable/ic_emoji_symbols_light.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.
+*/
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/ic_emoji_symbols_light_activated" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/ic_emoji_symbols_light_activated" />
+ <item
+ android:state_selected="true"
+ android:drawable="@drawable/ic_emoji_symbols_light_activated" />
+ <item android:drawable="@drawable/ic_emoji_symbols_light_normal" />
+</selector>
diff --git a/java/res/drawable/keyboard_key_feedback.xml b/java/res/drawable/keyboard_key_feedback_gb.xml
index 397e948d8..397e948d8 100644
--- a/java/res/drawable/keyboard_key_feedback.xml
+++ b/java/res/drawable/keyboard_key_feedback_gb.xml
diff --git a/java/res/layout/emoji_keyboard_page.xml b/java/res/layout/emoji_keyboard_page.xml
new file mode 100644
index 000000000..e0b752b32
--- /dev/null
+++ b/java/res/layout/emoji_keyboard_page.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.
+*/
+-->
+
+<com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier
+ 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>
diff --git a/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml b/java/res/layout/emoji_keyboard_tab_icon.xml
index f593fa944..d79276eb9 100644
--- a/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml
+++ b/java/res/layout/emoji_keyboard_tab_icon.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,9 +18,9 @@
*/
-->
-<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyWidth="3.5%p"
- latin:rowHeight="@dimen/popup_key_height"
- style="?attr/moreKeysKeyboardStyle"
- >
-</Keyboard>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+/>
diff --git a/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml b/java/res/layout/emoji_keyboard_tab_label.xml
index f89a0a673..62c552dd8 100644
--- a/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml
+++ b/java/res/layout/emoji_keyboard_tab_label.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2008, 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,9 +18,9 @@
*/
-->
-<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyWidth="5.0%p"
- latin:rowHeight="@dimen/popup_key_height"
- style="?attr/moreKeysKeyboardStyle"
- >
-</Keyboard>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+/>
diff --git a/java/res/layout/emoji_keyboard_view.xml b/java/res/layout/emoji_keyboard_view.xml
new file mode 100644
index 000000000..4566a5a1f
--- /dev/null
+++ b/java/res/layout/emoji_keyboard_view.xml
@@ -0,0 +1,110 @@
+<?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.
+*/
+-->
+
+<com.android.inputmethod.keyboard.EmojiKeyboardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/emoji_keyboard_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?attr/emojiKeyboardViewStyle"
+>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/suggestions_strip_height"
+ >
+ <TabHost
+ android:id="@+id/emoji_category_tabhost"
+ android:layout_width="0dip"
+ android:layout_weight="87.5"
+ android:layout_height="match_parent"
+ >
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/tab_selected"
+ android:divider="@null"
+ android:tabStripEnabled="true"
+ android:tabStripLeft="@drawable/tab_unselected"
+ android:tabStripRight="@drawable/tab_unselected" />
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="0dip"
+ android:layout_height="0dip"
+ >
+ <!-- Empty placeholder that TabHost requires. But we don't use it to actually
+ display anything. We monitor the tab changes and change the ViewPager.
+ Similarly the ViewPager swipes are intercepted and passed to the TabHost. -->
+ <View
+ android:id="@+id/emoji_keyboard_dummy"
+ android:layout_width="0dip"
+ android:layout_height="0dip"
+ android:visibility="gone" />
+ </FrameLayout>
+ </TabHost>
+ <View
+ android:layout_width="2dip"
+ android:layout_height="match_parent"
+ android:background="@drawable/suggestions_strip_divider" />
+ <ImageButton
+ android:id="@+id/emoji_keyboard_delete"
+ android:layout_width="0dip"
+ android:layout_weight="12.5"
+ android:layout_height="match_parent"
+ android:background="@color/emoji_key_background_color"
+ android:src="@drawable/sym_keyboard_delete_holo_dark" />
+ </LinearLayout>
+ <android.support.v4.view.ViewPager
+ android:id="@+id/emoji_keyboard_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <com.android.inputmethod.keyboard.EmojiCategoryPageIndicatorView
+ android:id="@+id/emoji_category_page_id_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/emoji_category_page_id_view_background" />
+ <LinearLayout
+ android:id="@+id/emoji_action_bar"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ >
+ <ImageButton
+ android:id="@+id/emoji_keyboard_alphabet"
+ android:layout_width="0dip"
+ android:layout_weight="0.15"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_ime_switcher_dark" />
+ <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_send"
+ android:layout_width="0dip"
+ android:layout_weight="0.15"
+ android:layout_height="match_parent"
+ android:src="@drawable/sym_keyboard_return_holo_dark" />
+ </LinearLayout>
+</com.android.inputmethod.keyboard.EmojiKeyboardView>
diff --git a/java/res/layout/hint_add_to_dictionary.xml b/java/res/layout/hint_add_to_dictionary.xml
index 73de44fae..68a9faf19 100644
--- a/java/res/layout/hint_add_to_dictionary.xml
+++ b/java/res/layout/hint_add_to_dictionary.xml
@@ -33,4 +33,4 @@
android:clickable="false"
android:singleLine="true"
android:ellipsize="none"
- style="?attr/suggestionBackgroundStyle" />
+ style="?attr/suggestionWordStyle" />
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 78217b01a..0b682d198 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -20,26 +20,41 @@
<com.android.inputmethod.latin.InputView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom|center_horizontal"
->
- <!-- To ensure that key preview popup is correctly placed when the current system locale is
- one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
- <com.android.inputmethod.latin.suggestions.SuggestionStripView
- android:id="@+id/suggestion_strip_view"
- android:layoutDirection="ltr"
+ android:orientation="vertical" >
+ <!-- The height of key_preview_backing view will automatically be determined by code. -->
+ <View
+ android:id="@+id/key_preview_backing"
android:layout_width="match_parent"
- android:layout_height="@dimen/suggestions_strip_height"
- android:paddingRight="@dimen/suggestions_strip_padding"
- android:paddingLeft="@dimen/suggestions_strip_padding"
- style="?attr/suggestionStripViewStyle" />
- <!-- To ensure that key preview popup is correctly placed when the current system locale is
- one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
- <com.android.inputmethod.keyboard.MainKeyboardView
- android:id="@+id/keyboard_view"
- android:layoutDirection="ltr"
+ android:layout_height="0dp" />
+ <LinearLayout
+ android:id="@+id/main_keyboard_frame"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <!-- To ensure that key preview popup is correctly placed when the current system locale is
+ one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
+ <com.android.inputmethod.latin.suggestions.SuggestionStripView
+ android:id="@+id/suggestion_strip_view"
+ android:layoutDirection="ltr"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/suggestions_strip_height"
+ android:gravity="center_vertical"
+ android:paddingRight="@dimen/suggestions_strip_padding"
+ android:paddingLeft="@dimen/suggestions_strip_padding"
+ style="?attr/suggestionStripViewStyle" />
+
+ <!-- To ensure that key preview popup is correctly placed when the current system locale is
+ one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
+ <com.android.inputmethod.keyboard.MainKeyboardView
+ android:id="@+id/keyboard_view"
+ android:layoutDirection="ltr"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ <include
+ layout="@layout/emoji_keyboard_view" />
</com.android.inputmethod.latin.InputView>
diff --git a/java/res/layout/key_preview.xml b/java/res/layout/key_preview_gb.xml
index 2fcd0c4dd..2f2a321a3 100644
--- a/java/res/layout/key_preview.xml
+++ b/java/res/layout/key_preview_gb.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"
+ android:background="@drawable/keyboard_key_feedback_gb"
android:minWidth="32dp"
android:gravity="center"
/>
diff --git a/java/res/layout/more_keys_keyboard.xml b/java/res/layout/more_keys_keyboard.xml
index 6b2464b99..6637117e0 100644
--- a/java/res/layout/more_keys_keyboard.xml
+++ b/java/res/layout/more_keys_keyboard.xml
@@ -17,17 +17,17 @@
** limitations under the License.
*/
-->
+
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- style="?attr/moreKeysKeyboardPanelStyle"
- >
+ 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"
+>
<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"
- />
+ 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" />
</LinearLayout>
diff --git a/java/res/layout/more_suggestions.xml b/java/res/layout/more_suggestions.xml
index b41bb8aa4..8659f0761 100644
--- a/java/res/layout/more_suggestions.xml
+++ b/java/res/layout/more_suggestions.xml
@@ -17,21 +17,21 @@
** limitations under the License.
*/
-->
+
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+ 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"
+>
+ <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"
- android:orientation="horizontal"
- style="?attr/moreKeysKeyboardPanelStyle"
- >
- <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:keyHintLetterColor="@android:color/white"
- />
+ latin:keyLetterSize="@dimen/suggestion_text_size"
+ latin:keyLabelSize="@dimen/suggestion_text_size"
+ latin:keyHintLetterRatio="@fraction/more_suggestions_info_ratio"
+ latin:keyHintLetterColor="@android:color/white" />
</LinearLayout>
diff --git a/java/res/layout/suggestion_info.xml b/java/res/layout/suggestion_info.xml
index a4ad6df25..0aa26000d 100644
--- a/java/res/layout/suggestion_info.xml
+++ b/java/res/layout/suggestion_info.xml
@@ -24,4 +24,4 @@
android:layout_height="wrap_content"
android:textSize="6dp"
android:textColor="@android:color/white"
- style="?attr/suggestionBackgroundStyle" />
+ style="?attr/suggestionWordStyle" />
diff --git a/java/res/layout/suggestion_word.xml b/java/res/layout/suggestion_word.xml
index fa00e041e..c82a13c99 100644
--- a/java/res/layout/suggestion_word.xml
+++ b/java/res/layout/suggestion_word.xml
@@ -36,4 +36,4 @@
android:clickable="false"
android:singleLine="true"
android:ellipsize="none"
- style="?attr/suggestionBackgroundStyle" />
+ style="?attr/suggestionWordStyle" />
diff --git a/java/res/raw/main_en.dict b/java/res/raw/main_en.dict
index 6564d47fa..8660c28e2 100644
--- a/java/res/raw/main_en.dict
+++ b/java/res/raw/main_en.dict
Binary files differ
diff --git a/java/res/raw/main_fr.dict b/java/res/raw/main_fr.dict
index 31fb2af85..0d2e51837 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_pt_br.dict b/java/res/raw/main_pt_br.dict
index 557d46e89..98a27c7c8 100644
--- a/java/res/raw/main_pt_br.dict
+++ b/java/res/raw/main_pt_br.dict
Binary files differ
diff --git a/java/res/raw/main_ru.dict b/java/res/raw/main_ru.dict
index 86c368eb9..7dec62425 100644
--- a/java/res/raw/main_ru.dict
+++ b/java/res/raw/main_ru.dict
Binary files differ
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index fc71368f0..01a57e7e0 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emosiekone"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Gepasmaakte invoerstyle"</string>
<string name="add_style" msgid="6163126614514489951">"Voeg styl by"</string>
<string name="add" msgid="8299699805688017798">"Voeg by"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 93f9a6000..774f2c552 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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">"ፊደላት (ፒሲ)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"ኢሞጂ"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"የተበጁ የግቤት ስታይሎች"</string>
<string name="add_style" msgid="6163126614514489951">"ስታይል አክል"</string>
<string name="add" msgid="8299699805688017798">"አክል"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index efb294985..7e39b597e 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"أنماط الإدخال المخصصة"</string>
<string name="add_style" msgid="6163126614514489951">"إضافة نمط"</string>
<string name="add" msgid="8299699805688017798">"إضافة"</string>
diff --git a/java/res/values-az-rAZ/strings-appname.xml b/java/res/values-az-rAZ/strings-appname.xml
new file mode 100644
index 000000000..2fcb76c69
--- /dev/null
+++ b/java/res/values-az-rAZ/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">"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.xml b/java/res/values-az-rAZ/strings.xml
new file mode 100644
index 000000000..bd62a95d4
--- /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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saxlanmış"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Get"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Növbəti"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Əvvəlki"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Hazırdır"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Göndər"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Gözlə"</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_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="4729081055438508321">"<xliff:g id="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_modes_main_keyboard" msgid="3360660341121083174">"Əsas klaviaturada"</string>
+ <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simvol klaviaturasında"</string>
+ <string name="voice_input_modes_off" msgid="3745699748218082014">"Qapalı"</string>
+ <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Əsas klaviaturada mikrofon"</string>
+ <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Simvol klaviaturasında mikrofon"</string>
+ <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Səs daxiletməsi deaktiv edildi"</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="2179097748724725906">"İngilis (BK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"İngilis (ABŞ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"İspan (ABŞ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%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="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="6898610163768980870">"Bu faylı həqiqətən <xliff:g id="LOCALE_NAME">%s</xliff:g> adlı yerə quraşdıraq?"</string>
+ <string name="error" msgid="8940763624668513648">"Xəta var idi"</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="8689096636874758814">"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="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="2878629598667658845">"Mobil cihazınızda seçilmiş dil üzrə lüğət mövcuddur.&lt;br/&gt; Yazı təcrübənizi təkmilləşdirmək üçün <xliff:g id="LANGUAGE">%1$s</xliff:g> lüğətini &lt;b&gt;endirməyi&lt;/b&gt; tövsiyə edirik.&lt;br/&gt; &lt;br/&gt; Endirmə 3G ilə bir və ya iki dəqiqə çəkəcək. &lt;b&gt;Limitsiz data planınız&lt;/b&gt;.&lt;br/&gt; olmadığı halda əlavə xərc tutula bilər, endirməni avtomatik başlatmaq üçün Wi-Fi bağlantı tapmanızı tövsiyə edirik.&lt;br/&gt; &lt;br/&gt; Məsləhət: Siz lüğətləri mobil cihazınızın &lt;b&gt;Dil və daxiletmə&lt;/b&gt; <b>Parametrlərindən</b> endirə və ya ləğv edə 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="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> üçün lüğət mövcuddur"</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="1313027353588566660">"Endirilir: <xliff:g id="LANGUAGE">%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-az/strings-appname.xml b/java/res/values-az/strings-appname.xml
new file mode 100644
index 000000000..2fcb76c69
--- /dev/null
+++ b/java/res/values-az/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">"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/strings.xml b/java/res/values-az/strings.xml
new file mode 100644
index 000000000..7fb13f7a0
--- /dev/null
+++ b/java/res/values-az/strings.xml
@@ -0,0 +1,242 @@
+<?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çənəkləri"</string>
+ <string name="english_ime_research_log" msgid="8492602295696577851">"Araşdırma Giriş Ə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">"İnkişaf etmiş parametrlər"</string>
+ <string name="advanced_settings_summary" msgid="4487980456152830271">"Mütəxəssislər üçün Seçənəklə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> ms"</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_double_space_period" msgid="8781529969425082860">"İkili boşluq periodu"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"Boşluqdakı ikiqat tıklama bolşuqdan sonrakı periodu əlavə edir"</string>
+ <string name="auto_cap" msgid="1719746674854628252">"Avtomatik böyük hərf"</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">"Aktiv"</string>
+ <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Çox aktiv"</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 işlətmə önizləməsi"</string>
+ <string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Jest zamanı təklif edilən sözə baxın"</string>
+ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Yadda saxlanıldı"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Get"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Növbəti"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Əvvəlki"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Hazırdır"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Göndər"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Gözlə"</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_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">"Klaviatura gizlədilib"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="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_modes_main_keyboard" msgid="3360660341121083174">"Əsas klaviaturada"</string>
+ <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simvol klaviaturasında"</string>
+ <string name="voice_input_modes_off" msgid="3745699748218082014">"Qapalı"</string>
+ <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Əsas klaviaturada mikrofon"</string>
+ <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Simvol klaviaturasında mikrofon"</string>
+ <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Səs daxiletməsi deaktiv edildi"</string>
+ <string name="configure_input_method" msgid="373356270290742459">"Daxiletmə üsullarını quraşdırın"</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="2179097748724725906">"İngilis (BK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"İngilis (ABŞ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"İspan (ABŞ) (<xliff:g id="LAYOUT">%s</xliff:g>)"</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="custom_input_styles_title" msgid="8429952441821251512">"Xüsusi daxiletmə üslubları"</string>
+ <string name="add_style" msgid="6163126614514489951">"Üslub əlavə edin"</string>
+ <string name="add" msgid="8299699805688017798">"Əlavə edin"</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="6898610163768980870">"Bu faylı həqiqətən <xliff:g id="LOCALE_NAME">%s</xliff:g> adlı yerə quraşdıraq?"</string>
+ <string name="error" msgid="8940763624668513648">"Xəta var idi"</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> 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 güncəllə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 seçənəkləri"</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əti ilə 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="8689096636874758814">"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="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">"Silin"</string>
+ <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Mobil cihazınızda seçilmiş dil üzrə lüğət mövcuddur.&lt;br/&gt; Yazı təcrübənizi təkmilləşdirmək üçün <xliff:g id="LANGUAGE">%1$s</xliff:g> lüğətini &lt;b&gt;endirməyi&lt;/b&gt; tövsiyə edirik.&lt;br/&gt; &lt;br/&gt; Endirmə 3G ilə bir və ya iki dəqiqə çəkəcək. &lt;b&gt;Limitsiz data planınız&lt;/b&gt;.&lt;br/&gt; olmadığı halda əlavə xərc tutula bilər, endirməni avtomatik başlatmaq üçün Wi-Fi bağlantı tapmanızı tövsiyə edirik.&lt;br/&gt; &lt;br/&gt; Məsləhət: Siz lüğətləri mobil cihazınızın &lt;b&gt;Dil və daxiletmə&lt;/b&gt; <b>Parametrlərindən</b> endirə və ya ləğv edə 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="6514288591959117288">"<xliff:g id="LANGUAGE">%1$s</xliff:g> üçün lüğət mövcuddur"</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="1313027353588566660">"Endirilir: <xliff:g id="LANGUAGE">%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/strings.xml b/java/res/values-be/strings.xml
index 21adcca17..db40c8a72 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -146,6 +146,8 @@
<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) -->
@@ -160,6 +162,8 @@
<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>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 301f84e38..d3879cca5 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Латиница (Дворак)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Латиница (Коулмак)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Латиница (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Емотикони"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Персон. стилове за въвежд."</string>
<string name="add_style" msgid="6163126614514489951">"+ стил"</string>
<string name="add" msgid="8299699805688017798">"Добавяне"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index 37e7d569c..03e2f3fdf 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Estils d\'entrada personalitzats"</string>
<string name="add_style" msgid="6163126614514489951">"Afeg. estil"</string>
<string name="add" msgid="8299699805688017798">"Afegeix"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 8aeaf73ff..a707f26a7 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Latinka (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Latinka (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Latinka (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emodži"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Vlastní styl zadávání"</string>
<string name="add_style" msgid="6163126614514489951">"Přidat styl"</string>
<string name="add" msgid="8299699805688017798">"Přidat"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index afd92658f..187689559 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Tilpasset inputtypografi"</string>
<string name="add_style" msgid="6163126614514489951">"Tilføj typografi"</string>
<string name="add" msgid="8299699805688017798">"Tilføj"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 12386d8e2..5f3e619ff 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Lat. Alphabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Lat. Alphabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Lat. Alphabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Benutzerdefinierte Eingabestile"</string>
<string name="add_style" msgid="6163126614514489951">"Stil hinzufügen"</string>
<string name="add" msgid="8299699805688017798">"Hinzufügen"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index b010e44e6..27eb865ea 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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">"Emoticon"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Προσαρμοσ. στυλ εισαγ."</string>
<string name="add_style" msgid="6163126614514489951">"Προσθ. στυλ"</string>
<string name="add" msgid="8299699805688017798">"Προσθήκη"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index c8dfe8f1e..6337aa019 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -24,13 +24,13 @@
<string name="english_ime_research_log" msgid="8492602295696577851">"Research Log Commands"</string>
<string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
<string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
- <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on key-press"</string>
- <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on key-press"</string>
+ <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
+ <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on keypress"</string>
<string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string>
<string name="general_category" msgid="1859088467017573195">"General"</string>
<string name="correction_category" msgid="2236750915056607613">"Text correction"</string>
<string name="gesture_typing_category" msgid="497263612130532630">"Gesture typing"</string>
- <string name="misc_category" msgid="6894192814868233453">"Other Options"</string>
+ <string name="misc_category" msgid="6894192814868233453">"Other options"</string>
<string name="advanced_settings" msgid="362895144495591463">"Advanced settings"</string>
<string name="advanced_settings_summary" msgid="4487980456152830271">"Options for experts"</string>
<string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Switch to other input methods"</string>
@@ -66,7 +66,7 @@
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
<string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Aggressive"</string>
<string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Very aggressive"</string>
- <string name="bigram_prediction" msgid="1084449187723948550">"Next word suggestions"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Next-word suggestions"</string>
<string name="bigram_prediction_summary" msgid="3896362682751109677">"Use the previous word when making suggestions"</string>
<string name="gesture_input" msgid="826951152254563827">"Enable gesture typing"</string>
<string name="gesture_input_summary" msgid="9180350639305731231">"Input a word by sliding through the letters"</string>
@@ -77,7 +77,7 @@
<string name="label_go_key" msgid="1635148082137219148">"Go"</string>
<string name="label_next_key" msgid="362972844525672568">"Next"</string>
<string name="label_previous_key" msgid="1211868118071386787">"Prev"</string>
- <string name="label_done_key" msgid="2441578748772529288">"Done"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Finished"</string>
<string name="label_send_key" msgid="2815056534433717444">"Send"</string>
<string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Wait"</string>
@@ -143,6 +143,7 @@
<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_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>
@@ -150,14 +151,15 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alphabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alphabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alphabet (PC)"</string>
- <string name="custom_input_styles_title" msgid="8429952441821251512">"Custom input styles"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Customised input styles"</string>
<string name="add_style" msgid="6163126614514489951">"Add style"</string>
<string name="add" msgid="8299699805688017798">"Add"</string>
<string name="remove" msgid="4486081658752944606">"Remove"</string>
<string name="save" msgid="7646738597196767214">"Save"</string>
<string name="subtype_locale" msgid="8576443440738143764">"Language"</string>
<string name="keyboard_layout_set" msgid="4309233698194565609">"Layout"</string>
- <string name="custom_input_style_note_message" msgid="8826731320846363423">"Your custom input style needs to be enabled before you start using it. Do you want to enable it now?"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Your customised input style needs to be enabled before you start using it. Do you want to enable it now?"</string>
<string name="enable" msgid="5031294444630523247">"Enable"</string>
<string name="not_now" msgid="6172462888202790482">"Not now"</string>
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
diff --git a/java/res/values-en-rIN/strings-appname.xml b/java/res/values-en-rIN/strings-appname.xml
new file mode 100644
index 000000000..5ad5eae66
--- /dev/null
+++ b/java/res/values-en-rIN/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">"Android Keyboard (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android Spell Checker (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android Keyboard Settings (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Spell Checker Settings (AOSP)"</string>
+</resources>
diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000..6337aa019
--- /dev/null
+++ b/java/res/values-en-rIN/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">"Input options"</string>
+ <string name="english_ime_research_log" msgid="8492602295696577851">"Research Log Commands"</string>
+ <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string>
+ <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on keypress"</string>
+ <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on keypress"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string>
+ <string name="general_category" msgid="1859088467017573195">"General"</string>
+ <string name="correction_category" msgid="2236750915056607613">"Text correction"</string>
+ <string name="gesture_typing_category" msgid="497263612130532630">"Gesture typing"</string>
+ <string name="misc_category" msgid="6894192814868233453">"Other options"</string>
+ <string name="advanced_settings" msgid="362895144495591463">"Advanced settings"</string>
+ <string name="advanced_settings_summary" msgid="4487980456152830271">"Options for experts"</string>
+ <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Switch to other input methods"</string>
+ <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Language switch key also covers other input methods"</string>
+ <string name="show_language_switch_key" msgid="5915478828318774384">"Language switch key"</string>
+ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Show when multiple input languages are enabled"</string>
+ <string name="sliding_key_input_preview" msgid="6604262359510068370">"Show slide indicator"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Display visual cue while sliding from Shift or Symbol keys"</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Key pop-up dismiss delay"</string>
+ <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"No delay"</string>
+ <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
+ <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+ <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_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>
+ <string name="auto_cap_summary" msgid="7934452761022946874">"Capitalise the first word of each sentence"</string>
+ <string name="edit_personal_dictionary" msgid="3996910038952940420">"Personal dictionary"</string>
+ <string name="configure_dictionaries_title" msgid="4238652338556902049">"Add-on dictionaries"</string>
+ <string name="main_dictionary" msgid="4798763781818361168">"Main dictionary"</string>
+ <string name="prefs_show_suggestions" msgid="8026799663445531637">"Show correction suggestions"</string>
+ <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Display suggested words while typing"</string>
+ <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Always show"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Show in portrait mode"</string>
+ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Always hide"</string>
+ <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Block offensive words"</string>
+ <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Do not suggest potentially offensive words"</string>
+ <string name="auto_correction" msgid="7630720885194996950">"Auto-correction"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Correct mistyped words automatically with spacebar and punctuation"</string>
+ <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Off"</string>
+ <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Aggressive"</string>
+ <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Very aggressive"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Next-word suggestions"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Use the previous word when making suggestions"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Enable gesture typing"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"Input a word by sliding through the letters"</string>
+ <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="label_go_key" msgid="1635148082137219148">"Go"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Next"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Prev"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Finished"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Wait"</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_description_unknown" msgid="3197434010402179157">"Key code %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift on (tap to disable)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock on (tap to disable)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbols"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbers"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Settings"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Voice input"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley face"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Search"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Switch language"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Next"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Previous"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift enabled"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock enabled"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift disabled"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbols mode"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Letters mode"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Phone mode"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Phone symbols mode"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Keyboard hidden"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Showing <xliff:g id="MODE">%s</xliff:g> keyboard"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"date"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"date and time"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"messaging"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"number"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"phone"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"text"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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="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>
+ <string name="select_language" msgid="3693815588777926848">"Input languages"</string>
+ <string name="hint_add_to_dictionary" msgid="573678656946085380">"Touch again to save"</string>
+ <string name="has_dictionary" msgid="6071847973466625007">"Dictionary available"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Enable user feedback"</string>
+ <string name="prefs_description_log" msgid="7525225584555429211">"Help improve this input method editor by automatically sending usage statistics and crash reports"</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"Keyboard theme"</string>
+ <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_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>
+ <string name="subtype_no_language_azerty" msgid="8144348527575640087">"Alphabet (AZERTY)"</string>
+ <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alphabet (Dvorak)"</string>
+ <string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alphabet (Colemak)"</string>
+ <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alphabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Customised input styles"</string>
+ <string name="add_style" msgid="6163126614514489951">"Add style"</string>
+ <string name="add" msgid="8299699805688017798">"Add"</string>
+ <string name="remove" msgid="4486081658752944606">"Remove"</string>
+ <string name="save" msgid="7646738597196767214">"Save"</string>
+ <string name="subtype_locale" msgid="8576443440738143764">"Language"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Layout"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Your customised input style needs to be enabled before you start using it. Do you want to enable it now?"</string>
+ <string name="enable" msgid="5031294444630523247">"Enable"</string>
+ <string name="not_now" msgid="6172462888202790482">"Not now"</string>
+ <string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
+ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Usability study mode"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Key long press delay"</string>
+ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Keypress vibration duration"</string>
+ <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Keypress sound volume"</string>
+ <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="error" msgid="8940763624668513648">"There was an error"</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>
+ <string name="setup_start_action" msgid="8936036460897347708">"Get started"</string>
+ <string name="setup_next_action" msgid="371821437915144603">"Next step"</string>
+ <string name="setup_steps_title" msgid="6400373034871816182">"Setting up <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_title" msgid="3147967630253462315">"Enable <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_instruction" msgid="2578631936624637241">"Please tick \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" in your Language &amp; input settings. This will authorise it to run on your device."</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<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_action" msgid="4366513534999901728">"Enable in Settings"</string>
+ <string name="setup_step2_title" msgid="6860725447906690594">"Switch to <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step2_instruction" msgid="9141481964870023336">"Next, select \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" as your active text-input method."</string>
+ <string name="setup_step2_action" msgid="1660330307159824337">"Switch input methods"</string>
+ <string name="setup_step3_title" msgid="3154757183631490281">"Congratulations, you\'re all set!"</string>
+ <string name="setup_step3_instruction" msgid="8025981829605426000">"Now you can type in all your favourite apps with <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
+ <string name="setup_step3_action" msgid="600879797256942259">"Configure additional languages"</string>
+ <string name="setup_finish_action" msgid="276559243409465389">"Finished"</string>
+ <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Show app icon"</string>
+ <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Display application icon in the launcher"</string>
+ <string name="app_name" msgid="6320102637491234792">"Dictionary Provider"</string>
+ <string name="dictionary_provider_name" msgid="3027315045397363079">"Dictionary Provider"</string>
+ <string name="dictionary_service_name" msgid="6237472350693511448">"Dictionary Service"</string>
+ <string name="download_description" msgid="6014835283119198591">"Dictionary update information"</string>
+ <string name="dictionary_settings_title" msgid="8091417676045693313">"Add-on dictionaries"</string>
+ <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Dictionary available"</string>
+ <string name="dictionary_settings_summary" msgid="5305694987799824349">"Settings for dictionaries"</string>
+ <string name="user_dictionaries" msgid="3582332055892252845">"User dictionaries"</string>
+ <string name="default_user_dict_pref_name" msgid="1625055720489280530">"User dictionary"</string>
+ <string name="dictionary_available" msgid="4728975345815214218">"Dictionary available"</string>
+ <string name="dictionary_downloading" msgid="2982650524622620983">"Currently downloading"</string>
+ <string name="dictionary_installed" msgid="8081558343559342962">"Installed"</string>
+ <string name="dictionary_disabled" msgid="8950383219564621762">"Installed, disabled"</string>
+ <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Problem connecting to dictionary service"</string>
+ <string name="no_dictionaries_available" msgid="8039920716566132611">"No dictionaries available"</string>
+ <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="main_dict_description" msgid="3072821352793492143">"Main dictionary"</string>
+ <string name="cancel" msgid="6830980399865683324">"Cancel"</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="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_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="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>
+ <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Phrase"</string>
+ <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"More options"</string>
+ <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Fewer options"</string>
+ <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OK"</string>
+ <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Word:"</string>
+ <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Shortcut:"</string>
+ <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Language:"</string>
+ <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Type a word"</string>
+ <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Optional shortcut"</string>
+ <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Edit word"</string>
+ <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Edit"</string>
+ <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Delete"</string>
+ <string name="user_dict_settings_empty_text" msgid="558499587532668203">"You don\'t have any words in the user dictionary. Add a word by touching the Add (+) button."</string>
+ <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"For all languages"</string>
+ <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"More languages…"</string>
+ <string name="user_dict_settings_delete" msgid="110413335187193859">"Delete"</string>
+ <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+</resources>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 52abe8259..b1a421475 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Estilos de entrada personalizados"</string>
<string name="add_style" msgid="6163126614514489951">"Agr. estilo"</string>
<string name="add" msgid="8299699805688017798">"Agregar"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index c25058c25..9ff9430de 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Estilos de entrada personalizados"</string>
<string name="add_style" msgid="6163126614514489951">"Añadir estilo"</string>
<string name="add" msgid="8299699805688017798">"Añadir"</string>
diff --git a/java/res/values-et-rEE/strings-appname.xml b/java/res/values-et-rEE/strings-appname.xml
new file mode 100644
index 000000000..bbc13d293
--- /dev/null
+++ b/java/res/values-et-rEE/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">"Androidi klaviatuur (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Androidi õigekirjakontroll (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Androidi klaviatuuri seaded (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Androidi õigekirjakontrolli seaded (AOSP)"</string>
+</resources>
diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml
new file mode 100644
index 000000000..62197d772
--- /dev/null
+++ b/java/res/values-et-rEE/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">"Sisestusvalikud"</string>
+ <string name="english_ime_research_log" msgid="8492602295696577851">"Uuringulogi käsud"</string>
+ <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakti nimede kontroll."</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Õigekirjakontroll kasutab teie kontaktisikute loendi sissekandeid"</string>
+ <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreeri klahvivajutusel"</string>
+ <string name="sound_on_keypress" msgid="6093592297198243644">"Heli klahvivajutusel"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Klahvivajutusel kuva hüpik"</string>
+ <string name="general_category" msgid="1859088467017573195">"Üldine"</string>
+ <string name="correction_category" msgid="2236750915056607613">"Teksti parandamine"</string>
+ <string name="gesture_typing_category" msgid="497263612130532630">"Joonistusega sisestamine"</string>
+ <string name="misc_category" msgid="6894192814868233453">"Muud valikud"</string>
+ <string name="advanced_settings" msgid="362895144495591463">"Täpsemad seaded"</string>
+ <string name="advanced_settings_summary" msgid="4487980456152830271">"Valikud ekspertidele"</string>
+ <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Vaheta sisestusmeetodit"</string>
+ <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Keelevahetuse võti hõlmab ka muid sisestusmeetodeid"</string>
+ <string name="show_language_switch_key" msgid="5915478828318774384">"Keelevahetuse nupp"</string>
+ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Kuva, kui lubatud on mitu sisendkeelt"</string>
+ <string name="sliding_key_input_preview" msgid="6604262359510068370">"Kuva lohistamisnäidik"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Tõstu- või sümboliklahvidelt lohistades anna visuaalselt märku"</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Hüpiku loobumisviivitus"</string>
+ <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Viivituseta"</string>
+ <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Vaikeseade"</string>
+ <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+ <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_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>
+ <string name="auto_cap_summary" msgid="7934452761022946874">"Iga lause esimese sõna kirjutamine suure algustähega"</string>
+ <string name="edit_personal_dictionary" msgid="3996910038952940420">"Isiklik sõnastik"</string>
+ <string name="configure_dictionaries_title" msgid="4238652338556902049">"Pistiksõnaraamatud"</string>
+ <string name="main_dictionary" msgid="4798763781818361168">"Peamine sõnaraamat"</string>
+ <string name="prefs_show_suggestions" msgid="8026799663445531637">"Kuva parandussoovitusi"</string>
+ <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Kuva sisestamise ajal sõnasoovitusi"</string>
+ <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Kuva alati"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Kuva vertikaalrežiimis"</string>
+ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Peida alati"</string>
+ <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Blokeeri solvavad sõnad"</string>
+ <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Ära soovita potentsiaals. solvavaid sõnu"</string>
+ <string name="auto_correction" msgid="7630720885194996950">"Automaatparandus"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Tühik ja kirjavahemärgid parand. autom. kirjavigadega sõnad"</string>
+ <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Väljas"</string>
+ <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mõõdukas"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Agressiivne"</string>
+ <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Väga agressiivne"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Järgmise sõna soovitused"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Soovituste tegemisel eelmise sõna kasutamine"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Luba joonistusega sisestamine"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"Sõna sisestamine tähtede lohistamisega"</string>
+ <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="label_go_key" msgid="1635148082137219148">"Mine"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Edasi"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Eelm."</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Saada"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Peata"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Oota"</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_description_unknown" msgid="3197434010402179157">"Klahvi kood: %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Tõstuklahv"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Tõstuklahv sees (puudutage keelamiseks)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Suurtähelukk on sees (puudutage keelamiseks)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Kustuta"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Sümbolid"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Tähed"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbrid"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Seaded"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tabulaator"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Tühik"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Kõnesisend"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Naerunägu"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Tagasi"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Otsing"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Keele vahetamine"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Järgmine"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Eelmine"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Tõstuklahv on lubatud"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Suurtähelukk on lubatud"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Tõstuklahv on keelatud"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Sümbolite režiim"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Tähtede režiim"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Telefonirežiim"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Telefoni sümbolite režiim"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Klaviatuur on peidetud"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Näitab klaviatuuri režiimil <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"kuupäev"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"kuupäev ja kellaaeg"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"e-post"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"sõnumiside"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"number"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"tekst"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"aeg"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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="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>
+ <string name="select_language" msgid="3693815588777926848">"Sisestuskeeled"</string>
+ <string name="hint_add_to_dictionary" msgid="573678656946085380">"Salvestamiseks puudutage uuesti"</string>
+ <string name="has_dictionary" msgid="6071847973466625007">"Sõnastik saadaval"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Luba kasutaja tagasiside"</string>
+ <string name="prefs_description_log" msgid="7525225584555429211">"Aidake seda sisestusmeetodi redigeerijat parandada, saates automaatselt kasutusstatistikat ja krahhiaruandeid."</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatuuri teema"</string>
+ <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_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>
+ <string name="subtype_no_language_azerty" msgid="8144348527575640087">"Tähestik (AZERTY)"</string>
+ <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Tähestik (Dvorak)"</string>
+ <string name="subtype_no_language_colemak" msgid="5837418400010302623">"Tähestik (Colemak)"</string>
+ <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Tähestik (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emotikon"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Kohandage sisendlaadid"</string>
+ <string name="add_style" msgid="6163126614514489951">"Lisage laad"</string>
+ <string name="add" msgid="8299699805688017798">"Lisa"</string>
+ <string name="remove" msgid="4486081658752944606">"Eemalda"</string>
+ <string name="save" msgid="7646738597196767214">"Salvesta"</string>
+ <string name="subtype_locale" msgid="8576443440738143764">"Keel"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Paigutus"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Kohandatud sisendi laad tuleb enne kasutamist lubada. Lubada?"</string>
+ <string name="enable" msgid="5031294444630523247">"Luba"</string>
+ <string name="not_now" msgid="6172462888202790482">"Mitte kohe"</string>
+ <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Sama sisendstiil on juba olemas: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
+ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kasutatavuse uurimisrežiim"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Pika klahvivajutuse viide"</string>
+ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Klahvivajutuse vibreerimise kestus"</string>
+ <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Klahvivajutuse helitugevus"</string>
+ <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="error" msgid="8940763624668513648">"Ilmnes viga"</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>
+ <string name="setup_start_action" msgid="8936036460897347708">"Alustamine"</string>
+ <string name="setup_next_action" msgid="371821437915144603">"Järgmine toiming"</string>
+ <string name="setup_steps_title" msgid="6400373034871816182">"Rakenduse <xliff:g id="APPLICATION_NAME">%s</xliff:g> seadistamine"</string>
+ <string name="setup_step1_title" msgid="3147967630253462315">"Lubage <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_instruction" msgid="2578631936624637241">"Märkige oma keele ja sisestamise seadetes rakendus „<xliff:g id="APPLICATION_NAME">%s</xliff:g>”. See lubab rakenduse käitamise teie seadmes."</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> on teie keele- ja sisestusseadetes juba lubatud, seega on see toiming tehtud. Asuge järgmise toimingu juurde."</string>
+ <string name="setup_step1_action" msgid="4366513534999901728">"Luba seadetes"</string>
+ <string name="setup_step2_title" msgid="6860725447906690594">"Minge üle rakendusele <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step2_instruction" msgid="9141481964870023336">"Järgmisena valige aktiivseks tekstisisestusmeetodiks rakendus „<xliff:g id="APPLICATION_NAME">%s</xliff:g>”."</string>
+ <string name="setup_step2_action" msgid="1660330307159824337">"Vaheta sisestusmeetodeid"</string>
+ <string name="setup_step3_title" msgid="3154757183631490281">"Õnnitleme. Kõik on valmis!"</string>
+ <string name="setup_step3_instruction" msgid="8025981829605426000">"Nüüd saate rakendusega <xliff:g id="APPLICATION_NAME">%s</xliff:g> sisestada kõikides oma lemmikrakendustes."</string>
+ <string name="setup_step3_action" msgid="600879797256942259">"Seadista lisakeeled"</string>
+ <string name="setup_finish_action" msgid="276559243409465389">"Lõpetatud"</string>
+ <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Kuva rakenduse ikoon"</string>
+ <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Rakenduse ikooni kuvamine käivitajas"</string>
+ <string name="app_name" msgid="6320102637491234792">"Sõnastikupakkuja"</string>
+ <string name="dictionary_provider_name" msgid="3027315045397363079">"Sõnastikupakkuja"</string>
+ <string name="dictionary_service_name" msgid="6237472350693511448">"Sõnastikuteenus"</string>
+ <string name="download_description" msgid="6014835283119198591">"Sõnastiku värskendamisteave"</string>
+ <string name="dictionary_settings_title" msgid="8091417676045693313">"Pistiksõnastikud"</string>
+ <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Sõnastik on saadaval"</string>
+ <string name="dictionary_settings_summary" msgid="5305694987799824349">"Sõnastike seaded"</string>
+ <string name="user_dictionaries" msgid="3582332055892252845">"Kasutaja sõnastikud"</string>
+ <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Kasutaja sõnastik"</string>
+ <string name="dictionary_available" msgid="4728975345815214218">"Sõnastik on saadaval"</string>
+ <string name="dictionary_downloading" msgid="2982650524622620983">"Praegu allalaadimisel"</string>
+ <string name="dictionary_installed" msgid="8081558343559342962">"Installitud"</string>
+ <string name="dictionary_disabled" msgid="8950383219564621762">"Installitud, keelatud"</string>
+ <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Probleem sõnastikuga ühendumisel"</string>
+ <string name="no_dictionaries_available" msgid="8039920716566132611">"Sõnastikke pole"</string>
+ <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="main_dict_description" msgid="3072821352793492143">"Peamine sõnastik"</string>
+ <string name="cancel" msgid="6830980399865683324">"Tühista"</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="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_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="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>
+ <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Fraas"</string>
+ <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"Rohkem valikuid"</string>
+ <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Vähem valikuid"</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õna:"</string>
+ <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Otsetee:"</string>
+ <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Keel:"</string>
+ <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Sisestage sõna"</string>
+ <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Valikuline otsetee"</string>
+ <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Sõna muutmine"</string>
+ <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Muuda"</string>
+ <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Kustuta"</string>
+ <string name="user_dict_settings_empty_text" msgid="558499587532668203">"Teie kasutaja sõnaraamatus ei ole ühtegi sõna. Sõna saate lisada, puudutades nuppu Lisa (+)."</string>
+ <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"Kõikides keeltes"</string>
+ <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"Rohkem keeli ..."</string>
+ <string name="user_dict_settings_delete" msgid="110413335187193859">"Kustuta"</string>
+ <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
+</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 6d8365926..5d8951619 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -147,6 +147,7 @@
<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_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>
@@ -154,6 +155,7 @@
<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">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"سبک‌های ورودی سفارشی"</string>
<string name="add_style" msgid="6163126614514489951">"افزودن سبک"</string>
<string name="add" msgid="8299699805688017798">"افزودن"</string>
@@ -163,7 +165,7 @@
<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="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>
@@ -205,7 +207,7 @@
<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="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>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index e0e595e2f..4cdf6210e 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -22,12 +22,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="english_ime_input_options" msgid="3909945612939668554">"Syöttövalinnat"</string>
<string name="english_ime_research_log" msgid="8492602295696577851">"Tutkimuslokin komennot"</string>
- <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae kontaktien nimiä"</string>
- <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Oikeinkirjoituksen tarkistus käyttää kontaktiluettelosi tietoja."</string>
+ <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae yht.tietojen nimiä"</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Oikeinkirjoituksen tarkistus käyttää yhteystietojasi."</string>
<string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
<string name="sound_on_keypress" msgid="6093592297198243644">"Toista ääni näppäimiä painettaessa"</string>
<string name="popup_on_keypress" msgid="123894815723512944">"Ponnahdusikkuna painalluksella"</string>
- <string name="general_category" msgid="1859088467017573195">"Yleinen"</string>
+ <string name="general_category" msgid="1859088467017573195">"Yleiset"</string>
<string name="correction_category" msgid="2236750915056607613">"Tekstin korjaus"</string>
<string name="gesture_typing_category" msgid="497263612130532630">"Piirtokirjoitus"</string>
<string name="misc_category" msgid="6894192814868233453">"Muut vaihtoehdot"</string>
@@ -38,33 +38,33 @@
<string name="show_language_switch_key" msgid="5915478828318774384">"Kielenvaihtonäppäin"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Näytä, kun käytössä on useita syöttökieliä"</string>
<string name="sliding_key_input_preview" msgid="6604262359510068370">"Näytä liu\'utuksen tilaosoitin"</string>
- <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Näytä visuaalinen vihje liu\'uttaessasi Shift- tai Symbol-näppäim."</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Näytä visuaalinen vihje Vaihto- tai Symbol-näppäim. liu\'uttam."</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Näppäimen hylkäysviive"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ei viivettä"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Oletus"</string>
<string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
- <string name="settings_system_default" msgid="6268225104743331821">"Järjest. oletusarvo"</string>
- <string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yhteystietojen nimiä"</string>
+ <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_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>
<string name="auto_cap_summary" msgid="7934452761022946874">"Kirjoita jokaisen lauseen ensimmäinen sana isolla alkukirjaimella"</string>
<string name="edit_personal_dictionary" msgid="3996910038952940420">"Oma sanakirja"</string>
- <string name="configure_dictionaries_title" msgid="4238652338556902049">"Lisäsanakirjat"</string>
+ <string name="configure_dictionaries_title" msgid="4238652338556902049">"Sanakirjalisäosat"</string>
<string name="main_dictionary" msgid="4798763781818361168">"Pääsanakirja"</string>
<string name="prefs_show_suggestions" msgid="8026799663445531637">"Näytä korjausehdotukset"</string>
<string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Näytä sanaehdotukset kirjoitettaessa"</string>
<string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Näytä aina"</string>
- <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Näytä pystyasennossa"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Näytä pystysuunnassa"</string>
<string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Piilota aina"</string>
<string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Estä loukkaavat sanat"</string>
- <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Älä ehdota mahdollisesti loukkaavia sanoja"</string>
+ <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Älä ehdota mahd. loukkaavia sanoja"</string>
<string name="auto_correction" msgid="7630720885194996950">"Autom. korjaus"</string>
- <string name="auto_correction_summary" msgid="5625751551134658006">"Välilyönnit ja välimerkit korjaavat väärinkirjoitetut sanat automaattisesti"</string>
- <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Älä käytä"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Välilyönti ja välimerkit korjaavat väärinkirjoitetut sanat autom."</string>
+ <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Ei käytössä"</string>
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Osittainen"</string>
- <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Täysi"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Aggressiivinen"</string>
<string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Hyvin aggressiivinen"</string>
<string name="bigram_prediction" msgid="1084449187723948550">"Seuraavan sanan ehdotukset"</string>
<string name="bigram_prediction_summary" msgid="3896362682751109677">"Käytä edellistä sanaa ehdotuksien perusteena"</string>
@@ -73,38 +73,38 @@
<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="label_go_key" msgid="1635148082137219148">"Siirry"</string>
+ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: tallennettu"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Mene"</string>
<string name="label_next_key" msgid="362972844525672568">"Seur."</string>
- <string name="label_previous_key" msgid="1211868118071386787">"Edell"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Edel."</string>
<string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
- <string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Läh."</string>
<string name="label_pause_key" msgid="181098308428035340">"Tauko"</string>
<string name="label_wait_key" msgid="6402152600878093134">"Odota"</string>
- <string name="spoken_use_headphones" msgid="896961781287283493">"Liitä kuulokkeet kuullaksesi, mitä näppäimiä painat kirjoittaessasi salasanaa."</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_description_unknown" msgid="3197434010402179157">"Näppäimen koodi %d"</string>
- <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
- <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Vaihto päällä (napauta poistaaksesi käytöstä)"</string>
- <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock päällä (napauta poistaaksesi käytöstä)"</string>
- <string name="spoken_description_delete" msgid="8740376944276199801">"Poisto"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Vaihto"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Vaihto päällä (poista käytöstä napauttamalla)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps Lock päällä (poista käytöstä napauttamalla)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Poista"</string>
<string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symbolit"</string>
<string name="spoken_description_to_alpha" msgid="23129338819771807">"Kirjaimet"</string>
<string name="spoken_description_to_numeric" msgid="591752092685161732">"Numerot"</string>
<string name="spoken_description_settings" msgid="4627462689603838099">"Asetukset"</string>
<string name="spoken_description_tab" msgid="2667716002663482248">"Sarkain"</string>
<string name="spoken_description_space" msgid="2582521050049860859">"Välilyönti"</string>
- <string name="spoken_description_mic" msgid="615536748882611950">"Puheohjaus"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Äänisyöte"</string>
<string name="spoken_description_smiley" msgid="2256309826200113918">"Hymiö"</string>
- <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Takaisin"</string>
<string name="spoken_description_search" msgid="1247236163755920808">"Haku"</string>
<string name="spoken_description_dot" msgid="40711082435231673">"Piste"</string>
<string name="spoken_description_language_switch" msgid="5507091328222331316">"Vaihda kieli"</string>
<string name="spoken_description_action_next" msgid="8636078276664150324">"Seuraava"</string>
<string name="spoken_description_action_previous" msgid="800872415009336208">"Edellinen"</string>
<string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Vaihto päällä"</string>
- <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock päällä"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock päällä"</string>
<string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Vaihto pois käytöstä"</string>
<string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Symbolit-tila"</string>
<string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Näppäimistötila"</string>
@@ -121,13 +121,13 @@
<string name="keyboard_mode_text" msgid="6479436687899701619">"teksti"</string>
<string name="keyboard_mode_time" msgid="4381856885582143277">"aika"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"URL-osoite"</string>
- <string name="voice_input" msgid="3583258583521397548">"Ääniohjausavain"</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äimistössä"</string>
- <string name="voice_input_modes_off" msgid="3745699748218082014">"Älä näytä"</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äim."</string>
- <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Ääniohjaus on pois käytöstä"</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="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>
@@ -140,9 +140,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-Britannia) (<xliff:g id="LAYOUT">%s</xliff:g>)"</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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Aakkoset (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Aakkoset (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Aakkoset (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Muokatut syöttötyylit"</string>
<string name="add_style" msgid="6163126614514489951">"Lisää tyyli"</string>
<string name="add" msgid="8299699805688017798">"Lisää"</string>
@@ -157,10 +159,10 @@
<string name="save" msgid="7646738597196767214">"Tallenna"</string>
<string name="subtype_locale" msgid="8576443440738143764">"Kieli"</string>
<string name="keyboard_layout_set" msgid="4309233698194565609">"Asettelu"</string>
- <string name="custom_input_style_note_message" msgid="8826731320846363423">"Ota muokattu syötetyyli käyttöön käyttääksesi sitä."</string>
- <string name="enable" msgid="5031294444630523247">"Käyttöön"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Muokattua syöttötyyliä ei ole otettu käyttöön. Haluatko ottaa sen käyttöön nyt?"</string>
+ <string name="enable" msgid="5031294444630523247">"Ota käyttöön"</string>
<string name="not_now" msgid="6172462888202790482">"Ei nyt"</string>
- <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Sama tulotyyli on jo olemassa: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
+ <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Syöttötyyli on jo olemassa: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_usability_study_mode" msgid="1261130555134595254">"Käytettävyystutkimustila"</string>
<string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Pitkän painalluksen viive"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Painalluksen värinän kesto"</string>
@@ -172,19 +174,19 @@
<string name="error" msgid="8940763624668513648">"Tapahtui virhe"</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">"sekä piirtokirjoitus"</string>
+ <string name="setup_welcome_additional_description" msgid="8150252008545768953">"ja piirtokirjoitus"</string>
<string name="setup_start_action" msgid="8936036460897347708">"Aloita"</string>
<string name="setup_next_action" msgid="371821437915144603">"Seuraava vaihe"</string>
<string name="setup_steps_title" msgid="6400373034871816182">"Sovelluksen <xliff:g id="APPLICATION_NAME">%s</xliff:g> asetukset"</string>
<string name="setup_step1_title" msgid="3147967630253462315">"Ota <xliff:g id="APPLICATION_NAME">%s</xliff:g> käyttöön"</string>
- <string name="setup_step1_instruction" msgid="2578631936624637241">"Valitse <xliff:g id="APPLICATION_NAME">%s</xliff:g> kieli- ja syöttötapa-asetuksissa, mikä valtuuttaa sovel. laitteellesi."</string>
- <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> on jo käytössä Kieli- ja syöttöasetuksissa, joten tämä vaihe on tehty. Siirrytään eteenpäin!"</string>
+ <string name="setup_step1_instruction" msgid="2578631936624637241">"Valitse <xliff:g id="APPLICATION_NAME">%s</xliff:g> Kieli ja syöttötapa -asetuksissa. Se antaa sovellukselle luvan toimia laitteessasi."</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> on jo käytössä Kieli ja syöttötapa -asetuksissa, joten tämä vaihe on tehty. Siirrytään eteenpäin!"</string>
<string name="setup_step1_action" msgid="4366513534999901728">"Ota käyttöön asetuksissa"</string>
<string name="setup_step2_title" msgid="6860725447906690594">"Siirry sovellukseen <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_step2_instruction" msgid="9141481964870023336">"Valitse <xliff:g id="APPLICATION_NAME">%s</xliff:g> käytössä olevaksi tekstinsyöttötavaksi."</string>
<string name="setup_step2_action" msgid="1660330307159824337">"Vaihda syöttötapaa"</string>
<string name="setup_step3_title" msgid="3154757183631490281">"Onneksi olkoon, valmista tuli!"</string>
- <string name="setup_step3_instruction" msgid="8025981829605426000">"Nyt voit kirjoittaa kaikkiin lempisovelluksiisi sovelluksen <xliff:g id="APPLICATION_NAME">%s</xliff:g> avulla."</string>
+ <string name="setup_step3_instruction" msgid="8025981829605426000">"Nyt voit kirjoittaa kaikissa lempisovelluksissasi sovelluksen <xliff:g id="APPLICATION_NAME">%s</xliff:g> avulla."</string>
<string name="setup_step3_action" msgid="600879797256942259">"Määritä lisää kieliä"</string>
<string name="setup_finish_action" msgid="276559243409465389">"Valmis"</string>
<string name="show_setup_wizard_icon" msgid="5008028590593710830">"Näytä sovelluskuvake"</string>
@@ -199,11 +201,11 @@
<string name="user_dictionaries" msgid="3582332055892252845">"Käyttäjän sanakirjat"</string>
<string name="default_user_dict_pref_name" msgid="1625055720489280530">"Käyttäjän sanakirja"</string>
<string name="dictionary_available" msgid="4728975345815214218">"Sanakirja saatavilla"</string>
- <string name="dictionary_downloading" msgid="2982650524622620983">"Ladataan parhaillaan"</string>
+ <string name="dictionary_downloading" msgid="2982650524622620983">"Ladataan"</string>
<string name="dictionary_installed" msgid="8081558343559342962">"Asennettu"</string>
<string name="dictionary_disabled" msgid="8950383219564621762">"Asennettu, poistettu käytöstä"</string>
- <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Ongelma yhdistettässä sanakirjapalveluun"</string>
- <string name="no_dictionaries_available" msgid="8039920716566132611">"Ei sanakirjoja saatavilla"</string>
+ <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Ei yhteyttä sanak."</string>
+ <string name="no_dictionaries_available" msgid="8039920716566132611">"Ei sanak. saatavilla"</string>
<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>
@@ -217,8 +219,8 @@
<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_description" msgid="1075194169443163487">"Paina tätä, jos haluat tarkastella kohdetta tai ladata sen"</string>
- <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Ladataan: pian ehdotuksia näytetään kielellä <xliff:g id="LANGUAGE">%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="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>
@@ -227,7 +229,7 @@
<string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Väh. vaihtoeht."</string>
<string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OK"</string>
<string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Sana:"</string>
- <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Pikanäppäin"</string>
+ <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Pikanäppäin:"</string>
<string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Kieli:"</string>
<string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Kirjoita sana"</string>
<string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Valinnainen pikanäppäin"</string>
diff --git a/java/res/values-fr-rCA/donottranslate.xml b/java/res/values-fr-rCA/donottranslate.xml
new file mode 100644
index 000000000..21f18d852
--- /dev/null
+++ b/java/res/values-fr-rCA/donottranslate.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<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>
+ <!-- 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>
+</resources>
diff --git a/java/res/values-fr-rCA/strings-appname.xml b/java/res/values-fr-rCA/strings-appname.xml
new file mode 100644
index 000000000..d45e239a0
--- /dev/null
+++ b/java/res/values-fr-rCA/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">"Clavier Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Correcteur orthographique Android (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Paramètres du clavier Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Paramètres du correcteur orthographique Android (AOSP)"</string>
+</resources>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
index b56463ed9..8d8fedd9a 100644
--- a/java/res/values-fr-rCA/strings.xml
+++ b/java/res/values-fr-rCA/strings.xml
@@ -1,19 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+/*
+**
+** 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.
+*/
+ -->
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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="7252517407088836577">"Clavier Android"</string>
+ <string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
+ <string name="english_ime_research_log" msgid="8492602295696577851">"Commandes journaux rech."</string>
+ <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string>
+ <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
+ <string name="sound_on_keypress" msgid="6093592297198243644">"Son à chaque touche"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères"</string>
+ <string name="general_category" msgid="1859088467017573195">"Général"</string>
+ <string name="correction_category" msgid="2236750915056607613">"Correction du texte"</string>
+ <string name="gesture_typing_category" msgid="497263612130532630">"Saisie gestuelle"</string>
+ <string name="misc_category" msgid="6894192814868233453">"Autres options"</string>
+ <string name="advanced_settings" msgid="362895144495591463">"Paramètres avancés"</string>
+ <string name="advanced_settings_summary" msgid="4487980456152830271">"Options destinées aux experts"</string>
+ <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Autres modes de saisie"</string>
+ <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"La touche de sélection de langue couvre d\'autres modes de saisie"</string>
+ <string name="show_language_switch_key" msgid="5915478828318774384">"Touche de sélection de langue"</string>
+ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Afficher lorsque plusieurs langues de saisie sont activées"</string>
+ <string name="sliding_key_input_preview" msgid="6604262359510068370">"Aff. indicateur saisie gestuelle"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Aff. un repère visuel si l\'utilisateur appuie sur Maj ou Symboles"</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Masquer touche agrandie"</string>
+ <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Aucun délai"</string>
+ <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string>
+ <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+ <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_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>
+ <string name="auto_cap_summary" msgid="7934452761022946874">"Majuscule au premier mot de chaque phrase"</string>
+ <string name="edit_personal_dictionary" msgid="3996910038952940420">"Dictionnaire personnel"</string>
+ <string name="configure_dictionaries_title" msgid="4238652338556902049">"Dictionnaires complémentaires"</string>
+ <string name="main_dictionary" msgid="4798763781818361168">"Dictionnaire principal"</string>
+ <string name="prefs_show_suggestions" msgid="8026799663445531637">"Suggestions de correction"</string>
+ <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Afficher les suggestions de terme lors de la saisie"</string>
+ <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Toujours afficher"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Afficher en mode Portrait"</string>
+ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Toujours masquer"</string>
+ <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Bloquer les termes choquants"</string>
+ <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Pas de termes potentiellement choquants"</string>
+ <string name="auto_correction" msgid="7630720885194996950">"Correction auto"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Corriger autom. orthographe (pression sur barre espace/signes ponctuation)"</string>
+ <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Désactiver"</string>
+ <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Simple"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Proactive"</string>
+ <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Très exigeante"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Suggestions pour le mot suivant"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Utiliser le mot précédent pour les suggestions"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Activer la saisie gestuelle"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"Saisir un mot en faisant glisser le doigt sur les lettres"</string>
+ <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="label_go_key" msgid="1635148082137219148">"Aller"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Suivant"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Préc."</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Terminé"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Envoyer"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Suspendre"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Attendre"</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_description_unknown" msgid="3197434010402179157">"Code touche %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Maj"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Touche Maj activée (appuyer pour désactiver)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Verrouillage des majuscules activé (appuyer pour désactiver)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Supprimer"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Symboles"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Lettres"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Nombres"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Paramètres"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Onglet"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Espace"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Saisie vocale"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Émoticône"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Renvoyer"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Rechercher"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Point"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Changer de langue"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Suivant"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Précédent"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Touche Maj activée"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Verrouillage des majuscules activé"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Touche Maj désactivée"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mode Symboles"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mode Lettres"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mode Téléphone"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mode Symboles du téléphone"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Clavier masqué"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Affichage du clavier <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"Date"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"Date et heure"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"Courriel"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"SMS/MMS"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"Nombre"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"Numéro de téléphone"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"Texte"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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="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>
+ <string name="select_language" msgid="3693815588777926848">"Langues de saisie"</string>
+ <string name="hint_add_to_dictionary" msgid="573678656946085380">"Appuyer de nouveau pour enregistrer"</string>
+ <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Autoriser les commentaires des utilisateurs"</string>
+ <string name="prefs_description_log" msgid="7525225584555429211">"Contribuer à l\'amélioration de cet éditeur du mode de saisie grâce à l\'envoi automatique de statistiques d\'utilisation et de rapports d\'erreur"</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"Thème du clavier"</string>
+ <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_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>
+ <string name="subtype_no_language_azerty" msgid="8144348527575640087">"Alphabet latin (AZERTY)"</string>
+ <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alphabet latin (Dvorak)"</string>
+ <string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alphabet latin (Colemak)"</string>
+ <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alphabet latin (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Styles saisie personnalisés"</string>
+ <string name="add_style" msgid="6163126614514489951">"Ajouter style"</string>
+ <string name="add" msgid="8299699805688017798">"Ajouter"</string>
+ <string name="remove" msgid="4486081658752944606">"Supprimer"</string>
+ <string name="save" msgid="7646738597196767214">"Enregistrer"</string>
+ <string name="subtype_locale" msgid="8576443440738143764">"Langue"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Disposition"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Vous devez activer votre style de saisie personnalisé avant de l\'utiliser. Voulez-vous le faire maintenant ?"</string>
+ <string name="enable" msgid="5031294444630523247">"Activer"</string>
+ <string name="not_now" msgid="6172462888202790482">"Pas maintenant"</string>
+ <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Le style de saisie suivant existe déjà : <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
+ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'étude de l\'utilisabilité"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Délai appui prolongé sur touche"</string>
+ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durée vibration press. touche"</string>
+ <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume pression de touche"</string>
+ <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="error" msgid="8940763624668513648">"Une erreur s\'est produite"</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>
+ <string name="setup_start_action" msgid="8936036460897347708">"Commencer"</string>
+ <string name="setup_next_action" msgid="371821437915144603">"Étape suivante"</string>
+ <string name="setup_steps_title" msgid="6400373034871816182">"Configurer <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_title" msgid="3147967630253462315">"Activer <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_instruction" msgid="2578631936624637241">"Sous \"Langue et saisie\", cochez \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" pour autoriser son exécution sur l\'appareil."</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"L\'application \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" est déjà activée dans vos paramètres \"Langue et saisie\". Passez à l\'étape suivante."</string>
+ <string name="setup_step1_action" msgid="4366513534999901728">"Activer le clavier dans les paramètres"</string>
+ <string name="setup_step2_title" msgid="6860725447906690594">"Basculer vers <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step2_instruction" msgid="9141481964870023336">"Sélectionnez ensuite \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" comme mode de saisie actif."</string>
+ <string name="setup_step2_action" msgid="1660330307159824337">"Changer de mode de saisie"</string>
+ <string name="setup_step3_title" msgid="3154757183631490281">"Félicitations, l\'opération est terminée"</string>
+ <string name="setup_step3_instruction" msgid="8025981829605426000">"Avec <xliff:g id="APPLICATION_NAME">%s</xliff:g>, vous pouvez saisir du texte dans toutes vos applications préférées."</string>
+ <string name="setup_step3_action" msgid="600879797256942259">"Configurer des langues supplémentaires"</string>
+ <string name="setup_finish_action" msgid="276559243409465389">"OK"</string>
+ <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Afficher icône application"</string>
+ <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Afficher l\'icône de l\'application dans le lanceur"</string>
+ <string name="app_name" msgid="6320102637491234792">"Fournisseur de dictionnaires"</string>
+ <string name="dictionary_provider_name" msgid="3027315045397363079">"Fournisseur de dictionnaires"</string>
+ <string name="dictionary_service_name" msgid="6237472350693511448">"Service de dictionnaires"</string>
+ <string name="download_description" msgid="6014835283119198591">"Informations relatives à la mise à jour des dictionnaires"</string>
+ <string name="dictionary_settings_title" msgid="8091417676045693313">"Dictionnaires complémentaires"</string>
+ <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Dictionnaire disponible"</string>
+ <string name="dictionary_settings_summary" msgid="5305694987799824349">"Paramètres des dictionnaires"</string>
+ <string name="user_dictionaries" msgid="3582332055892252845">"Dictionnaires personnels"</string>
+ <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Dictionnaire personnel"</string>
+ <string name="dictionary_available" msgid="4728975345815214218">"Dictionnaire disponible"</string>
+ <string name="dictionary_downloading" msgid="2982650524622620983">"Téléchargement en cours…"</string>
+ <string name="dictionary_installed" msgid="8081558343559342962">"Installé"</string>
+ <string name="dictionary_disabled" msgid="8950383219564621762">"Installé, désactivé"</string>
+ <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Pas de service dico."</string>
+ <string name="no_dictionaries_available" msgid="8039920716566132611">"Aucun dictionnaire"</string>
+ <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="main_dict_description" msgid="3072821352793492143">"Dictionnaire principal"</string>
+ <string name="cancel" msgid="6830980399865683324">"Annuler"</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="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_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="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>
+ <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Expression"</string>
+ <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"Plus d\'options"</string>
+ <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Moins d\'options"</string>
+ <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OK"</string>
+ <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Mot :"</string>
+ <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Raccourci :"</string>
+ <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Langue :"</string>
+ <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Saisissez un mot"</string>
+ <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Raccourci facultatif"</string>
+ <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Modifier le mot"</string>
+ <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Modifier"</string>
+ <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Supprimer"</string>
+ <string name="user_dict_settings_empty_text" msgid="558499587532668203">"Votre dictionnaire personnel ne contient aucun mot. Ajoutez un mot en appuyant sur le bouton d\'ajout (\"+\")."</string>
+ <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"Pour toutes les langues"</string>
+ <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"Plus de langues…"</string>
+ <string name="user_dict_settings_delete" msgid="110413335187193859">"Supprimer"</string>
+ <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
</resources>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index edabdb3ee..e096a1fb8 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alphabet latin (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alphabet latin (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alphabet latin (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Styles saisie personnalisés"</string>
<string name="add_style" msgid="6163126614514489951">"Ajouter style"</string>
<string name="add" msgid="8299699805688017798">"Ajouter"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 19135ff52..dcbbcd97c 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -31,7 +31,7 @@
<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" 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>
@@ -41,7 +41,7 @@
<string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"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="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>
@@ -50,8 +50,8 @@
<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="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>
@@ -130,7 +130,7 @@
<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="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>
@@ -143,13 +143,15 @@
<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_no_language" msgid="7137390094240139495">"कोई भाषा नहीं (लैटिन वर्णाक्षर)"</string>
+ <string name="subtype_nepali_traditional" msgid="9032247506728040447">"<xliff:g id="LANGUAGE">%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">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"कस्‍टम इनपुट शैलियां"</string>
<string name="add_style" msgid="6163126614514489951">"शैली जोड़ें"</string>
<string name="add" msgid="8299699805688017798">"जोड़ें"</string>
@@ -164,56 +166,56 @@
<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="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="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_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_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="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="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="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="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="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; आपके लेखन अनुभव को बेहतर बनाने के लिए हम <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="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="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>
@@ -225,7 +227,7 @@
<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_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>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 084d5b6fb..0dca64ef0 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Abeceda (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Abeceda (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Abeceda (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Prilagođeni stilovi unosa"</string>
<string name="add_style" msgid="6163126614514489951">"Dodaj stil"</string>
<string name="add" msgid="8299699805688017798">"Dodaj"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index a335aa957..2abed7401 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Ábécé (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Ábécé (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Ábécé (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Hangulatjel"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Egyedi bevitelstílusok"</string>
<string name="add_style" msgid="6163126614514489951">"Új stílus"</string>
<string name="add" msgid="8299699805688017798">"Hozzáadás"</string>
diff --git a/java/res/values-hy-rAM/strings-appname.xml b/java/res/values-hy-rAM/strings-appname.xml
new file mode 100644
index 000000000..dc3c0c678
--- /dev/null
+++ b/java/res/values-hy-rAM/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">"Android Ստեղնաշար (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android տառասխալների ուղղիչ (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android ստեղնաշարի կարգավորումներ (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android տառասխալների ուղղիչի կարգավորումներ (AOSP)"</string>
+</resources>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
new file mode 100644
index 000000000..fdf07420c
--- /dev/null
+++ b/java/res/values-hy-rAM/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">"Ցուցադրել տեսողական հուշումը Shift-ի կամ նշանների ստեղներից սահեցման ընթացքում"</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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>` պահված է"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Առաջ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Հաջորդը"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Նխրդ"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Կատարված է"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Ուղարկել"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Դադար"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Սպասել"</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_description_unknown" msgid="3197434010402179157">"Բանալու կոդը՝ %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift-ը միացված է (հպել անջատելու համար)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock-ը միացված է (հպել՝ անջատելու համար)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Ջնջել"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Նշաններ"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Տառեր"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Թվեր"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Կարգավորումներ"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Բացակ"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Ձայնային մուտքագրում"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Ժպիտ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Վերադարձ"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Որոնել"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Կետ"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Փոխել լեզուն"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Հաջորդը"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Նախորդը"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift-ը միացված է"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock-ը միացված է"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift-ն անջատված է"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Նշանների ռեժիմ"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Տառերի ռեժիմ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Հեռախոսային ռեժիմ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Հեռախոսի նշանների ռեժիմ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Ստեղնաշարը թաքցված է"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Ցուցադրված է <xliff:g id="MODE">%s</xliff:g> ստեղնաշարը"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"ամսաթիվ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"ամսաթիվ և ժամ"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"էլփոստ"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"նամակագրություն"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"թվեր"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"հեռախոսահամար"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"տեքստ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ժամանակ"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"Իսպաներեն (ԱՄՆ)"</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_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="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">"Lեզու"</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>»-ը ձեր Լեզվի &amp; մուտքագրման կարգավորումներում: Դա կլիազորի նրան գործարկվել ձեր սարքում:"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>-ն արդեն միացված է ձեր Լեզվի &amp; մուտքագրման կարգավորումներում, ուստի այս քայլն արված է: Անցնել հաջորդին:"</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="8689096636874758814">"Բեռնվում է..."</string>
+ <string name="main_dict_description" msgid="3072821352793492143">"Հիմնական բառարան"</string>
+ <string name="cancel" msgid="6830980399865683324">"Չեղարկել"</string>
+ <string name="install_dict" msgid="180852772562189365">"Տեղադրել"</string>
+ <string name="cancel_download_dict" msgid="7843340278507019303">"Չեղարկել"</string>
+ <string name="delete_dict" msgid="756853268088330054">"Ջնջել"</string>
+ <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Ձեր բջջային սարքում ընտրված լեզվով առկա է բառարան:<br/> Խորհուրդ ենք տալիս &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="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">"Սեղմեք՝ վերանայելու և ներբեռնելու համար"</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">"Լավ"</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">"Lեզուն՝"</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">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
+</resources>
diff --git a/java/res/values-hy/donottranslate.xml b/java/res/values-hy/donottranslate.xml
new file mode 100644
index 000000000..4a6d188fb
--- /dev/null
+++ b/java/res/values-hy/donottranslate.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Same list as in English, but add armenian period and comma: -->
+ <!-- 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>
+ <!-- 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>
+</resources>
diff --git a/java/res/values-hy/strings-appname.xml b/java/res/values-hy/strings-appname.xml
new file mode 100644
index 000000000..dc3c0c678
--- /dev/null
+++ b/java/res/values-hy/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">"Android Ստեղնաշար (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android տառասխալների ուղղիչ (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android ստեղնաշարի կարգավորումներ (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android տառասխալների ուղղիչի կարգավորումներ (AOSP)"</string>
+</resources>
diff --git a/java/res/values-hy/strings.xml b/java/res/values-hy/strings.xml
new file mode 100644
index 000000000..ec4eb4651
--- /dev/null
+++ b/java/res/values-hy/strings.xml
@@ -0,0 +1,242 @@
+<?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">"Ցուցադրել տեսողական հուշումը Shift-ի կամ նշանների ստեղներից սահեցման ընթացքում"</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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>` պահված է"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Առաջ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Հաջորդը"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Նխրդ"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Կատարված է"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Ուղարկել"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Դադար"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Սպասել"</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_description_unknown" msgid="3197434010402179157">"Բանալու կոդը՝ %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift-ը միացված է (հպել անջատելու համար)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock-ը միացված է (հպել՝ անջատելու համար)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Ջնջել"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Նշաններ"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Տառեր"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Թվեր"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Կարգավորումներ"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Բացակ"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Ձայնային մուտքագրում"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Ժպիտ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Վերադարձ"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Որոնել"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Կետ"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Փոխել լեզուն"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Հաջորդը"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Նախորդը"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift-ը միացված է"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock-ը միացված է"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift-ն անջատված է"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Նշանների ռեժիմ"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Տառերի ռեժիմ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Հեռախոսային ռեժիմ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Հեռախոսի նշանների ռեժիմ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Ստեղնաշարը թաքցված է"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Ցուցադրված է <xliff:g id="MODE">%s</xliff:g> ստեղնաշարը"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"ամսաթիվ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"ամսաթիվ և ժամ"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"էլփոստ"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"նամակագրություն"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"թվեր"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"հեռախոսահամար"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"տեքստ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ժամանակ"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"Իսպաներեն (ԱՄՆ)"</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_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="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">"Lեզու"</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>»-ը ձեր Լեզվի &amp; մուտքագրման կարգավորումներում: Դա կլիազորի նրան գործարկվել ձեր սարքում:"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>-ն արդեն միացված է ձեր Լեզվի &amp; մուտքագրման կարգավորումներում, ուստի այս քայլն արված է: Անցնել հաջորդին:"</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="8689096636874758814">"Բեռնվում է..."</string>
+ <string name="main_dict_description" msgid="3072821352793492143">"Հիմնական բառարան"</string>
+ <string name="cancel" msgid="6830980399865683324">"Չեղարկել"</string>
+ <string name="install_dict" msgid="180852772562189365">"Տեղադրել"</string>
+ <string name="cancel_download_dict" msgid="7843340278507019303">"Չեղարկել"</string>
+ <string name="delete_dict" msgid="756853268088330054">"Ջնջել"</string>
+ <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Ձեր բջջային սարքում ընտրված լեզվով առկա է բառարան:<br/> Խորհուրդ ենք տալիս &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="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">"Սեղմեք՝ վերանայելու և ներբեռնելու համար"</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">"Լավ"</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">"Lեզուն՝"</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">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
+</resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 229cf8586..c73c26c1a 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Abjad (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Abjad (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Abjad (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Gaya masukan khusus"</string>
<string name="add_style" msgid="6163126614514489951">"Tambah gaya"</string>
<string name="add" msgid="8299699805688017798">"Tambahkan"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 310ffee63..eb8e1e959 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Stili personalizzati"</string>
<string name="add_style" msgid="6163126614514489951">"Aggiungi stile"</string>
<string name="add" msgid="8299699805688017798">"Aggiungi"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 3c0cbad54..e71bd3190 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -39,7 +39,7 @@
<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">"הצג סימון ויזואלי בעת הסטה מ-Shift או ממקשי סמלים"</string>
- <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"עיכוב סגירת חלון קופץ של מקש"</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>
@@ -51,7 +51,7 @@
<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="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>
@@ -71,13 +71,13 @@
<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" 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="label_go_key" msgid="1635148082137219148">"בצע"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"התחל"</string>
<string name="label_next_key" msgid="362972844525672568">"הבא"</string>
<string name="label_previous_key" msgid="1211868118071386787">"הקודם"</string>
- <string name="label_done_key" msgid="2441578748772529288">"סיום"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"בוצע"</string>
<string name="label_send_key" msgid="2815056534433717444">"שלח"</string>
<string name="label_pause_key" msgid="181098308428035340">"השהה"</string>
<string name="label_wait_key" msgid="6402152600878093134">"המתן"</string>
@@ -93,18 +93,18 @@
<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_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_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_on" msgid="5700440798609574589">"Shift פועל"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps Lock פועל"</string>
<string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift מושבת"</string>
<string name="spoken_description_mode_symbol" msgid="7183343879909747642">"מצב סמלים"</string>
<string name="spoken_description_mode_alpha" msgid="3528307674390156956">"מצב אותיות"</string>
@@ -134,7 +134,7 @@
<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_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>
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"סגנונות קלט מותאמים אישית"</string>
<string name="add_style" msgid="6163126614514489951">"הוסף סגנון"</string>
<string name="add" msgid="8299699805688017798">"הוסף"</string>
@@ -161,7 +163,7 @@
<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_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>
@@ -173,7 +175,7 @@
<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_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>
@@ -184,11 +186,11 @@
<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_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="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>
@@ -209,7 +211,7 @@
<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="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>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 594220613..4d3f155bb 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"カスタム入力スタイル"</string>
<string name="add_style" msgid="6163126614514489951">"スタイル追加"</string>
<string name="add" msgid="8299699805688017798">"追加"</string>
diff --git a/java/res/values-ka-rGE/strings-appname.xml b/java/res/values-ka-rGE/strings-appname.xml
new file mode 100644
index 000000000..703c66aac
--- /dev/null
+++ b/java/res/values-ka-rGE/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">"Android-ის კლავიატურა (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android-ის მართლწერის შემმოწმებელი (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android-ის კლავიატურის პარამეტრები (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android-ის მართლწერის შემმოწმებლის პარამეტრები (AOSP)"</string>
+</resources>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
new file mode 100644
index 000000000..043c14c94
--- /dev/null
+++ b/java/res/values-ka-rGE/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">"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>
+ <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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : შეინახა"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"წასვლა"</string>
+ <string name="label_next_key" msgid="362972844525672568">"შემდ."</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"წინა"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"დასრულდა"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"გაგზ."</string>
+ <string name="label_pause_key" msgid="181098308428035340">"პაუზა"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"მოცდა"</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_description_unknown" msgid="3197434010402179157">"კლავიატურის კოდი %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ჩართულია (შეეხეთ გამოსართავად)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"ჩართულია Caps (შეეხეთ გამოსართავად)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"სიმბოლოები"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"ასოები"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"ნომრები"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"პარამეტრები"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"შორისი"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"ხმოვანი შეყვანა"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"ღიმილი"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"დაბრუნება"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"ძიება"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"წერტილი"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"ენის გადართვა"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"შემდეგი"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"წინა"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ჩართულია"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"ჩართულია Caps"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift გამორთულია"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"სიმბოლოების რეჟიმი"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"ასოების რეჟიმი"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"ტელეფონის რეჟიმი"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"ტელეფონის სიმბოლოების რეჟიმი"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"კლავიატურა დამალულია"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"ნაჩვენებია <xliff:g id="MODE">%s</xliff:g> კლავიატურა"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"თარიღი"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"თარიღი და დრო"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"ელფოსტა"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"შეტყობინებები"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"რიცხვები"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"ტელეფონი"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"ტექსტი"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"დრო"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"შეიტანეთ წვლილი შეყვანის ამ მეთოდის გაუმჯობესებაში — გააგზავნეთ მოხმარების სტატისტიკა და ავარიული გათიშვების ანგარიშები"</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="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_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="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">"ამიერიდან შეძლებთ ყველა სასურველ აპში <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="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/&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_description" msgid="1075194169443163487">"დააჭირეთ განხილვას და ჩამოტვირთეთ"</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">"კარგი"</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">"თქვენ არ გაქვთ სიტყვები მომხმარებლის ლექსიკონში. დაამატეთ სიტყვები ღილაკ Add (+) შეხებით."</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-ka/strings-appname.xml b/java/res/values-ka/strings-appname.xml
new file mode 100644
index 000000000..703c66aac
--- /dev/null
+++ b/java/res/values-ka/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">"Android-ის კლავიატურა (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android-ის მართლწერის შემმოწმებელი (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android-ის კლავიატურის პარამეტრები (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android-ის მართლწერის შემმოწმებლის პარამეტრები (AOSP)"</string>
+</resources>
diff --git a/java/res/values-km-rKH/strings-appname.xml b/java/res/values-km-rKH/strings-appname.xml
new file mode 100644
index 000000000..e7b27072e
--- /dev/null
+++ b/java/res/values-km-rKH/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">"ក្ដារចុច Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"កម្មវិធី​ពិនិត្យ​អក្ខរាវិរុទ្ធ Android (AOSP​)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"ការ​កំណត់​ក្ដារ​ចុច Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"កំណត់​​កម្មវិធី​ពិនិត្យ​​អក្ខរាវិរុទ្ធ​សម្រាប់ ​​Android (AOSP)"</string>
+</resources>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
new file mode 100644
index 000000000..aa40a7a02
--- /dev/null
+++ b/java/res/values-km-rKH/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_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="added_word" msgid="8993883354622484372">"បាន​រក្សាទុក <xliff:g id="WORD">%s</xliff:g> ៖"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"ទៅ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"បន្ទាប់"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"មុន"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"រួចរាល់"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"ផ្ញើ"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"ផ្អាក"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"រង់ចាំ"</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_description_unknown" msgid="3197434010402179157">"កូដ​គ្រាប់​ចុច %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"បើក Shift (​ប៉ះ​ដើម្បី​បិទ)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"បើក Caps lock (ប៉ះ​​ដើម្បី​បិទ)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"និមិត្ត​សញ្ញា"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"អក្សរ"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"លេខ"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"ការ​កំណត់"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"ដកឃ្លា"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"បញ្ចូលសំឡេង"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"មុខ​ញញឹម"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"ស្វែងរក"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"ប្ដូរ​​ភាសា"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"បន្ទាប់"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"មុន"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"បាន​បើក Shift"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"បាន​បើក Caps lock"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"បាន​បិទ Shift"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"របៀប​និមិត្តសញ្ញា"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"របៀប​អក្សរ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"របៀប​ទូរស័ព្ទ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"​របៀប​និមិត្ត​សញ្ញា​ទូរស័ព្ទ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"បាន​លាក់​ក្ដារចុច"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"បង្ហាញ​ក្ដារ​ចុច <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"កាលបរិច្ឆេទ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"កាល​បរិច្ឆេទ​ និង​ពេល​វេលា"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"អ៊ីមែល"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"​ផ្ញើ​សារ"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"លេខ"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"ទូរស័ព្ទ"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"អត្ថបទ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ពេលវេលា"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"ជំនួយ​​​ធ្វើ​ឲ្យ​​ប្រសើរ​ឡើង​​នៃ​កម្មវិធី​កែ​​វិធី​សាស្ត្រ​​បញ្ចូល​ដោយ​ស្វ័យ​ប្រវត្តិ​ ដោយ​ផ្ញើ​ស្ថិតិ​​ប្រើ​ប្រាស់​ ​និង​របាយការណ៍​គាំង"</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="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_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">"តាម​លំដាប់​អក្សរក្រម (កុំព្យូទ័រ)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"សញ្ញា​អារម្មណ៍"</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="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>\" នៅ​ក្នុង​ការ​កំណត់​ភាសា &amp; និង​ការ​បញ្ចូល​របស់​អ្នក។ វា​នឹង​ដំណើរការ​នៅ​លើ​ឧបករណ៍​របស់​អ្នក។"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>បាន​បើក​នៅ​ក្នុង​​ការ​កំណត់​​ភាសា​ &amp; ការ​បញ្ចូល​របស់ ដូច្នេះ​ជំហាន​នេះ​រួចរាល់​ហើយ។ បន្ត​ទៅ​ជំហាន​បន្ទាប់!"</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="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; ប្រសិនបើ​​អ្នក​មិន​ប្រាកដ​​ថា​ទិន្នន័យ​អ្នក​​មិន​បាន​​កំណត់ យើង​បាន​ផ្ដល់​អនុសាសន៍​ដោយ​ស្វែងរក​ការ​ភ្ជាប់​​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យប្រវត្តិ។&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_description" msgid="1075194169443163487">"ចុច​ ដើម្បី​ពិនិត្យ​មើល​ឡើង​​វិញ​ និង​ទាញ​យក"</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">"យល់ព្រម"</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-km/donottranslate.xml b/java/res/values-km/donottranslate.xml
new file mode 100644
index 000000000..a9893feec
--- /dev/null
+++ b/java/res/values-km/donottranslate.xml
@@ -0,0 +1,23 @@
+<?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">
+ <!-- Whether this language uses spaces between words -->
+ <bool name="current_language_has_spaces">false</bool>
+</resources>
diff --git a/java/res/values-km/strings-appname.xml b/java/res/values-km/strings-appname.xml
new file mode 100644
index 000000000..e7b27072e
--- /dev/null
+++ b/java/res/values-km/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">"ក្ដារចុច Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"កម្មវិធី​ពិនិត្យ​អក្ខរាវិរុទ្ធ Android (AOSP​)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"ការ​កំណត់​ក្ដារ​ចុច Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"កំណត់​​កម្មវិធី​ពិនិត្យ​​អក្ខរាវិរុទ្ធ​សម្រាប់ ​​Android (AOSP)"</string>
+</resources>
diff --git a/java/res/values-km/strings.xml b/java/res/values-km/strings.xml
new file mode 100644
index 000000000..03b973885
--- /dev/null
+++ b/java/res/values-km/strings.xml
@@ -0,0 +1,242 @@
+<?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">"បង្ហាញ​អត្ថបទ​ដែល​មើល​ឃើញ​ខណៈ​ពេល​ដែល sliding ពី​គ្រាប់ចុច​ប្ដូរ​ឬ​និមិត្ត​សញ្ញា"</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>ms"</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_double_space_period" msgid="8781529969425082860">"រយៈ​ពេល​ចុច space ពីរដង"</string>
+ <string name="use_double_space_period_summary" msgid="6532892187247952799">"ចុច​ tap ពីរ​​ដង​លើ​ spacebar រយៈ​ពេល​​បញ្ចូល​​​ដែល​បាន​អនុវត្ត​ដោយ​ចុច space"</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">"Spacebar ​និង​សញ្ញា​​វណ្ណយុត្ត​កែ​ពាក្យ​ដែល​បាន​វាយ​ខុស​ស្វ័យប្រវត្តិ"</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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : បាន​រក្សាទុក"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"ទៅ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"បន្ទាប់"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"មុន"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"រួចរាល់"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"ផ្ញើ"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"ផ្អាក"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"រង់ចាំ"</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_description_unknown" msgid="3197434010402179157">"កូដ​គ្រាប់​ចុច %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"បើក Shift (ចុច tap ដើម្បី​បិទ)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"បើក Caps lock (ចុច​ tap ដើម្បី​បិទ)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Delete"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"និមិត្ត​សញ្ញា"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Letters"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"លេខ"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"ការ​កំណត់"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Space"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"ការ​បញ្ចូល​សំឡេង"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"មុខ​ញញឹម"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"ស្វែងរក"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"ប្ដូរ​​ភាសា"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"បន្ទាប់"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"មុន"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"បាន​បើក Shift"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"បាន​បើក Caps lock"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"បាន​បិទ Shift"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"របៀប​និមិត្តសញ្ញា"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"របៀប​អក្សរ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"របៀប​ទូរស័ព្ទ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"​របៀប​និមិត្ត​សញ្ញា​ទូរស័ព្ទ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"បាន​លាក់​ក្ដារចុច"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"បង្ហាញ​ក្ដារ​ចុច <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"កាលបរិច្ឆេទ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"កាល​បរិច្ឆេទ​ និង​ពេល​វេលា"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"អ៊ីមែល"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"ការ​ផ្ញើ​សារ"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"លេខ"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"ទូរស័ព្ទ"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"អត្ថបទ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ពេលវេលា"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"ជំនួយ​​​ធ្វើ​ឲ្យ​​ប្រសើរ​ឡើង​​នៃ​កម្មវិធី​កែ​​វិធី​សាស្ត្រ​​បញ្ចូល​ដោយ​ស្វ័យ​ប្រវត្តិ​ដោយ​ការ​ផ្ញើ​ស្ថិតិ​ការ​ប្រើ​ប្រាស់​ ​និង​របាយការណ៍​គាំង"</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="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_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">"អក្សរ​ក្រម (កុំព្យូទ័រ)"</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="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>\" នៅ​ក្នុង​ការ​កំណត់​ភាសា &amp; និង​ការ​បញ្ចូល​របស់​អ្នក។ វា​នឹង​ដំណើរការ​នៅ​លើ​ឧបករណ៍​របស់​អ្នក។"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> បាន​បើក​នៅ​ក្នុង​​ការ​កំណត់​​ភាសា​ &amp; ការ​បញ្ចូល​របស់ ដូច្នេះ​ជំហាន​នេះ​រួចរាល់​ហើយ។ បន្ត​ទៅ​ជំហាន​បន្ទាប់!"</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="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; ប្រសិនបើ​​អ្នក​មិន​ប្រាកដ​​ថា​ទិន្នន័យ​អ្នក​​មិន​បាន​​កំណត់ យើង​បាន​ផ្ដល់​អនុសាសន៍​ដោយ​ស្វែងរក​ការ​តភ្ជាប់​​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យប្រវត្តិ។&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">"ទាញ​យក​តាម​វ៉ាយហ្វាយ"</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">"ចុច​ដើម្បី​ពិនិត្យ​មើល​ឡើង​​វិញ​ និង​ទាញ​យក"</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">"យល់​ព្រម"</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-ko/strings.xml b/java/res/values-ko/strings.xml
index e729fc60d..a74b4f1f4 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"알파벳(드보락)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"알파벳(콜맥)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"알파벳(PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"이모티콘"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"맞춤 입력 스타일"</string>
<string name="add_style" msgid="6163126614514489951">"스타일 추가"</string>
<string name="add" msgid="8299699805688017798">"추가"</string>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index c78c25f86..42a746b60 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -26,14 +26,8 @@
<!-- key_height + key_bottom_gap = popup_key_height -->
<dimen name="popup_key_height">44.8dp</dimen>
- <fraction name="keyboard_top_padding">1.818%p</fraction>
- <fraction name="keyboard_bottom_padding">0.0%p</fraction>
- <fraction name="key_bottom_gap">4.330%p</fraction>
- <fraction name="key_horizontal_gap">0.405%p</fraction>
-
- <fraction name="key_bottom_gap_stone">5.010%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.159%p</fraction>
-
+ <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>
@@ -53,7 +47,7 @@
<fraction name="key_uppercase_letter_ratio">40%</fraction>
<fraction name="key_preview_text_ratio">90%</fraction>
<fraction name="spacebar_text_ratio">40.000%</fraction>
- <dimen name="key_preview_offset">0.0dp</dimen>
+ <dimen name="key_preview_offset_gb">0.0dp</dimen>
<!-- For 5-row keyboard -->
<fraction name="key_bottom_gap_5row">3.20%p</fraction>
@@ -72,11 +66,18 @@
<!-- 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">-44.8dp</dimen>
+ <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">60%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">20</integer>
+
</resources>
diff --git a/java/res/values-lo-rLA/strings-appname.xml b/java/res/values-lo-rLA/strings-appname.xml
new file mode 100644
index 000000000..17a009483
--- /dev/null
+++ b/java/res/values-lo-rLA/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">"ແປ້ນພິມ Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"ໂຕກວດການສະກົດຄຳໃນ Android (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"ຕັ້ງຄ່າແປ້ນພິມ Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Spell Checker Settings (AOSP)"</string>
+</resources>
diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml
new file mode 100644
index 000000000..f848a8ff3
--- /dev/null
+++ b/java/res/values-lo-rLA/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">"Research Log Commands"</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">"ການພິມແບບ Gesture"</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">"ສະແດງແນວທາງໃນຂະນະທີ່ສະໄລ້ຈາກ Shift ຫຼື ປຸ່ມເຄື່ອງໝາຍ"</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>ms"</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_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">"ເປີດນຳໃຊ້ການພິມແບບ Gesture"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"ໃສ່ຄຳສັບລົງໄປໂດຍການສະໄລ້ຜ່ານໂຕອັກສອນ"</string>
+ <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="label_go_key" msgid="1635148082137219148">"ໄປ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"ຕໍ່ໄປ"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"ກ່ອນໜ້າ"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"ແລ້ວໆ"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"ສົ່ງ"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"ຄ້າງໄວ້"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"ລໍຖ້າ"</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_description_unknown" msgid="3197434010402179157">"ລະຫັດກະແຈ %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ເປີດນຳໃຊ້ຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock ເປີດຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"ລຶບ"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"ສັນຍາລັກ"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"ໂຕອັກ​ສອນ"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"ໂຕເລກ"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"ການຕັ້ງຄ່າ"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ແທັບ"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"ຍະຫວ່າງ"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"ການປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"ຮອຍຍິ້ມ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"ກັບຄືນ"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"ຊອກຫາ"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"ຈ້ຳ"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"ສະລັບພາສາ"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"ຕໍ່ໄປ"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"ກ່ອນໜ້າ"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ເປີດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ເປີດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift ປິດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"ໂຫມດສັນຍາລັກ"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"ໂຫມດ​ໂຕອັກ​ສອນ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"ໂຫມດໂທລະສັບ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"ໂຫມດສັນຍາລັກໂທລະສັບ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"ແປ້ນ​ພິມ​ເຊື່ອງ​ໄວ້"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"ກຳລັງສະແດງແປ້ນພິມ <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"ວັນທີ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"ວັນ​ທີ​ແລະ​ເວ​ລາ"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"email"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"ຂໍ້ຄວາມ"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"ໂຕເລກ"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"ໂທລະສັບ"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"ຂໍ້ຄວາມ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ເວລາ"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"ຊ່ວຍເພີ່ມປະສິດທິພາບໂຕແກ້ໄຂການປ້ອນຂໍ້ມູນ ໂດຍການສົ່ງສະຖິຕິການນຳໃຊ້ ແລະການລາຍການຂໍ້ຜິດພາດໂດຍອັດຕະໂນມັດ"</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="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_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="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">"ໂໝດການສຶກສາ Usability"</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">"ດ້ວຍການພິມແບບ Gesture"</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>\" ໃນການຕັ້ງຄ່າພາສາ &amp; ການປ້ອນຂໍ້ມູນຂອງທ່ານ. ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ມັນເຮັດວຽກໃນອຸປະກອນຂອງທ່ານ"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ຖືກເປີດນຳໃຊ້ໃນການຕັ້ງຄ່າພາສາ &amp; ການປ້ອນຂໍ້ມູນຂອງທ່ານແລ້ວ, ສະນັ້ນຂັ້ນຕອນນີ້ແມ່ນສຳເລັດໄປແລ້ວ. ໄປທີ່ຂັ້ນຕອນຕໍ່ໄປ!"</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">"ສະແດງໄອຄອນຂອງແອັບຯໃນ Launcher"</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;ພາສາ &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_description" msgid="1075194169443163487">"ກົດທີ່ກວດຄືນ ແລະ ດາວໂຫລດ"</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">"ຕົກລົງ"</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-lo/donottranslate.xml b/java/res/values-lo/donottranslate.xml
new file mode 100644
index 000000000..a9893feec
--- /dev/null
+++ b/java/res/values-lo/donottranslate.xml
@@ -0,0 +1,23 @@
+<?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">
+ <!-- Whether this language uses spaces between words -->
+ <bool name="current_language_has_spaces">false</bool>
+</resources>
diff --git a/java/res/values-lo/strings-appname.xml b/java/res/values-lo/strings-appname.xml
new file mode 100644
index 000000000..17a009483
--- /dev/null
+++ b/java/res/values-lo/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">"ແປ້ນພິມ Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"ໂຕກວດການສະກົດຄຳໃນ Android (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"ຕັ້ງຄ່າແປ້ນພິມ Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Spell Checker Settings (AOSP)"</string>
+</resources>
diff --git a/java/res/values-lo/strings.xml b/java/res/values-lo/strings.xml
new file mode 100644
index 000000000..cc15a4226
--- /dev/null
+++ b/java/res/values-lo/strings.xml
@@ -0,0 +1,242 @@
+<?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">"Research Log Commands"</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">"ການພິມແບບ Gesture"</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">"ສະແດງແນວທາງໃນຂະນະທີ່ສະໄລ້ຈາກ Shift ຫຼື ປຸ່ມເຄື່ອງໝາຍ"</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>ms"</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_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">"ເປີດນຳໃຊ້ການພິມແບບ Gesture"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"ໃສ່ຄຳສັບລົງໄປໂດຍການສະໄລ້ຜ່ານໂຕອັກສອນ"</string>
+ <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="label_go_key" msgid="1635148082137219148">"ໄປ"</string>
+ <string name="label_next_key" msgid="362972844525672568">"ຕໍ່ໄປ"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"ກ່ອນໜ້າ"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"ແລ້ວໆ"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"ສົ່ງ"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"ຄ້າງໄວ້"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"ລໍຖ້າ"</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_description_unknown" msgid="3197434010402179157">"ລະຫັດກະແຈ %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift ເປີດນຳໃຊ້ຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Caps lock ເປີດຢູ່ (ກົດເພື່ອປິດນຳໃຊ້)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"ລຶບ"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"ສັນ​ຍາ​ລັກ"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"ໂຕອັກ​ສອນ"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"ໂຕເລກ"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"ການຕັ້ງຄ່າ"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ແທັບ"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"ຍະຫວ່າງ"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"ການປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"ຮອຍຍິ້ມ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"ກັບຄືນ"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"ຊອກຫາ"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"ຈ້ຳ"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"ສະລັບພາສາ"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"ຕໍ່ໄປ"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"ກ່ອນໜ້າ"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift ເປີດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Caps lock ເປີດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift ປິດນຳໃຊ້ຢູ່"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"ໂຫມດສັນຍາລັກ"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"ໂຫມດ​ໂຕອັກ​ສອນ"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"ໂຫມດໂທລະສັບ"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"ໂຫມດສັນຍາລັກໂທລະສັບ"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"ແປ້ນ​ພິມ​ເຊື່ອງ​ໄວ້"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"ກຳລັງສະແດງແປ້ນພິມ <xliff:g id="MODE">%s</xliff:g>"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"ວັນທີ"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"ວັນ​ທີ​ແລະ​ເວ​ລາ"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"ອີເມວ"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"ຂໍ້ຄວາມ"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"ໂຕເລກ"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"ໂທລະສັບ"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"ຂໍ້ຄວາມ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"ເວລາ"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"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">"ຊ່ວຍເພີ່ມປະສິດທິພາບໂຕແກ້ໄຂການປ້ອນຂໍ້ມູນ ໂດຍການສົ່ງສະຖິຕິການນຳໃຊ້ ແລະການລາຍການຂໍ້ຜິດພາດໂດຍອັດຕະໂນມັດ"</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"ສີສັນແປ້ນພິມ"</string>
+ <string name="subtype_en_GB" msgid="88170601942311355">"ອັງກິດ (UK)"</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_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="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">"ໂໝດການສຶກສາ Usability"</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">"ດ້ວຍການພິມແບບ Gesture"</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>\" ໃນການຕັ້ງຄ່າພາສາ &amp; ການປ້ອນຂໍ້ມູນຂອງທ່ານ. ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ມັນເຮັດວຽກໃນອຸປະກອນຂອງທ່ານ"</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ຖືກເປີດນຳໃຊ້ໃນການຕັ້ງຄ່າພາສາ &amp; ການປ້ອນຂໍ້ມູນຂອງທ່ານແລ້ວ, ສະນັ້ນຂັ້ນຕອນນີ້ແມ່ນສຳເລັດໄປແລ້ວ. ໄປທີ່ຂັ້ນຕອນຕໍ່ໄປ!"</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">"ສະແດງໄອຄອນຂອງແອັບຯໃນ Launcher"</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;ພາສາ &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_description" msgid="1075194169443163487">"ກົດທີ່ກວດຄືນ ແລະ ດາວໂຫລດ"</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">"ຕົກລົງ"</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-lt/strings.xml b/java/res/values-lt/strings.xml
index 44e01a977..6110858dd 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Abėcėlė (Dvorako)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Abėcėlė („Colemak“)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Abėcėlė (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Jaustukai"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Pasirinkti įvesties stilių"</string>
<string name="add_style" msgid="6163126614514489951">"Prid. stilių"</string>
<string name="add" msgid="8299699805688017798">"Pridėti"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 152ed856d..ecd4e511d 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabēts (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabēts (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabēts (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Japāņu emocijzīmes"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Pielāg. ievades stili"</string>
<string name="add_style" msgid="6163126614514489951">"Piev. stilu"</string>
<string name="add" msgid="8299699805688017798">"Pievienot"</string>
diff --git a/java/res/values-mn-rMN/strings-appname.xml b/java/res/values-mn-rMN/strings-appname.xml
new file mode 100644
index 000000000..6c27e3d34
--- /dev/null
+++ b/java/res/values-mn-rMN/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-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml
new file mode 100644
index 000000000..92c2befa2
--- /dev/null
+++ b/java/res/values-mn-rMN/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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Хадгалагдсан"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"Явах"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Дараах"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Өмнөх"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Дууссан"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Илгээх"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Пауз"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Хүлээх"</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_description_unknown" msgid="3197434010402179157">"Товчийн код %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Сэлгэх"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Сэлгэхийг идэвхжүүлсэн (товшиж идэвхгүйжүүлнэ үү)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Томоор бичихийг асаасан (товшиж идэвхгүйжүүлнэ үү)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Устгах"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Симбол"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Үсэгнүүд"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Тоонууд"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Тохиргоо"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Таб"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Хоосон зай"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Дуугаар оруулах"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Инээсэн царай"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Буцах"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Хайх"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Цэг"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Хэл солих"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Дараах"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Өмнөх"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Сэлгэхийг идэвхжүүлсэн"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Томоор бичихийг идэвхжүүлсэн"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Сэлгэхийг идэвхжүүлээгүй"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Симбол төлөв"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Үсэгнүүд төлөв"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Утасны төлөв"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Утасны символ төлөв"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Гарыг нуусан"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> гарыг харуулж байна"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"огноо"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"огноо болон цаг"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"и"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"зурвас"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"дугаар"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"утас"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"текст"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"цаг"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"Ашиглалтын статистик болон гацалтын репортуудыг автоматаар илгээснээр энэ оруулах арга засагчийг сайжруулахад туслаарай"</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="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_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="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">"Өөрийн Хэл &amp; оруулах тохиргоон дотроос \"<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> таны Хэл &amp;amp оруулах тохиргоонд аль хэдийн идэвхжүүлсэн байгаа учир энэ алхам хийгдсэн. Дараагийн алхам руу!"</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="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; Тус  <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="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_description" msgid="1075194169443163487">"Шалгах болон татаж авахын тулд дарна уу"</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">"Тийм"</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-ms-rMY/strings-appname.xml b/java/res/values-ms-rMY/strings-appname.xml
new file mode 100644
index 000000000..76d1d294c
--- /dev/null
+++ b/java/res/values-ms-rMY/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">"Papan Kekunci Android (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Penyemak Ejaan Android (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Tetapan Papan Kekunci Android (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Tetapan Penyemak Ejaan Android (AOSP)"</string>
+</resources>
diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml
new file mode 100644
index 000000000..49efdf18f
--- /dev/null
+++ b/java/res/values-ms-rMY/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">"Pilihan input"</string>
+ <string name="english_ime_research_log" msgid="8492602295696577851">"Arahan Log Penyelidikan"</string>
+ <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string>
+ <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Penyemak ejaan menggunakan entri dari senarai kenalan anda"</string>
+ <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar pada tekanan kekunci"</string>
+ <string name="sound_on_keypress" msgid="6093592297198243644">"Bunyi pada tekanan kekunci"</string>
+ <string name="popup_on_keypress" msgid="123894815723512944">"Pop timbul pada tekanan kunci"</string>
+ <string name="general_category" msgid="1859088467017573195">"Umum"</string>
+ <string name="correction_category" msgid="2236750915056607613">"Pembetulan teks"</string>
+ <string name="gesture_typing_category" msgid="497263612130532630">"Taipan gerak isyarat"</string>
+ <string name="misc_category" msgid="6894192814868233453">"Pilihan lain"</string>
+ <string name="advanced_settings" msgid="362895144495591463">"Tetapan lanjutan"</string>
+ <string name="advanced_settings_summary" msgid="4487980456152830271">"Pilihan untuk pakar"</string>
+ <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Tukar ke kaedah input lain"</string>
+ <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Kunci pertukaran bahasa meliputi kaedah masukan lain juga"</string>
+ <string name="show_language_switch_key" msgid="5915478828318774384">"Kekunci tukar bahasa"</string>
+ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Tunjukkan apabila berbilang bahasa input didayakan"</string>
+ <string name="sliding_key_input_preview" msgid="6604262359510068370">"Tunjukkan penunjuk slaid"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Paparkan petunjuk visual semasa meluncur daripada kekunci Shift atau Simbol"</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Pop tmbl knci ketpkn lengah"</string>
+ <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tiada kelewatan"</string>
+ <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Lalai"</string>
+ <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+ <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_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>
+ <string name="auto_cap_summary" msgid="7934452761022946874">"Besarkan perkataan pertama setiap ayat"</string>
+ <string name="edit_personal_dictionary" msgid="3996910038952940420">"Kamus peribadi"</string>
+ <string name="configure_dictionaries_title" msgid="4238652338556902049">"Kamus tambahan"</string>
+ <string name="main_dictionary" msgid="4798763781818361168">"Kamus utama"</string>
+ <string name="prefs_show_suggestions" msgid="8026799663445531637">"Tunjukkan cadangan pembetulan"</string>
+ <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Paparkan cadangan perkataan semasa menaip"</string>
+ <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Sentiasa tunjukkan"</string>
+ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"Tunjukkan dalam mod potret"</string>
+ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Sentiasa sembunyikan"</string>
+ <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"Sekat perkataan yg menyinggung"</string>
+ <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"Jangan cadangkan perkataan yang boleh menyinggung"</string>
+ <string name="auto_correction" msgid="7630720885194996950">"Auto pembetulan"</string>
+ <string name="auto_correction_summary" msgid="5625751551134658006">"Bar ruang dan tanda baca secara automatik membetulkan perkataan yang ditaip salah"</string>
+ <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Dimati"</string>
+ <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Sederhana"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Agresif"</string>
+ <string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Sangat agresif"</string>
+ <string name="bigram_prediction" msgid="1084449187723948550">"Cadangan perkataan seterusnya"</string>
+ <string name="bigram_prediction_summary" msgid="3896362682751109677">"Gunakan perkataan sebelumnya dalam membuat cadangan"</string>
+ <string name="gesture_input" msgid="826951152254563827">"Dayakan taipan gerak isyarat"</string>
+ <string name="gesture_input_summary" msgid="9180350639305731231">"Input perkataan dengan meluncur melalui huruf"</string>
+ <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="label_go_key" msgid="1635148082137219148">"Pergi"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Seterusnya"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"Sblm"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"Hantar"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"Jeda"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"Tunggu"</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_description_unknown" msgid="3197434010402179157">"Kod kunci %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Kunci anjak dihidupkan (ketik untuk melumpuhkan)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"Kunci huruf besar dihidupkan (ketik untuk melumpuhkan)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"Padam"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"Simbol"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"Huruf"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"Numbers"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"Tetapan"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"Ruang"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"Input suara"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"Muka senyum"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Kembali"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"Cari"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"Tukar bahasa"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"Seterusnya"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"Sebelumnya"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift didayakan"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"Kunci huruf besar didayakan"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Kunci anjak dilumpuhkan"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"Mod simbol"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"Mod huruf"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"Mod telefon"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"Mod simbol telefon"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"Papan kekunci tersembunyi"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"Menunjukkan <xliff:g id="MODE">%s</xliff:g> papan kekunci"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"tarikh"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"tarikh dan masa"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"e-mel"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"pemesejan"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"nombor"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"telefon"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"teks"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"masa"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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="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>
+ <string name="select_language" msgid="3693815588777926848">"Bahasa input"</string>
+ <string name="hint_add_to_dictionary" msgid="573678656946085380">"Sentuh lagi untuk menyimpan"</string>
+ <string name="has_dictionary" msgid="6071847973466625007">"Kamus tersedia"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Dayakan maklum balas pengguna"</string>
+ <string name="prefs_description_log" msgid="7525225584555429211">"Bantu memperbaik editor kaedah input ini dengan menghantar statistik penggunaan dan laporan ranap secara automatik"</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"Tema papan kekunci"</string>
+ <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_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>
+ <string name="subtype_no_language_azerty" msgid="8144348527575640087">"Abjad (AZERTY)"</string>
+ <string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Abjad (Dvorak)"</string>
+ <string name="subtype_no_language_colemak" msgid="5837418400010302623">"Abjad (Colemak)"</string>
+ <string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Abjad (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
+ <string name="custom_input_styles_title" msgid="8429952441821251512">"Gaya input peribadi"</string>
+ <string name="add_style" msgid="6163126614514489951">"Tambah gaya"</string>
+ <string name="add" msgid="8299699805688017798">"Tambah"</string>
+ <string name="remove" msgid="4486081658752944606">"Alih Keluar"</string>
+ <string name="save" msgid="7646738597196767214">"Simpan"</string>
+ <string name="subtype_locale" msgid="8576443440738143764">"Bahasa"</string>
+ <string name="keyboard_layout_set" msgid="4309233698194565609">"Reka letak"</string>
+ <string name="custom_input_style_note_message" msgid="8826731320846363423">"Gaya input tersuai anda perlu didayakan sebelum anda mula menggunakannya. Adakah anda ingin mendayakannya sekarang?"</string>
+ <string name="enable" msgid="5031294444630523247">"Dayakan"</string>
+ <string name="not_now" msgid="6172462888202790482">"Bukan sekarang"</string>
+ <string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
+ <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mod kajian kebolehgunaan"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Kelewatan tekan lama kekunci"</string>
+ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Tempoh getaran tekan kekunci"</string>
+ <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Kelantangan bunyi tekan kekunci"</string>
+ <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="error" msgid="8940763624668513648">"Berlaku ralat"</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>
+ <string name="setup_start_action" msgid="8936036460897347708">"Bermula"</string>
+ <string name="setup_next_action" msgid="371821437915144603">"Langkah seterusnya"</string>
+ <string name="setup_steps_title" msgid="6400373034871816182">"Menyediakan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_title" msgid="3147967630253462315">"Dayakan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step1_instruction" msgid="2578631936624637241">"Sila semak \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" dlm ttpn Bhs &amp; input. Ini mbnarkn apl djlnkn pd pranti anda."</string>
+ <string name="setup_step1_finished_instruction" msgid="10761482004957994">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> sudah didayakan dalam tetapan Bahasa &amp; input anda, jadi langkah ini telah selesai. Beralih ke langkah seterusnya!"</string>
+ <string name="setup_step1_action" msgid="4366513534999901728">"Dayakan dalam Tetapan"</string>
+ <string name="setup_step2_title" msgid="6860725447906690594">"Beralih ke <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="setup_step2_instruction" msgid="9141481964870023336">"Seterusnya, pilih \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\" sebagai kaedah input teks aktif anda."</string>
+ <string name="setup_step2_action" msgid="1660330307159824337">"Tukar kaedah input"</string>
+ <string name="setup_step3_title" msgid="3154757183631490281">"Tahniah, anda sudah sedia!"</string>
+ <string name="setup_step3_instruction" msgid="8025981829605426000">"Kini anda boleh menaip dalam semua apl kegemaran anda dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
+ <string name="setup_step3_action" msgid="600879797256942259">"Konfigurasikan bahasa tambahan"</string>
+ <string name="setup_finish_action" msgid="276559243409465389">"Selesai"</string>
+ <string name="show_setup_wizard_icon" msgid="5008028590593710830">"Tunjukkan ikon apl"</string>
+ <string name="show_setup_wizard_icon_summary" msgid="4119998322536880213">"Paparkan ikon apl dalam pelancar"</string>
+ <string name="app_name" msgid="6320102637491234792">"Pembekal Kamus"</string>
+ <string name="dictionary_provider_name" msgid="3027315045397363079">"Pembekal Kamus"</string>
+ <string name="dictionary_service_name" msgid="6237472350693511448">"Perkhidmatan Kamus"</string>
+ <string name="download_description" msgid="6014835283119198591">"Maklumat kemas kini kamus"</string>
+ <string name="dictionary_settings_title" msgid="8091417676045693313">"Kamus tambahan"</string>
+ <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"Kamus tersedia"</string>
+ <string name="dictionary_settings_summary" msgid="5305694987799824349">"Tetapan untuk kamus"</string>
+ <string name="user_dictionaries" msgid="3582332055892252845">"Kamus pengguna"</string>
+ <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Kamus pengguna"</string>
+ <string name="dictionary_available" msgid="4728975345815214218">"Kamus tersedia"</string>
+ <string name="dictionary_downloading" msgid="2982650524622620983">"Sedang memuat turun"</string>
+ <string name="dictionary_installed" msgid="8081558343559342962">"Dipasang"</string>
+ <string name="dictionary_disabled" msgid="8950383219564621762">"Dipasang, dilumpuhkan"</string>
+ <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Masalah menyambung kepada perkhidmatan kamus"</string>
+ <string name="no_dictionaries_available" msgid="8039920716566132611">"Tiada kamus tersedia"</string>
+ <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="main_dict_description" msgid="3072821352793492143">"Kamus utama"</string>
+ <string name="cancel" msgid="6830980399865683324">"Batal"</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="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_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="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>
+ <string name="user_dict_settings_add_screen_title" msgid="5818914331629278758">"Frasa"</string>
+ <string name="user_dict_settings_add_dialog_more_options" msgid="5671682004887093112">"Lagi pilihan"</string>
+ <string name="user_dict_settings_add_dialog_less_options" msgid="2716586567241724126">"Kurang pilihan"</string>
+ <string name="user_dict_settings_add_dialog_confirm" msgid="4703129507388332950">"OK"</string>
+ <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"Perkataan:"</string>
+ <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"Pintasan:"</string>
+ <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"Bahasa:"</string>
+ <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"Taip perkataan"</string>
+ <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"Pintasan pilihan"</string>
+ <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"Edit perkataan"</string>
+ <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"Edit"</string>
+ <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"Padam"</string>
+ <string name="user_dict_settings_empty_text" msgid="558499587532668203">"Anda tidak mempunyai sebarang perkataan dalam kamus pengguna. Tambahkan perkataan dengan menyentuh butang Tambah (+)."</string>
+ <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"Untuk semua bahasa"</string>
+ <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"Lebih banyak bahasa..."</string>
+ <string name="user_dict_settings_delete" msgid="110413335187193859">"Padam"</string>
+ <string name="user_dict_fast_scroll_alphabet" msgid="5431919401558285473">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+</resources>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 1f9dbed41..9b30ea329 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Egendefinerte inndata"</string>
<string name="add_style" msgid="6163126614514489951">"Legg til stil"</string>
<string name="add" msgid="8299699805688017798">"Legg til"</string>
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..5ad5eae66
--- /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">"Android Keyboard (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android Spell Checker (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android Keyboard Settings (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Spell Checker Settings (AOSP)"</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..5aa676a10
--- /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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : बचत गरियो"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"जानुहोस्"</string>
+ <string name="label_next_key" msgid="362972844525672568">"अर्को"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"अघिल्लो"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"भयो"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"पठाउनुहोस्"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"रोक्नुहोस्"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"प्रतीक्षा गर्ने"</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_description_unknown" msgid="3197434010402179157">"कुञ्जी कोड %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"सिफ्ट"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"सिप्ट सक्रिय (असक्षम पार्न ट्याप गर्नुहोस्)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"क्याप्स लक सक्रिय छ (असक्षम पार्न ट्याप गर्नुहोस्)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"मेट्ने"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"प्रतिकहरू"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"अक्षरहरू"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"नम्बरहरू"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"सेटिङहरू"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ट्याब"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"स्पेस"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"आवाज इनपुट"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"मुस्कुराएको अनुहार"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"फर्कनुहोस्"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"खोज्नुहोस्"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"डट"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"भाषा स्विच गर्नुहोस्"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"अर्को"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"अघिल्लो"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"सिफ्ट सक्षम पारिएको छ"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"क्याप्स लक सक्षम पारिएको छ"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"सिफ्ट असक्षम पारिएको छ"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"प्रतिक मोड"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"अक्षर मोड"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"फोन मोड"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"फोन प्रतिक मोड"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"किबोर्ड लुकाइएको छ"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> किबोर्ड देखाइँदै"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"मिति"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"मिति र समय"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"इमेल"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"सन्देश गर्दै"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"सङ्ख्या"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"फोन"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"पाठ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"समय"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"स्वचालित रूपमा प्रयोग तथ्याङ्कहरू र क्यास रिपोर्टहरू पठाएर यस इनपुट विधि सम्पादकलाई सुधार्न सहयोग गर्नुहोस्।"</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="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_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="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">"अब तपाईँ <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="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">"तपाईँको मोबाइल उपकरणमा चयन गरिएको भाषामा शब्दकोश उपलब्ध छ। हामी सिफारिश गर्छौं <xliff:g id="LANGUAGE">%1$s</xliff:g> शब्दकोश डाउनलोड गर्नका लागि तपाईँको टाइपिङ अनुभव सुधार्न। यस डाउनलोड 3G मा एक वा दुई मिनेट लाग्छ। शुल्कहरू लाग्न सक्छ यदि तपाईँसँग असीमित डेटा योजना छैन भने। यदि आफूसँग कुन डेटा योजना छ तपाईँ यकिन हुनुहुन्न भने हामी स्वचालित रूपमा डाउनलोड सुरु गर्न वाइ-फाइ जडान खोज्न सिफारिस गर्छौं। सल्लाह: तपाईँको मोबाइल उपकरणको भाषा र इनपुट सेटिङ मेनुमा गई तपाईँ शब्दकोशलाई डाउनलोड वा हटाउन सक्नुहुन्छ।"</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="6514288591959117288">"एक शब्दकोश <xliff:g id="LANGUAGE">%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="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-ne/strings-appname.xml b/java/res/values-ne/strings-appname.xml
new file mode 100644
index 000000000..5ad5eae66
--- /dev/null
+++ b/java/res/values-ne/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">"Android Keyboard (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android Spell Checker (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android Keyboard Settings (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android Spell Checker Settings (AOSP)"</string>
+</resources>
diff --git a/java/res/values-ne/strings.xml b/java/res/values-ne/strings.xml
new file mode 100644
index 000000000..6c149456d
--- /dev/null
+++ b/java/res/values-ne/strings.xml
@@ -0,0 +1,242 @@
+<?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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : बचत गरियो"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"जानुहोस्"</string>
+ <string name="label_next_key" msgid="362972844525672568">"अर्को"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"अघिल्लो"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"भयो"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"पठाउनुहोस्"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"रोक्नुहोस्"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"प्रतीक्षा गर्नुहोस्"</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_description_unknown" msgid="3197434010402179157">"कुञ्जी कोड %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"सिफ्ट"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"सिप्ट सक्रिय (असक्षम पार्न ट्याप गर्नुहोस्)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"क्याप्स लक सक्रिय छ (असक्षम पार्न ट्याप गर्नुहोस्)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"मेट्नुहोस्"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"प्रतिकहरू"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"अक्षरहरू"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"नम्बरहरू"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"सेटिङहरू"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ट्याब"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"स्पेस"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"आवाज इनपुट"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"मुस्कुराएको अनुहार"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"फर्कनुहोस्"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"खोज्नुहोस्"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"डट"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"भाषा स्विच गर्नुहोस्"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"अर्को"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"अघिल्लो"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"सिफ्ट सक्षम पारिएको छ"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"क्याप्स लक सक्षम पारिएको छ"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"सिफ्ट असक्षम पारिएको छ"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"प्रतिक मोड"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"अक्षर मोड"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"फोन मोड"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"फोन प्रतिक मोड"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"किबोर्ड लुकाइएको छ"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> किबोर्ड देखाइँदै"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"मिति"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"मिति र समय"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"इमेल"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"सन्देश गर्दै"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"सङ्ख्या"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"फोन"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"पाठ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"समय"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"स्वचालित रूपमा प्रयोग तथ्याङ्कहरू र क्यास रिपोर्टहरू पठाएर यस इनपुट विधि सम्पादकलाई सुधार्न सहयोग गर्नुहोस्।"</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="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_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="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">"अब तपाईँ <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="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">"तपाईँको मोबाइल उपकरणमा चयन गरिएको भाषामा शब्दकोश उपलब्ध छ। हामी सिफारिश गर्छौं <xliff:g id="LANGUAGE">%1$s</xliff:g> शब्दकोश डाउनलोड गर्नका लागि तपाईँको टाइपिङ अनुभव सुधार्न। यस डाउनलोड 3G मा एक वा दुई मिनेट लाग्छ। शुल्कहरू लाग्न सक्छ यदि तपाईँसँग असीमित डेटा योजना छैन भने। यदि आफूसँग कुन डेटा योजना छ तपाईँ यकिन हुनुहुन्न भने हामी स्वचालित रूपमा डाउनलोड सुरु गर्न वाइ-फाइ जडान खोज्न सिफारिस गर्छौं। सल्लाह: तपाईँको मोबाइल उपकरणको भाषा र इनपुट सेटिङ मेनुमा गई तपाईँ शब्दकोशलाई डाउनलोड वा हटाउन सक्नुहुन्छ।"</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="6514288591959117288">"एक शब्दकोश <xliff:g id="LANGUAGE">%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="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.xml b/java/res/values-nl/strings.xml
index 3eed154f7..c61b090b6 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (pc)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Aangep. invoerstijlen"</string>
<string name="add_style" msgid="6163126614514489951">"Stijl toev."</string>
<string name="add" msgid="8299699805688017798">"Toevoegen"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index b4f261213..31eace5cb 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emotikony"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Style niestandardowe"</string>
<string name="add_style" msgid="6163126614514489951">"Dodaj styl"</string>
<string name="add" msgid="8299699805688017798">"Dodaj"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index cacc3970e..cd89a7765 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -134,7 +134,7 @@
<string name="select_language" msgid="3693815588777926848">"Idiomas de introdução"</string>
<string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para guardar"</string>
<string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
- <string name="prefs_enable_log" msgid="6620424505072963557">"Activar comentários do utilizador"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Ativar comentários do utilizador"</string>
<string name="prefs_description_log" msgid="7525225584555429211">"Envie automaticamente estatísticas de utilização e relatórios de falhas e ajude-nos a melhorar este editor do método de introdução."</string>
<string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string>
<string name="subtype_en_GB" msgid="88170601942311355">"Inglês (RU)"</string>
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Estilos entrada pers."</string>
<string name="add_style" msgid="6163126614514489951">"Adic. estilo"</string>
<string name="add" msgid="8299699805688017798">"Adicionar"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 57ebe127e..820f577ad 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -56,7 +56,7 @@
<string name="prefs_show_suggestions" msgid="8026799663445531637">"Exibir 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 de retrato"</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_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>
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Estilos personalizados"</string>
<string name="add_style" msgid="6163126614514489951">"Adic. estilo"</string>
<string name="add" msgid="8299699805688017798">"Adicionar"</string>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index 1d14b8f4c..1c509ad73 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -254,6 +254,8 @@
<skip />
<!-- no translation found for subtype_with_layout_es_US (6261791057007890189) -->
<skip />
+ <!-- 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) -->
@@ -268,6 +270,8 @@
<skip />
<!-- no translation found for subtype_no_language_pcqwerty (5354918232046200018) -->
<skip />
+ <!-- no translation found for subtype_emoji (7483586578074549196) -->
+ <skip />
<!-- no translation found for custom_input_styles_title (8429952441821251512) -->
<skip />
<!-- no translation found for add_style (6163126614514489951) -->
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 8df11b1ac..3caff1337 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -39,7 +39,7 @@
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Afişaţi când sunt activate mai multe limbi de intrare"</string>
<string name="sliding_key_input_preview" msgid="6604262359510068370">"Afișați indicator glisare"</string>
<string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Afișați un indicator în timpul glisării de la Shift sau tasta de simboluri"</string>
- <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Înt. înch. pop-up esenţ."</string>
+ <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Închidere pop-up taste"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fără întârziere"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string>
<string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> msec."</string>
@@ -48,7 +48,7 @@
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</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">"Auto-capitalizare"</string>
+ <string name="auto_cap" msgid="1719746674854628252">"Scriere automată cu majuscule"</string>
<string name="auto_cap_summary" msgid="7934452761022946874">"Scrie cu majusculă primul cuvânt din fiecare propoziţie"</string>
<string name="edit_personal_dictionary" msgid="3996910038952940420">"Dicționar personal"</string>
<string name="configure_dictionaries_title" msgid="4238652338556902049">"Dicţionare suplimentare"</string>
@@ -64,7 +64,7 @@
<string name="auto_correction_summary" msgid="5625751551134658006">"Corectare automată cuvinte prin bară spaţiu/semne punctuaţie"</string>
<string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Dezactivată"</string>
<string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderată"</string>
- <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Agresivă"</string>
+ <string name="auto_correction_threshold_mode_aggressive" msgid="7319007299148899623">"Exigentă"</string>
<string name="auto_correction_threshold_mode_very_aggressive" msgid="1853309024129480416">"Foarte agresivă"</string>
<string name="bigram_prediction" msgid="1084449187723948550">"Sugestii pentru cuvântul următor"</string>
<string name="bigram_prediction_summary" msgid="3896362682751109677">"Utilizează cuvântul anterior pentru sugestii"</string>
@@ -131,18 +131,19 @@
<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>
- <string name="select_language" msgid="3693815588777926848">"Limbi de intrare"</string>
+ <string name="select_language" msgid="3693815588777926848">"Limbi de introducere de text"</string>
<string name="hint_add_to_dictionary" msgid="573678656946085380">"Atingeţi din nou pentru a salva"</string>
<string name="has_dictionary" msgid="6071847973466625007">"Dicţionar disponibil"</string>
<string name="prefs_enable_log" msgid="6620424505072963557">"Activaţi feedback de la utilizatori"</string>
<string name="prefs_description_log" msgid="7525225584555429211">"Ajutați la îmbunătățirea acestui instrument de editare a metodelor de introducere a textului trimițând în mod automat statistici de utilizare și rapoarte de blocare."</string>
<string name="keyboard_layout" msgid="8451164783510487501">"Temă pentru tastatură"</string>
- <string name="subtype_en_GB" msgid="88170601942311355">"Engleză (Marea Britanie)"</string>
- <string name="subtype_en_US" msgid="6160452336634534239">"Engleză (S.U.A.)"</string>
- <string name="subtype_es_US" msgid="5583145191430180200">"Spaniolă (S.U.A.)"</string>
+ <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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Stiluri personalizate"</string>
<string name="add_style" msgid="6163126614514489951">"Stil"</string>
<string name="add" msgid="8299699805688017798">"Adăugaţi"</string>
@@ -164,7 +166,7 @@
<string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modul Studiu privind utilizarea"</string>
<string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Timpul apăsării lungi a tastei"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrare după apăsarea tastei"</string>
- <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volum prin apăsarea tastei"</string>
+ <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Sunet la apăsarea tastelor"</string>
<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>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index b7539d13a..affe88fbe 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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">"Латиница (ПК)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Эмодзи"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Персонализированные стили"</string>
<string name="add_style" msgid="6163126614514489951">"Добавить стиль"</string>
<string name="add" msgid="8299699805688017798">"Добавить"</string>
diff --git a/java/res/values-si-rLK/strings-appname.xml b/java/res/values-si-rLK/strings-appname.xml
new file mode 100644
index 000000000..108104872
--- /dev/null
+++ b/java/res/values-si-rLK/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">"Android යතුරු පුවරුව (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android අක්ෂර වින්‍යාස පරීක්ෂක (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android යතුරු පුවරු සැකසීම් (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android අක්ෂර වින්‍යාස පරීක්ෂක සැකසීම් (AOSP)"</string>
+</resources>
diff --git a/java/res/values-si-rLK/strings.xml b/java/res/values-si-rLK/strings.xml
new file mode 100644
index 000000000..23896b2e8
--- /dev/null
+++ b/java/res/values-si-rLK/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>ms"</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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : සුරැකිණි"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"යන්න"</string>
+ <string name="label_next_key" msgid="362972844525672568">"ඊළඟ"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"පෙර"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"හරි"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"යවන්න"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"විරාම කරන්න"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"රැඳී සිටින්න"</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_description_unknown" msgid="3197434010402179157">"යතුරු කේතය %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"ෂිෆ්ට්"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"ෂිෆ්ට් සක්‍රියයි (අබල කිරීමට තට්ටු කරන්න)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"කැප්ස් ලොක් සක්‍රියයි (අබල කිරීමට තට්ටු කරන්න)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"මකන්න"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"සංකේත"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"අකුරු"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"අංක"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"සැකසීම්"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ටැබය"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"හිඩස"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"හඬ ආදානය"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"සිනහ මුහුණ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"ආපසු එවන්න"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"සෙවීම"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"තිත"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"භාෂාව මාරු කරන්න"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"ඊළඟ"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"පෙර"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"ෂිෆ්ට් සබල කර ඇත"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"කැප්ස් ලොක් සබල කර ඇත"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ෂිෆ්ට් අබල කර ඇත"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"සංකේත ආකාරය"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"අකුරු ආකාරය"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"දුරකථන ආකාරය"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"දුරකථන සංකේත ආකාරය"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"යතුරු පුවරුව සැඟවී ඇත"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> යතුරු පුවරුව පෙන්නුම් කෙරේ"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"දිනය"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"දිනය සහ වේලාව"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"ඊ-තැපෑල"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"පණිවිඩ යැවීම"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"අංකය"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"දුරකථනය"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"පෙළ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"කාලය"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"භාවිතය පිළිබඳ සංඛ්‍යාලේඛන සහ බිඳ වැටීම් වාර්තා ස්වයංක්‍රියව යැවීම මගින් ආදාන ක්‍රම සංස්කාරක වැඩි දියුණු කිරීමට උදව් වන්න."</string>
+ <string name="keyboard_layout" msgid="8451164783510487501">"යතුරු පුවරු තේමාව"</string>
+ <string name="subtype_en_GB" msgid="88170601942311355">"ඉංග්‍රීසි (UK)"</string>
+ <string name="subtype_en_US" msgid="6160452336634534239">"ඉංග්‍රීසි (US)"</string>
+ <string name="subtype_es_US" msgid="5583145191430180200">"ස්පාඤ්ඤ (US)"</string>
+ <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"ඉංග්‍රිසි (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"ඉංග්‍රීසි (US) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+ <string name="subtype_with_layout_es_US" msgid="6261791057007890189">"ස්පාඤ්ඤ (US) (<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_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="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">"දැන් ඔබට <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="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; අප ඔබගේ ටයිප් කිරීමේ පළපුරුද්ද වැඩි දියුණු කිරීමට <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="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_description" msgid="1075194169443163487">"සමාලෝචනය කිරීමට සහ බාගැනීමට ඔබන්න"</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">"හරි"</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-si/strings-appname.xml b/java/res/values-si/strings-appname.xml
new file mode 100644
index 000000000..108104872
--- /dev/null
+++ b/java/res/values-si/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">"Android යතුරු පුවරුව (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android අක්ෂර වින්‍යාස පරීක්ෂක (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android යතුරු පුවරු සැකසීම් (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android අක්ෂර වින්‍යාස පරීක්ෂක සැකසීම් (AOSP)"</string>
+</resources>
diff --git a/java/res/values-si/strings.xml b/java/res/values-si/strings.xml
new file mode 100644
index 000000000..6d2a6f61b
--- /dev/null
+++ b/java/res/values-si/strings.xml
@@ -0,0 +1,242 @@
+<?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>ms"</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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : සුරැකිණි"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"යන්න"</string>
+ <string name="label_next_key" msgid="362972844525672568">"මීලඟ"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"පෙර"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"හරි"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"යවන්න"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"විරාම කරන්න"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"රැඳී සිටින්න"</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_description_unknown" msgid="3197434010402179157">"යතුරු කේතය %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"ෂිෆ්ට්"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"ෂිෆ්ට් සක්‍රියයි (අබල කිරීමට තට්ටු කරන්න)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"කැප්ස් ලොක් සක්‍රියයි (අබල කිරීමට තට්ටු කරන්න)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"මකන්න"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"සංකේත"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"අකුරු"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"අංක"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"සැකසීම්"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"ටැබය"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"හිඩස"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"හඬ ආදානය"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"සිනහ මුහුණ"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"ආපසු එවන්න"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"සෙවීම"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"තිත"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"භාෂාව මාරු කරන්න"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"මීලඟ"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"පෙර"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"ෂිෆ්ට් සබල කර ඇත"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"කැප්ස් ලොක් සබල කර ඇත"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"ෂිෆ්ට් අබල කර ඇත"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"සංකේත ප්‍රකාරය"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"අකුරු ආකාරය"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"දුරකථන ආකාරය"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"දුරකථන සංකේත ආකාරය"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"යතුරු පුවරුව සැඟවී ඇත"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"<xliff:g id="MODE">%s</xliff:g> යතුරු පුවරුව පෙන්නුම් කෙරේ"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"දිනය"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"දිනය සහ වේලාව"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"ඊ-තැපෑල"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"පණිවිඩ යැවීම"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"අංකය"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"දුරකථනය"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"පෙළ"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"කාලය"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
+ <string name="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">"භාවිතය පිළිබඳ සංඛ්‍යාලේඛන සහ බිඳ වැටීම් වාර්තා ස්වයංක්‍රියව යැවීම මගින් ආදාන ක්‍රම සංස්කාරක වැඩි දියුණු කිරීමට උදව් වන්න."</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="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_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="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">"දැන් ඔබට <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="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; අප ඔබගේ ටයිප් කිරීමේ පළපුරුද්ද වැඩි දියුණු කිරීමට <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="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_description" msgid="1075194169443163487">"සමාලෝචනය කිරීමට සහ බාගැනීමට ඔබන්න"</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">"හරි"</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-sk/strings.xml b/java/res/values-sk/strings.xml
index c4e5a06b5..85d64c6c0 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Latinka (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Latinka (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Latinka (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Vlastné štýly vstupu"</string>
<string name="add_style" msgid="6163126614514489951">"Pridať štýl"</string>
<string name="add" msgid="8299699805688017798">"Pridať"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index c6e7c24dd..7648d73b2 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Latinica (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Latinica (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Latinica (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Znaki »emoji«"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Slogi vnosa po meri"</string>
<string name="add_style" msgid="6163126614514489951">"Dodaj slog"</string>
<string name="add" msgid="8299699805688017798">"Dodaj"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index cb3e32bbe..db06bce7e 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"Прилаг. стилови уноса"</string>
<string name="add_style" msgid="6163126614514489951">"Додав. стила"</string>
<string name="add" msgid="8299699805688017798">"Додај"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 5b34b2f02..c6635165c 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabet (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabet (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabet (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Humörsymbol"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Anpassade indatastilar"</string>
<string name="add_style" msgid="6163126614514489951">"Ny stil"</string>
<string name="add" msgid="8299699805688017798">"Lägg till"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 94759b683..188bbca9c 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabeti (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabeti (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabeti (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Mitindo maalum ya ingizo"</string>
<string name="add_style" msgid="6163126614514489951">"Ongeza mtindo"</string>
<string name="add" msgid="8299699805688017798">"Ongeza"</string>
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml
index 51c710fa4..730b7d813 100644
--- a/java/res/values-sw600dp-land/dimens.xml
+++ b/java/res/values-sw600dp-land/dimens.xml
@@ -24,20 +24,15 @@
<dimen name="keyboardHeight">283.5dp</dimen>
<fraction name="minKeyboardHeight">45%p</fraction>
- <fraction name="keyboard_top_padding">2.444%p</fraction>
- <fraction name="keyboard_bottom_padding">0.0%p</fraction>
- <fraction name="key_bottom_gap">4.911%p</fraction>
- <fraction name="key_horizontal_gap">1.284%p</fraction>
-
- <fraction name="key_bottom_gap_stone">4.355%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.505%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_ics">2.727%p</fraction>
+ <fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
<fraction name="key_bottom_gap_ics">4.5%p</fraction>
<fraction name="key_horizontal_gap_ics">0.9%p</fraction>
- <fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
<dimen name="popup_key_height">81.9dp</dimen>
@@ -67,4 +62,11 @@
<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">95%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">30</integer>
+
</resources>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 826565168..93862a767 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -28,8 +28,6 @@
<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>
- <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
- <string name="config_default_keyboard_theme_index" translatable="false">5</string>
<integer name="config_max_more_keys_column">5</integer>
<!--
Configuration for MainKeyboardView
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index 75b476c64..2bcf2fa84 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -27,27 +27,22 @@
<dimen name="popup_key_height">63.0dp</dimen>
- <fraction name="keyboard_top_padding">2.291%p</fraction>
- <fraction name="keyboard_bottom_padding">0.0%p</fraction>
- <fraction name="key_bottom_gap">3.750%p</fraction>
- <fraction name="key_horizontal_gap">1.857%p</fraction>
-
- <fraction name="key_bottom_gap_stone">3.75%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.602%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.625%p</fraction>
<fraction name="key_horizontal_gap_gb">2.113%p</fraction>
+ <fraction name="keyboard_top_padding_ics">2.335%p</fraction>
+ <fraction name="keyboard_bottom_padding_ics">4.0%p</fraction>
<fraction name="key_bottom_gap_ics">4.5%p</fraction>
<fraction name="key_horizontal_gap_ics">1.565%p</fraction>
- <fraction name="keyboard_bottom_padding_ics">4.0%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">-81.9dp</dimen>
+ <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>
@@ -64,7 +59,7 @@
<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">16.0dp</dimen>
+ <dimen name="key_preview_offset_gb">16.0dp</dimen>
<!-- For 5-row keyboard -->
<fraction name="key_bottom_gap_5row">3.20%p</fraction>
@@ -93,4 +88,11 @@
<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">85%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">24</integer>
+
</resources>
diff --git a/java/res/values-sw600dp/touch-position-correction.xml b/java/res/values-sw600dp/touch-position-correction.xml
index f77d3ae83..df07c1295 100644
--- a/java/res/values-sw600dp/touch-position-correction.xml
+++ b/java/res/values-sw600dp/touch-position-correction.xml
@@ -37,7 +37,7 @@
</string-array>
<string-array
- name="touch_position_correction_data_gingerbread"
+ name="touch_position_correction_data_gb"
translatable="false"
>
<!-- The default touch position data (See com.android.inputmethod.keyboard.ProximityInfo)
@@ -48,7 +48,7 @@
</string-array>
<string-array
- name="touch_position_correction_data_ice_cream_sandwich"
+ name="touch_position_correction_data_ics"
translatable="false"
>
<!-- The default touch position data (See com.android.inputmethod.keyboard.ProximityInfo)
diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml
index f4a57ffb0..1e2e1c651 100644
--- a/java/res/values-sw768dp-land/dimens.xml
+++ b/java/res/values-sw768dp-land/dimens.xml
@@ -24,15 +24,8 @@
<dimen name="keyboardHeight">365.4dp</dimen>
<fraction name="minKeyboardHeight">45%p</fraction>
- <fraction name="keyboard_top_padding">1.896%p</fraction>
- <fraction name="keyboard_bottom_padding">0.0%p</fraction>
-
- <fraction name="key_bottom_gap">4.103%p</fraction>
- <fraction name="key_horizontal_gap">1.034%p</fraction>
-
- <fraction name="key_bottom_gap_stone">3.379%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.062%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>
@@ -70,4 +63,11 @@
<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">75%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">39</integer>
+
</resources>
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 97f11cb04..e1c07d6f8 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -26,8 +26,6 @@
<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>
- <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
- <string name="config_default_keyboard_theme_index" translatable="false">5</string>
<integer name="config_max_more_keys_column">5</integer>
<!--
Configuration for MainKeyboardView
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index 91251f5a4..f62a536d7 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -25,18 +25,12 @@
<fraction name="maxKeyboardHeight">46%p</fraction>
<fraction name="minKeyboardHeight">-35.0%p</fraction>
- <fraction name="keyboard_top_padding">2.291%p</fraction>
- <fraction name="keyboard_bottom_padding">0.0%p</fraction>
-
- <fraction name="key_bottom_gap">4.270%p</fraction>
- <fraction name="key_horizontal_gap">1.551%p</fraction>
-
- <fraction name="key_bottom_gap_stone">3.75%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.059%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_ics">2.335%p</fraction>
<fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
<fraction name="key_bottom_gap_ics">3.312%p</fraction>
<fraction name="key_horizontal_gap_ics">1.066%p</fraction>
@@ -48,7 +42,7 @@
<!-- 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">-81.9dp</dimen>
+ <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>
@@ -65,7 +59,7 @@
<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">16.0dp</dimen>
+ <dimen name="key_preview_offset_gb">16.0dp</dimen>
<!-- For 5-row keyboard -->
<fraction name="key_bottom_gap_5row">2.95%p</fraction>
@@ -94,4 +88,11 @@
<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">85%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">30</integer>
+
</resources>
diff --git a/java/res/values-th/donottranslate.xml b/java/res/values-th/donottranslate.xml
new file mode 100644
index 000000000..a9893feec
--- /dev/null
+++ b/java/res/values-th/donottranslate.xml
@@ -0,0 +1,23 @@
+<?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">
+ <!-- Whether this language uses spaces between words -->
+ <bool name="current_language_has_spaces">false</bool>
+</resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 58faeb00c..632f39a74 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"รูปแบบอินพุตกำหนดเอง"</string>
<string name="add_style" msgid="6163126614514489951">"เพิ่มสไตล์"</string>
<string name="add" msgid="8299699805688017798">"เพิ่ม"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 1c27ffdd8..3ec962b01 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alpabeto (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alpabeto (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alpabeto (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Custom style ng input"</string>
<string name="add_style" msgid="6163126614514489951">"Dagdag style"</string>
<string name="add" msgid="8299699805688017798">"Idagdag"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 6d4653373..4d0a6174c 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabe (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabe (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabe (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Özel giriş stilleri"</string>
<string name="add_style" msgid="6163126614514489951">"Stil ekle"</string>
<string name="add" msgid="8299699805688017798">"Ekle"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index affce86c9..df62f3286 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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">"Латиниця (ПК)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Cмайли Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Персональні стилі введення"</string>
<string name="add_style" msgid="6163126614514489951">"Додати стиль"</string>
<string name="add" msgid="8299699805688017798">"Додати"</string>
diff --git a/java/res/values-v18/emoji-categories.xml b/java/res/values-v18/emoji-categories.xml
new file mode 100644
index 000000000..2ea08159b
--- /dev/null
+++ b/java/res/values-v18/emoji-categories.xml
@@ -0,0 +1,909 @@
+<?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.
+-->
+
+<!-- Note: This emoji code point list is valid on JB-MR2 (API == 18).
+ There is another emoji code point list for KLP and later under res/xml/values-v19. -->
+<resources>
+ <array
+ name="emoji_nature"
+ format="string"
+ >
+ <!-- <item>1f415</item> -->
+ <item>1f436</item>
+ <item>1f429</item>
+ <!-- <item>1f408</item> -->
+ <item>1f431</item>
+ <!-- <item>1f400</item> -->
+ <!-- <item>1f401</item> -->
+ <item>1f42d</item>
+ <item>1f439</item>
+ <item>1f422</item>
+ <!-- <item>1f407</item> -->
+ <item>1f430</item>
+ <!-- <item>1f413</item> -->
+ <item>1f414</item>
+ <item>1f423</item>
+ <item>1f424</item>
+ <item>1f425</item>
+ <item>1f426</item>
+ <!-- <item>1f40f</item> -->
+ <item>1f411</item>
+ <!-- <item>1f410</item> -->
+ <item>1f43a</item>
+ <!-- <item>1f403</item> -->
+ <!-- <item>1f402</item> -->
+ <!-- <item>1f404</item> -->
+ <item>1f42e</item>
+ <item>1f434</item>
+ <item>1f417</item>
+ <!-- <item>1f416</item> -->
+ <item>1f437</item>
+ <item>1f43d</item>
+ <item>1f438</item>
+ <item>1f40d</item>
+ <item>1f43c</item>
+ <item>1f427</item>
+ <item>1f418</item>
+ <item>1f428</item>
+ <item>1f412</item>
+ <item>1f435</item>
+ <!-- <item>1f406</item> -->
+ <item>1f42f</item>
+ <item>1f43b</item>
+ <item>1f42b</item>
+ <!-- <item>1f42a</item> -->
+ <!-- <item>1f40a</item> -->
+ <item>1f433</item>
+ <!-- <item>1f40b</item> -->
+ <item>1f41f</item>
+ <item>1f420</item>
+ <item>1f421</item>
+ <item>1f419</item>
+ <item>1f41a</item>
+ <item>1f42c</item>
+ <item>1f40c</item>
+ <item>1f41b</item>
+ <item>1f41c</item>
+ <item>1f41d</item>
+ <item>1f41e</item>
+ <item>1f432</item>
+ <!-- <item>1f409</item> -->
+ <item>1f43e</item>
+ <item>1f378</item>
+ <item>1f37a</item>
+ <item>1f37b</item>
+ <item>1f377</item>
+ <item>1f379</item>
+ <item>1f376</item>
+ <!-- <item>2615</item> -->
+ <item>1f375</item>
+ <!-- <item>1f37c</item> -->
+ <item>1f374</item>
+ <item>1f368</item>
+ <item>1f367</item>
+ <item>1f366</item>
+ <item>1f369</item>
+ <item>1f370</item>
+ <item>1f36a</item>
+ <item>1f36b</item>
+ <item>1f36c</item>
+ <item>1f36d</item>
+ <item>1f36e</item>
+ <item>1f36f</item>
+ <item>1f373</item>
+ <item>1f354</item>
+ <item>1f35f</item>
+ <item>1f35d</item>
+ <item>1f355</item>
+ <item>1f356</item>
+ <item>1f357</item>
+ <item>1f364</item>
+ <item>1f363</item>
+ <item>1f371</item>
+ <item>1f35e</item>
+ <item>1f35c</item>
+ <item>1f359</item>
+ <item>1f35a</item>
+ <item>1f35b</item>
+ <item>1f372</item>
+ <item>1f365</item>
+ <item>1f362</item>
+ <item>1f361</item>
+ <item>1f358</item>
+ <item>1f360</item>
+ <item>1f34c</item>
+ <item>1f34e</item>
+ <item>1f34f</item>
+ <item>1f34a</item>
+ <!-- <item>1f34b</item> -->
+ <item>1f344</item>
+ <item>1f345</item>
+ <item>1f346</item>
+ <item>1f347</item>
+ <item>1f348</item>
+ <item>1f349</item>
+ <!-- <item>1f350</item> -->
+ <item>1f351</item>
+ <item>1f352</item>
+ <item>1f353</item>
+ <item>1f34d</item>
+ <item>1f330</item>
+ <item>1f331</item>
+ <!-- <item>1f332</item> -->
+ <!-- <item>1f333</item> -->
+ <item>1f334</item>
+ <item>1f335</item>
+ <item>1f337</item>
+ <item>1f338</item>
+ <item>1f339</item>
+ <item>1f340</item>
+ <item>1f341</item>
+ <item>1f342</item>
+ <item>1f343</item>
+ <item>1f33a</item>
+ <item>1f33b</item>
+ <item>1f33c</item>
+ <item>1f33d</item>
+ <item>1f33e</item>
+ <item>1f33f</item>
+ <item>2600</item>
+ <item>1f308</item>
+ <item>26c5</item>
+ <item>2601</item>
+ <item>1f301</item>
+ <item>1f302</item>
+ <!-- <item>2614</item> -->
+ <item>1f4a7</item>
+ <item>26a1</item>
+ <item>1f300</item>
+ <item>2744</item>
+ <item>26c4</item>
+ <item>1f319</item>
+ <!-- <item>1f31e</item> -->
+ <!-- <item>1f31d</item> -->
+ <!-- <item>1f31a</item> -->
+ <item>1f31b</item>
+ <!-- <item>1f31c</item> -->
+ <item>1f311</item>
+ <!-- <item>1f312</item> -->
+ <item>1f313</item>
+ <item>1f314</item>
+ <item>1f315</item>
+ <!-- <item>1f316</item> -->
+ <!-- <item>1f317</item> -->
+ <!-- <item>1f318</item> -->
+ <item>1f391</item>
+ <item>1f304</item>
+ <item>1f305</item>
+ <item>1f307</item>
+ <item>1f306</item>
+ <item>1f303</item>
+ <item>1f30c</item>
+ <item>1f309</item>
+ <item>1f30a</item>
+ <item>1f30b</item>
+ <!-- <item>1f30e</item> -->
+ <item>1f30f</item>
+ <!-- <item>1f30d</item> -->
+ <!-- <item>1f310</item> -->
+ </array>
+ <array
+ name="emoji_symbols"
+ format="string"
+ >
+ <!-- <item>fe82e|0031,20e3</item> -->
+ <!-- <item>fe82f|0032,20e3</item> -->
+ <!-- <item>fe830|0033,20e3</item> -->
+ <!-- <item>fe831|0034,20e3</item> -->
+ <!-- <item>fe832|0035,20e3</item> -->
+ <!-- <item>fe833|0036,20e3</item> -->
+ <!-- <item>fe834|0037,20e3</item> -->
+ <!-- <item>fe835|0038,20e3</item> -->
+ <!-- <item>fe836|0039,20e3</item> -->
+ <!-- <item>fe837|0030,20e3</item> -->
+ <!-- <item>1f51f</item> -->
+ <!-- <item>fe82c|0023,20e3</item> -->
+ <item>1f51d</item>
+ <item>1f519</item>
+ <item>1f51b</item>
+ <item>1f51c</item>
+ <item>1f51a</item>
+ <item>23f3</item>
+ <item>231b</item>
+ <item>23f0</item>
+ <item>2648</item>
+ <item>2649</item>
+ <item>264a</item>
+ <item>264b</item>
+ <item>264c</item>
+ <item>264d</item>
+ <item>264e</item>
+ <item>264f</item>
+ <item>2650</item>
+ <item>2651</item>
+ <item>2652</item>
+ <item>2653</item>
+ <item>26ce</item>
+ <item>1f531</item>
+ <item>1f52f</item>
+ <item>1f6bb</item>
+ <!-- <item>1f6ae</item> -->
+ <!-- <item>1f6af</item> -->
+ <!-- <item>1f6b0</item> -->
+ <!-- <item>1f6b1</item> -->
+ <item>1f170</item>
+ <item>1f171</item>
+ <item>1f18e</item>
+ <item>1f17e</item>
+ <item>1f4ae</item>
+ <item>1f4af</item>
+ <item>1f520</item>
+ <item>1f521</item>
+ <item>1f522</item>
+ <item>1f523</item>
+ <item>1f524</item>
+ <item>27bf</item>
+ <item>1f4f6</item>
+ <item>1f4f3</item>
+ <item>1f4f4</item>
+ <!-- <item>1f4f5</item> -->
+ <item>1f6b9</item>
+ <item>1f6ba</item>
+ <item>1f6bc</item>
+ <item>267f</item>
+ <item>267b</item>
+ <item>1f6ad</item>
+ <item>1f6a9</item>
+ <item>26a0</item>
+ <item>1f201</item>
+ <item>1f51e</item>
+ <item>26d4</item>
+ <item>1f192</item>
+ <item>1f197</item>
+ <item>1f195</item>
+ <item>1f198</item>
+ <item>1f199</item>
+ <item>1f193</item>
+ <item>1f196</item>
+ <item>1f19a</item>
+ <item>1f232</item>
+ <item>1f233</item>
+ <item>1f234</item>
+ <item>1f235</item>
+ <item>1f236</item>
+ <item>1f237</item>
+ <item>1f238</item>
+ <item>1f239</item>
+ <item>1f202</item>
+ <item>1f23a</item>
+ <item>1f250</item>
+ <item>1f251</item>
+ <item>3299</item>
+ <item>00ae</item>
+ <item>00a9</item>
+ <item>2122</item>
+ <item>1f21a</item>
+ <item>1f22f</item>
+ <item>3297</item>
+ <item>2b55</item>
+ <item>274c</item>
+ <item>274e</item>
+ <item>2139</item>
+ <item>1f6ab</item>
+ <item>2705</item>
+ <item>2714</item>
+ <item>1f517</item>
+ <item>2734</item>
+ <item>2733</item>
+ <item>2795</item>
+ <item>2796</item>
+ <item>2716</item>
+ <item>2797</item>
+ <item>1f4a0</item>
+ <item>1f4a1</item>
+ <item>1f4a4</item>
+ <item>1f4a2</item>
+ <item>1f525</item>
+ <item>1f4a5</item>
+ <item>1f4a8</item>
+ <item>1f4a6</item>
+ <item>1f4ab</item>
+ <item>1f55b</item>
+ <!-- <item>1f567</item> -->
+ <item>1f550</item>
+ <!-- <item>1f55c</item> -->
+ <item>1f551</item>
+ <!-- <item>1f55d</item> -->
+ <item>1f552</item>
+ <!-- <item>1f55e</item> -->
+ <item>1f553</item>
+ <!-- <item>1f55f</item> -->
+ <item>1f554</item>
+ <!-- <item>1f560</item> -->
+ <item>1f555</item>
+ <!-- <item>1f561</item> -->
+ <item>1f556</item>
+ <!-- <item>1f562</item> -->
+ <item>1f557</item>
+ <!-- <item>1f563</item> -->
+ <item>1f558</item>
+ <!-- <item>1f564</item> -->
+ <item>1f559</item>
+ <!-- <item>1f565</item> -->
+ <item>1f55a</item>
+ <!-- <item>1f566</item> -->
+ <item>2195</item>
+ <item>2b06</item>
+ <item>2197</item>
+ <item>27a1</item>
+ <item>2198</item>
+ <item>2b07</item>
+ <item>2199</item>
+ <item>2b05</item>
+ <item>2196</item>
+ <item>2194</item>
+ <item>2934</item>
+ <item>2935</item>
+ <item>23ea</item>
+ <item>23eb</item>
+ <item>23ec</item>
+ <item>23e9</item>
+ <item>25c0</item>
+ <item>25b6</item>
+ <item>1f53d</item>
+ <item>1f53c</item>
+ <item>2747</item>
+ <item>2728</item>
+ <item>1f534</item>
+ <item>1f535</item>
+ <item>26aa</item>
+ <item>26ab</item>
+ <item>1f533</item>
+ <item>1f532</item>
+ <item>2b50</item>
+ <item>1f31f</item>
+ <item>1f320</item>
+ <item>25ab</item>
+ <item>25aa</item>
+ <item>25fd</item>
+ <item>25fe</item>
+ <item>25fb</item>
+ <item>25fc</item>
+ <item>2b1c</item>
+ <item>2b1b</item>
+ <item>1f538</item>
+ <item>1f539</item>
+ <item>1f536</item>
+ <item>1f537</item>
+ <item>1f53a</item>
+ <item>1f53b</item>
+ <item>2754</item>
+ <item>2753</item>
+ <item>2755</item>
+ <item>2757</item>
+ <item>203c</item>
+ <item>2049</item>
+ <item>3030</item>
+ <item>27b0</item>
+ <item>2660</item>
+ <item>2665</item>
+ <item>2663</item>
+ <item>2666</item>
+ <item>1f194</item>
+ <item>1f511</item>
+ <item>21a9</item>
+ <item>1f191</item>
+ <item>1f50d</item>
+ <item>1f512</item>
+ <item>1f513</item>
+ <item>21aa</item>
+ <item>1f510</item>
+ <!-- <item>2611</item> -->
+ <item>1f518</item>
+ <item>1f50e</item>
+ <item>1f516</item>
+ <item>1f50f</item>
+ <item>1f503</item>
+ <!-- <item>1f500</item> -->
+ <!-- <item>1f501</item> -->
+ <!-- <item>1f502</item> -->
+ <!-- <item>1f504</item> -->
+ <item>1f4e7</item>
+ <!-- <item>1f505</item> -->
+ <!-- <item>1f506</item> -->
+ <!-- <item>1f507</item> -->
+ <!-- <item>1f508</item> -->
+ <!-- <item>1f509</item> -->
+ <item>1f50a</item>
+ </array>
+ <array
+ name="emoji_faces"
+ format="string"
+ >
+ <item>263a</item>
+ <item>1f60a</item>
+ <!-- <item>1f600</item> -->
+ <item>1f601</item>
+ <item>1f602</item>
+ <item>1f603</item>
+ <item>1f604</item>
+ <item>1f605</item>
+ <item>1f606</item>
+ <!-- <item>1f607</item> -->
+ <!-- <item>1f608</item> -->
+ <item>1f609</item>
+ <!-- <item>1f62f</item> -->
+ <!-- <item>1f610</item> -->
+ <!-- <item>1f611</item> -->
+ <!-- <item>1f615</item> -->
+ <item>1f620</item>
+ <!-- <item>1f62c</item> -->
+ <item>1f621</item>
+ <item>1f622</item>
+ <!-- <item>1f634</item> -->
+ <!-- <item>1f62e</item> -->
+ <item>1f623</item>
+ <item>1f624</item>
+ <item>1f625</item>
+ <!-- <item>1f626</item> -->
+ <!-- <item>1f627</item> -->
+ <item>1f628</item>
+ <item>1f629</item>
+ <item>1f630</item>
+ <!-- <item>1f61f</item> -->
+ <item>1f631</item>
+ <item>1f632</item>
+ <item>1f633</item>
+ <item>1f635</item>
+ <!-- <item>1f636</item> -->
+ <item>1f637</item>
+ <item>1f61e</item>
+ <item>1f612</item>
+ <item>1f60d</item>
+ <!-- <item>1f61b</item> -->
+ <item>1f61c</item>
+ <item>1f61d</item>
+ <item>1f60b</item>
+ <!-- <item>1f617</item> -->
+ <!-- <item>1f619</item> -->
+ <item>1f618</item>
+ <item>1f61a</item>
+ <!-- <item>1f60e</item> -->
+ <item>1f62d</item>
+ <item>1f60c</item>
+ <item>1f616</item>
+ <item>1f614</item>
+ <item>1f62a</item>
+ <item>1f60f</item>
+ <item>1f613</item>
+ <item>1f62b</item>
+ <item>1f64b</item>
+ <item>1f64c</item>
+ <item>1f64d</item>
+ <item>1f645</item>
+ <item>1f646</item>
+ <item>1f647</item>
+ <item>1f64e</item>
+ <item>1f64f</item>
+ <item>1f63a</item>
+ <item>1f63c</item>
+ <item>1f638</item>
+ <item>1f639</item>
+ <item>1f63b</item>
+ <item>1f63d</item>
+ <item>1f63f</item>
+ <item>1f63e</item>
+ <item>1f640</item>
+ <item>1f648</item>
+ <item>1f649</item>
+ <item>1f64a</item>
+ <item>1f4a9</item>
+ <item>1f476</item>
+ <item>1f466</item>
+ <item>1f467</item>
+ <item>1f468</item>
+ <item>1f469</item>
+ <item>1f474</item>
+ <item>1f475</item>
+ <item>1f48f</item>
+ <item>1f491</item>
+ <item>1f46a</item>
+ <item>1f46b</item>
+ <!-- <item>1f46c</item> -->
+ <!-- <item>1f46d</item> -->
+ <item>1f464</item>
+ <!-- <item>1f465</item> -->
+ <item>1f46e</item>
+ <item>1f477</item>
+ <item>1f481</item>
+ <item>1f482</item>
+ <item>1f46f</item>
+ <item>1f470</item>
+ <item>1f478</item>
+ <item>1f385</item>
+ <item>1f47c</item>
+ <!-- <item>1f471</item> -->
+ <!-- <item>1f472</item> -->
+ <!-- <item>1f473</item> -->
+ <item>1f483</item>
+ <item>1f486</item>
+ <item>1f487</item>
+ <item>1f485</item>
+ <item>1f47b</item>
+ <item>1f479</item>
+ <item>1f47a</item>
+ <item>1f47d</item>
+ <item>1f47e</item>
+ <item>1f47f</item>
+ <item>1f480</item>
+ <item>1f4aa</item>
+ <item>1f440</item>
+ <item>1f442</item>
+ <item>1f443</item>
+ <item>1f463</item>
+ <item>1f444</item>
+ <item>1f445</item>
+ <item>1f48b</item>
+ <item>2764</item>
+ <item>1f499</item>
+ <item>1f49a</item>
+ <item>1f49b</item>
+ <item>1f49c</item>
+ <item>1f493</item>
+ <item>1f494</item>
+ <item>1f495</item>
+ <item>1f496</item>
+ <item>1f497</item>
+ <item>1f498</item>
+ <item>1f49d</item>
+ <item>1f49e</item>
+ <item>1f49f</item>
+ <item>1f44d</item>
+ <item>1f44e</item>
+ <item>1f44c</item>
+ <item>270a</item>
+ <item>270c</item>
+ <item>270b</item>
+ <item>1f44a</item>
+ <!-- <item>261d</item> -->
+ <item>1f446</item>
+ <item>1f447</item>
+ <item>1f448</item>
+ <item>1f449</item>
+ <item>1f44b</item>
+ <item>1f44f</item>
+ <!-- <item>1f450</item> -->
+ </array>
+ <array
+ name="emoji_objects"
+ format="string"
+ >
+ <item>1f530</item>
+ <item>1f484</item>
+ <item>1f45e</item>
+ <item>1f45f</item>
+ <item>1f451</item>
+ <item>1f452</item>
+ <item>1f3a9</item>
+ <item>1f393</item>
+ <item>1f453</item>
+ <item>231a</item>
+ <item>1f454</item>
+ <item>1f455</item>
+ <item>1f456</item>
+ <item>1f457</item>
+ <item>1f458</item>
+ <item>1f459</item>
+ <item>1f460</item>
+ <item>1f461</item>
+ <item>1f462</item>
+ <item>1f45a</item>
+ <item>1f45c</item>
+ <item>1f4bc</item>
+ <item>1f392</item>
+ <item>1f45d</item>
+ <item>1f45b</item>
+ <item>1f4b0</item>
+ <item>1f4b3</item>
+ <item>1f4b2</item>
+ <item>1f4b5</item>
+ <item>1f4b4</item>
+ <!-- <item>1f4b6</item> -->
+ <!-- <item>1f4b7</item> -->
+ <item>1f4b8</item>
+ <item>1f4b1</item>
+ <item>1f4b9</item>
+ <item>1f52b</item>
+ <item>1f52a</item>
+ <item>1f4a3</item>
+ <item>1f489</item>
+ <item>1f48a</item>
+ <item>1f6ac</item>
+ <item>1f514</item>
+ <!-- <item>1f515</item> -->
+ <item>1f6aa</item>
+ <!-- <item>1f52c</item> -->
+ <!-- <item>1f52d</item> -->
+ <item>1f52e</item>
+ <item>1f526</item>
+ <item>1f50b</item>
+ <item>1f50c</item>
+ <item>1f4dc</item>
+ <item>1f4d7</item>
+ <item>1f4d8</item>
+ <item>1f4d9</item>
+ <item>1f4da</item>
+ <item>1f4d4</item>
+ <item>1f4d2</item>
+ <item>1f4d1</item>
+ <item>1f4d3</item>
+ <item>1f4d5</item>
+ <item>1f4d6</item>
+ <item>1f4f0</item>
+ <item>1f4db</item>
+ <item>1f383</item>
+ <item>1f384</item>
+ <item>1f380</item>
+ <item>1f381</item>
+ <item>1f382</item>
+ <item>1f388</item>
+ <item>1f386</item>
+ <item>1f387</item>
+ <item>1f389</item>
+ <item>1f38a</item>
+ <item>1f38d</item>
+ <item>1f38f</item>
+ <item>1f38c</item>
+ <item>1f390</item>
+ <item>1f38b</item>
+ <item>1f38e</item>
+ <item>1f4f1</item>
+ <item>1f4f2</item>
+ <item>1f4df</item>
+ <item>260e</item>
+ <item>1f4de</item>
+ <item>1f4e0</item>
+ <item>1f4e6</item>
+ <item>2709</item>
+ <item>1f4e8</item>
+ <item>1f4e9</item>
+ <item>1f4ea</item>
+ <item>1f4eb</item>
+ <!-- <item>1f4ed</item> -->
+ <!-- <item>1f4ec</item> -->
+ <item>1f4ee</item>
+ <item>1f4e4</item>
+ <item>1f4e5</item>
+ <!-- <item>1f4ef</item> -->
+ <item>1f4e2</item>
+ <item>1f4e3</item>
+ <item>1f4e1</item>
+ <item>1f4ac</item>
+ <!-- <item>1f4ad</item> -->
+ <item>2712</item>
+ <item>270f</item>
+ <item>1f4dd</item>
+ <item>1f4cf</item>
+ <item>1f4d0</item>
+ <item>1f4cd</item>
+ <item>1f4cc</item>
+ <item>1f4ce</item>
+ <item>2702</item>
+ <item>1f4ba</item>
+ <item>1f4bb</item>
+ <item>1f4bd</item>
+ <item>1f4be</item>
+ <item>1f4bf</item>
+ <item>1f4c6</item>
+ <item>1f4c5</item>
+ <item>1f4c7</item>
+ <item>1f4cb</item>
+ <item>1f4c1</item>
+ <item>1f4c2</item>
+ <item>1f4c3</item>
+ <item>1f4c4</item>
+ <item>1f4ca</item>
+ <item>1f4c8</item>
+ <item>1f4c9</item>
+ <item>26fa</item>
+ <item>1f3a1</item>
+ <item>1f3a2</item>
+ <item>1f3a0</item>
+ <item>1f3aa</item>
+ <item>1f3a8</item>
+ <item>1f3ac</item>
+ <item>1f3a5</item>
+ <item>1f4f7</item>
+ <item>1f4f9</item>
+ <item>1f3a6</item>
+ <item>1f3ad</item>
+ <item>1f3ab</item>
+ <item>1f3ae</item>
+ <item>1f3b2</item>
+ <item>1f3b0</item>
+ <item>1f0cf</item>
+ <item>1f3b4</item>
+ <item>1f004</item>
+ <item>1f3af</item>
+ <item>1f4fa</item>
+ <item>1f4fb</item>
+ <item>1f4c0</item>
+ <item>1f4fc</item>
+ <item>1f3a7</item>
+ <item>1f3a4</item>
+ <item>1f3b5</item>
+ <item>1f3b6</item>
+ <item>1f3bc</item>
+ <item>1f3bb</item>
+ <item>1f3b9</item>
+ <item>1f3b7</item>
+ <item>1f3ba</item>
+ <item>1f3b8</item>
+ <item>303d</item>
+ </array>
+ <array
+ name="emoji_places"
+ format="string"
+ >
+ <item>1f3e0</item>
+ <item>1f3e1</item>
+ <item>1f3e2</item>
+ <item>1f3e3</item>
+ <!-- <item>1f3e4</item> -->
+ <item>1f3e5</item>
+ <item>1f3e6</item>
+ <item>1f3e7</item>
+ <item>1f3e8</item>
+ <item>1f3e9</item>
+ <item>1f3ea</item>
+ <item>1f3eb</item>
+ <item>26ea</item>
+ <item>26f2</item>
+ <item>1f3ec</item>
+ <item>1f3ef</item>
+ <item>1f3f0</item>
+ <item>1f3ed</item>
+ <item>1f5fb</item>
+ <item>1f5fc</item>
+ <item>1f5fd</item>
+ <item>1f5fe</item>
+ <item>1f5ff</item>
+ <item>2693</item>
+ <item>1f3ee</item>
+ <item>1f488</item>
+ <item>1f527</item>
+ <item>1f528</item>
+ <item>1f529</item>
+ <!-- <item>1f6bf</item> -->
+ <!-- <item>1f6c1</item> -->
+ <item>1f6c0</item>
+ <item>1f6bd</item>
+ <item>1f6be</item>
+ <item>1f3bd</item>
+ <item>1f3a3</item>
+ <item>1f3b1</item>
+ <item>1f3b3</item>
+ <item>26be</item>
+ <item>26f3</item>
+ <item>1f3be</item>
+ <item>26bd</item>
+ <item>1f3bf</item>
+ <item>1f3c0</item>
+ <item>1f3c1</item>
+ <item>1f3c2</item>
+ <item>1f3c3</item>
+ <item>1f3c4</item>
+ <item>1f3c6</item>
+ <!-- <item>1f3c7</item> -->
+ <item>1f40e</item>
+ <item>1f3c8</item>
+ <!-- <item>1f3c9</item> -->
+ <item>1f3ca</item>
+ <!-- <item>1f682</item> -->
+ <item>1f683</item>
+ <item>1f684</item>
+ <item>1f685</item>
+ <!-- <item>1f686</item> -->
+ <item>1f687</item>
+ <item>24c2</item>
+ <!-- <item>1f688</item> -->
+ <!-- <item>1f68a</item> -->
+ <!-- <item>1f68b</item> -->
+ <item>1f68c</item>
+ <!-- <item>1f68d</item> -->
+ <!-- <item>1f68e</item> -->
+ <item>1f68f</item>
+ <!-- <item>1f690</item> -->
+ <item>1f691</item>
+ <item>1f692</item>
+ <item>1f693</item>
+ <!-- <item>1f694</item> -->
+ <item>1f695</item>
+ <!-- <item>1f696</item> -->
+ <item>1f697</item>
+ <!-- <item>1f698</item> -->
+ <item>1f699</item>
+ <!-- <item>1f69a</item> -->
+ <!-- <item>1f69b</item> -->
+ <!-- <item>1f69c</item> -->
+ <!-- <item>1f69d</item> -->
+ <!-- <item>1f69e</item> -->
+ <!-- <item>1f69f</item> -->
+ <!-- <item>1f6a0</item> -->
+ <!-- <item>1f6a1</item> -->
+ <item>1f6a2</item>
+ <!-- <item>1f6a3</item> -->
+ <!-- <item>1f681</item> -->
+ <item>2708</item>
+ <!-- <item>1f6c2</item> -->
+ <!-- <item>1f6c3</item> -->
+ <!-- <item>1f6c4</item> -->
+ <!-- <item>1f6c5</item> -->
+ <item>26f5</item>
+ <item>1f6b2</item>
+ <!-- <item>1f6b3</item> -->
+ <!-- <item>1f6b4</item> -->
+ <!-- <item>1f6b5</item> -->
+ <!-- <item>1f6b7</item> -->
+ <!-- <item>1f6b8</item> -->
+ <item>1f689</item>
+ <item>1f680</item>
+ <item>1f6a4</item>
+ <item>1f6b6</item>
+ <item>26fd</item>
+ <item>1f17f</item>
+ <item>1f6a5</item>
+ <!-- <item>1f6a6</item> -->
+ <item>1f6a7</item>
+ <item>1f6a8</item>
+ <item>2668</item>
+ <item>1f48c</item>
+ <item>1f48d</item>
+ <item>1f48e</item>
+ <item>1f490</item>
+ <item>1f492</item>
+ <item>fe4e5|1f1ef,1f1f5</item>
+ <item>fe4e6|1f1fa,1f1f8</item>
+ <item>fe4e7|1f1eb,1f1f7</item>
+ <item>fe4e8|1f1e9,1f1ea</item>
+ <item>fe4e9|1f1ee,1f1f9</item>
+ <item>fe4ea|1f1ec,1f1e7</item>
+ <item>fe4eb|1f1ea,1f1f8</item>
+ <item>fe4ec|1f1f7,1f1fa</item>
+ <item>fe4ed|1f1e8,1f1f3</item>
+ <item>fe4ee|1f1f0,1f1f7</item>
+ </array>
+ <array
+ name="emoji_emoticons"
+ format="string"
+ >
+ <item>=-O</item>
+ <item>:-P</item>
+ <item>;-)</item>
+ <item>:-(</item>
+ <item>:-)</item>
+ <item>:-!</item>
+ <item>:-$</item>
+ <item>B-)</item>
+ <item>:O</item>
+ <item>:-*</item>
+ <item>:-D</item>
+ <item>:\'(</item>
+ <item>:-\\</item>
+ <item>O:-)</item>
+ <item>:-[</item>
+ </array>
+</resources>
diff --git a/java/res/values-v19/emoji-categories.xml b/java/res/values-v19/emoji-categories.xml
new file mode 100644
index 000000000..658bbfa83
--- /dev/null
+++ b/java/res/values-v19/emoji-categories.xml
@@ -0,0 +1,909 @@
+<?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.
+-->
+
+<!-- Note: This emoji code point list is valid on KLP and later (API >= 19).
+ There is another emoji code point list for JB-MR2 under res/xml/values and values-v18.-->
+<resources>
+ <array
+ name="emoji_nature"
+ format="string"
+ >
+ <item>1f415</item>
+ <item>1f436</item>
+ <item>1f429</item>
+ <item>1f408</item>
+ <item>1f431</item>
+ <item>1f400</item>
+ <item>1f401</item>
+ <item>1f42d</item>
+ <item>1f439</item>
+ <item>1f422</item>
+ <item>1f407</item>
+ <item>1f430</item>
+ <item>1f413</item>
+ <item>1f414</item>
+ <item>1f423</item>
+ <item>1f424</item>
+ <item>1f425</item>
+ <item>1f426</item>
+ <item>1f40f</item>
+ <item>1f411</item>
+ <item>1f410</item>
+ <item>1f43a</item>
+ <item>1f403</item>
+ <item>1f402</item>
+ <item>1f404</item>
+ <item>1f42e</item>
+ <item>1f434</item>
+ <item>1f417</item>
+ <item>1f416</item>
+ <item>1f437</item>
+ <item>1f43d</item>
+ <item>1f438</item>
+ <item>1f40d</item>
+ <item>1f43c</item>
+ <item>1f427</item>
+ <item>1f418</item>
+ <item>1f428</item>
+ <item>1f412</item>
+ <item>1f435</item>
+ <item>1f406</item>
+ <item>1f42f</item>
+ <item>1f43b</item>
+ <item>1f42b</item>
+ <item>1f42a</item>
+ <item>1f40a</item>
+ <item>1f433</item>
+ <item>1f40b</item>
+ <item>1f41f</item>
+ <item>1f420</item>
+ <item>1f421</item>
+ <item>1f419</item>
+ <item>1f41a</item>
+ <item>1f42c</item>
+ <item>1f40c</item>
+ <item>1f41b</item>
+ <item>1f41c</item>
+ <item>1f41d</item>
+ <item>1f41e</item>
+ <item>1f432</item>
+ <item>1f409</item>
+ <item>1f43e</item>
+ <item>1f378</item>
+ <item>1f37a</item>
+ <item>1f37b</item>
+ <item>1f377</item>
+ <item>1f379</item>
+ <item>1f376</item>
+ <item>2615</item>
+ <item>1f375</item>
+ <item>1f37c</item>
+ <item>1f374</item>
+ <item>1f368</item>
+ <item>1f367</item>
+ <item>1f366</item>
+ <item>1f369</item>
+ <item>1f370</item>
+ <item>1f36a</item>
+ <item>1f36b</item>
+ <item>1f36c</item>
+ <item>1f36d</item>
+ <item>1f36e</item>
+ <item>1f36f</item>
+ <item>1f373</item>
+ <item>1f354</item>
+ <item>1f35f</item>
+ <item>1f35d</item>
+ <item>1f355</item>
+ <item>1f356</item>
+ <item>1f357</item>
+ <item>1f364</item>
+ <item>1f363</item>
+ <item>1f371</item>
+ <item>1f35e</item>
+ <item>1f35c</item>
+ <item>1f359</item>
+ <item>1f35a</item>
+ <item>1f35b</item>
+ <item>1f372</item>
+ <item>1f365</item>
+ <item>1f362</item>
+ <item>1f361</item>
+ <item>1f358</item>
+ <item>1f360</item>
+ <item>1f34c</item>
+ <item>1f34e</item>
+ <item>1f34f</item>
+ <item>1f34a</item>
+ <item>1f34b</item>
+ <item>1f344</item>
+ <item>1f345</item>
+ <item>1f346</item>
+ <item>1f347</item>
+ <item>1f348</item>
+ <item>1f349</item>
+ <item>1f350</item>
+ <item>1f351</item>
+ <item>1f352</item>
+ <item>1f353</item>
+ <item>1f34d</item>
+ <item>1f330</item>
+ <item>1f331</item>
+ <item>1f332</item>
+ <item>1f333</item>
+ <item>1f334</item>
+ <item>1f335</item>
+ <item>1f337</item>
+ <item>1f338</item>
+ <item>1f339</item>
+ <item>1f340</item>
+ <item>1f341</item>
+ <item>1f342</item>
+ <item>1f343</item>
+ <item>1f33a</item>
+ <item>1f33b</item>
+ <item>1f33c</item>
+ <item>1f33d</item>
+ <item>1f33e</item>
+ <item>1f33f</item>
+ <item>2600</item>
+ <item>1f308</item>
+ <item>26c5</item>
+ <item>2601</item>
+ <item>1f301</item>
+ <item>1f302</item>
+ <item>2614</item>
+ <item>1f4a7</item>
+ <item>26a1</item>
+ <item>1f300</item>
+ <item>2744</item>
+ <item>26c4</item>
+ <item>1f319</item>
+ <item>1f31e</item>
+ <item>1f31d</item>
+ <item>1f31a</item>
+ <item>1f31b</item>
+ <item>1f31c</item>
+ <item>1f311</item>
+ <item>1f312</item>
+ <item>1f313</item>
+ <item>1f314</item>
+ <item>1f315</item>
+ <item>1f316</item>
+ <item>1f317</item>
+ <item>1f318</item>
+ <item>1f391</item>
+ <item>1f304</item>
+ <item>1f305</item>
+ <item>1f307</item>
+ <item>1f306</item>
+ <item>1f303</item>
+ <item>1f30c</item>
+ <item>1f309</item>
+ <item>1f30a</item>
+ <item>1f30b</item>
+ <item>1f30e</item>
+ <item>1f30f</item>
+ <item>1f30d</item>
+ <item>1f310</item>
+ </array>
+ <array
+ name="emoji_symbols"
+ format="string"
+ >
+ <item>fe82e|0031,20e3</item>
+ <item>fe82f|0032,20e3</item>
+ <item>fe830|0033,20e3</item>
+ <item>fe831|0034,20e3</item>
+ <item>fe832|0035,20e3</item>
+ <item>fe833|0036,20e3</item>
+ <item>fe834|0037,20e3</item>
+ <item>fe835|0038,20e3</item>
+ <item>fe836|0039,20e3</item>
+ <item>fe837|0030,20e3</item>
+ <item>1f51f</item>
+ <item>fe82c|0023,20e3</item>
+ <item>1f51d</item>
+ <item>1f519</item>
+ <item>1f51b</item>
+ <item>1f51c</item>
+ <item>1f51a</item>
+ <item>23f3</item>
+ <item>231b</item>
+ <item>23f0</item>
+ <item>2648</item>
+ <item>2649</item>
+ <item>264a</item>
+ <item>264b</item>
+ <item>264c</item>
+ <item>264d</item>
+ <item>264e</item>
+ <item>264f</item>
+ <item>2650</item>
+ <item>2651</item>
+ <item>2652</item>
+ <item>2653</item>
+ <item>26ce</item>
+ <item>1f531</item>
+ <item>1f52f</item>
+ <item>1f6bb</item>
+ <item>1f6ae</item>
+ <item>1f6af</item>
+ <item>1f6b0</item>
+ <item>1f6b1</item>
+ <item>1f170</item>
+ <item>1f171</item>
+ <item>1f18e</item>
+ <item>1f17e</item>
+ <item>1f4ae</item>
+ <item>1f4af</item>
+ <item>1f520</item>
+ <item>1f521</item>
+ <item>1f522</item>
+ <item>1f523</item>
+ <item>1f524</item>
+ <item>27bf</item>
+ <item>1f4f6</item>
+ <item>1f4f3</item>
+ <item>1f4f4</item>
+ <item>1f4f5</item>
+ <item>1f6b9</item>
+ <item>1f6ba</item>
+ <item>1f6bc</item>
+ <item>267f</item>
+ <item>267b</item>
+ <item>1f6ad</item>
+ <item>1f6a9</item>
+ <item>26a0</item>
+ <item>1f201</item>
+ <item>1f51e</item>
+ <item>26d4</item>
+ <item>1f192</item>
+ <item>1f197</item>
+ <item>1f195</item>
+ <item>1f198</item>
+ <item>1f199</item>
+ <item>1f193</item>
+ <item>1f196</item>
+ <item>1f19a</item>
+ <item>1f232</item>
+ <item>1f233</item>
+ <item>1f234</item>
+ <item>1f235</item>
+ <item>1f236</item>
+ <item>1f237</item>
+ <item>1f238</item>
+ <item>1f239</item>
+ <item>1f202</item>
+ <item>1f23a</item>
+ <item>1f250</item>
+ <item>1f251</item>
+ <item>3299</item>
+ <item>00ae</item>
+ <item>00a9</item>
+ <item>2122</item>
+ <item>1f21a</item>
+ <item>1f22f</item>
+ <item>3297</item>
+ <item>2b55</item>
+ <item>274c</item>
+ <item>274e</item>
+ <item>2139</item>
+ <item>1f6ab</item>
+ <item>2705</item>
+ <item>2714</item>
+ <item>1f517</item>
+ <item>2734</item>
+ <item>2733</item>
+ <item>2795</item>
+ <item>2796</item>
+ <item>2716</item>
+ <item>2797</item>
+ <item>1f4a0</item>
+ <item>1f4a1</item>
+ <item>1f4a4</item>
+ <item>1f4a2</item>
+ <item>1f525</item>
+ <item>1f4a5</item>
+ <item>1f4a8</item>
+ <item>1f4a6</item>
+ <item>1f4ab</item>
+ <item>1f55b</item>
+ <item>1f567</item>
+ <item>1f550</item>
+ <item>1f55c</item>
+ <item>1f551</item>
+ <item>1f55d</item>
+ <item>1f552</item>
+ <item>1f55e</item>
+ <item>1f553</item>
+ <item>1f55f</item>
+ <item>1f554</item>
+ <item>1f560</item>
+ <item>1f555</item>
+ <item>1f561</item>
+ <item>1f556</item>
+ <item>1f562</item>
+ <item>1f557</item>
+ <item>1f563</item>
+ <item>1f558</item>
+ <item>1f564</item>
+ <item>1f559</item>
+ <item>1f565</item>
+ <item>1f55a</item>
+ <item>1f566</item>
+ <item>2195</item>
+ <item>2b06</item>
+ <item>2197</item>
+ <item>27a1</item>
+ <item>2198</item>
+ <item>2b07</item>
+ <item>2199</item>
+ <item>2b05</item>
+ <item>2196</item>
+ <item>2194</item>
+ <item>2934</item>
+ <item>2935</item>
+ <item>23ea</item>
+ <item>23eb</item>
+ <item>23ec</item>
+ <item>23e9</item>
+ <item>25c0</item>
+ <item>25b6</item>
+ <item>1f53d</item>
+ <item>1f53c</item>
+ <item>2747</item>
+ <item>2728</item>
+ <item>1f534</item>
+ <item>1f535</item>
+ <item>26aa</item>
+ <item>26ab</item>
+ <item>1f533</item>
+ <item>1f532</item>
+ <item>2b50</item>
+ <item>1f31f</item>
+ <item>1f320</item>
+ <item>25ab</item>
+ <item>25aa</item>
+ <item>25fd</item>
+ <item>25fe</item>
+ <item>25fb</item>
+ <item>25fc</item>
+ <item>2b1c</item>
+ <item>2b1b</item>
+ <item>1f538</item>
+ <item>1f539</item>
+ <item>1f536</item>
+ <item>1f537</item>
+ <item>1f53a</item>
+ <item>1f53b</item>
+ <item>2754</item>
+ <item>2753</item>
+ <item>2755</item>
+ <item>2757</item>
+ <item>203c</item>
+ <item>2049</item>
+ <item>3030</item>
+ <item>27b0</item>
+ <item>2660</item>
+ <item>2665</item>
+ <item>2663</item>
+ <item>2666</item>
+ <item>1f194</item>
+ <item>1f511</item>
+ <item>21a9</item>
+ <item>1f191</item>
+ <item>1f50d</item>
+ <item>1f512</item>
+ <item>1f513</item>
+ <item>21aa</item>
+ <item>1f510</item>
+ <item>2611</item>
+ <item>1f518</item>
+ <item>1f50e</item>
+ <item>1f516</item>
+ <item>1f50f</item>
+ <item>1f503</item>
+ <item>1f500</item>
+ <item>1f501</item>
+ <item>1f502</item>
+ <item>1f504</item>
+ <item>1f4e7</item>
+ <item>1f505</item>
+ <item>1f506</item>
+ <item>1f507</item>
+ <item>1f508</item>
+ <item>1f509</item>
+ <item>1f50a</item>
+ </array>
+ <array
+ name="emoji_faces"
+ format="string"
+ >
+ <item>263a</item>
+ <item>1f60a</item>
+ <item>1f600</item>
+ <item>1f601</item>
+ <item>1f602</item>
+ <item>1f603</item>
+ <item>1f604</item>
+ <item>1f605</item>
+ <item>1f606</item>
+ <item>1f607</item>
+ <item>1f608</item>
+ <item>1f609</item>
+ <item>1f62f</item>
+ <item>1f610</item>
+ <item>1f611</item>
+ <item>1f615</item>
+ <item>1f620</item>
+ <item>1f62c</item>
+ <item>1f621</item>
+ <item>1f622</item>
+ <item>1f634</item>
+ <item>1f62e</item>
+ <item>1f623</item>
+ <item>1f624</item>
+ <item>1f625</item>
+ <item>1f626</item>
+ <item>1f627</item>
+ <item>1f628</item>
+ <item>1f629</item>
+ <item>1f630</item>
+ <item>1f61f</item>
+ <item>1f631</item>
+ <item>1f632</item>
+ <item>1f633</item>
+ <item>1f635</item>
+ <item>1f636</item>
+ <item>1f637</item>
+ <item>1f61e</item>
+ <item>1f612</item>
+ <item>1f60d</item>
+ <item>1f61b</item>
+ <item>1f61c</item>
+ <item>1f61d</item>
+ <item>1f60b</item>
+ <item>1f617</item>
+ <item>1f619</item>
+ <item>1f618</item>
+ <item>1f61a</item>
+ <item>1f60e</item>
+ <item>1f62d</item>
+ <item>1f60c</item>
+ <item>1f616</item>
+ <item>1f614</item>
+ <item>1f62a</item>
+ <item>1f60f</item>
+ <item>1f613</item>
+ <item>1f62b</item>
+ <item>1f64b</item>
+ <item>1f64c</item>
+ <item>1f64d</item>
+ <item>1f645</item>
+ <item>1f646</item>
+ <item>1f647</item>
+ <item>1f64e</item>
+ <item>1f64f</item>
+ <item>1f63a</item>
+ <item>1f63c</item>
+ <item>1f638</item>
+ <item>1f639</item>
+ <item>1f63b</item>
+ <item>1f63d</item>
+ <item>1f63f</item>
+ <item>1f63e</item>
+ <item>1f640</item>
+ <item>1f648</item>
+ <item>1f649</item>
+ <item>1f64a</item>
+ <item>1f4a9</item>
+ <item>1f476</item>
+ <item>1f466</item>
+ <item>1f467</item>
+ <item>1f468</item>
+ <item>1f469</item>
+ <item>1f474</item>
+ <item>1f475</item>
+ <item>1f48f</item>
+ <item>1f491</item>
+ <item>1f46a</item>
+ <item>1f46b</item>
+ <item>1f46c</item>
+ <item>1f46d</item>
+ <item>1f464</item>
+ <item>1f465</item>
+ <item>1f46e</item>
+ <item>1f477</item>
+ <item>1f481</item>
+ <item>1f482</item>
+ <item>1f46f</item>
+ <item>1f470</item>
+ <item>1f478</item>
+ <item>1f385</item>
+ <item>1f47c</item>
+ <item>1f471</item>
+ <item>1f472</item>
+ <item>1f473</item>
+ <item>1f483</item>
+ <item>1f486</item>
+ <item>1f487</item>
+ <item>1f485</item>
+ <item>1f47b</item>
+ <item>1f479</item>
+ <item>1f47a</item>
+ <item>1f47d</item>
+ <item>1f47e</item>
+ <item>1f47f</item>
+ <item>1f480</item>
+ <item>1f4aa</item>
+ <item>1f440</item>
+ <item>1f442</item>
+ <item>1f443</item>
+ <item>1f463</item>
+ <item>1f444</item>
+ <item>1f445</item>
+ <item>1f48b</item>
+ <item>2764</item>
+ <item>1f499</item>
+ <item>1f49a</item>
+ <item>1f49b</item>
+ <item>1f49c</item>
+ <item>1f493</item>
+ <item>1f494</item>
+ <item>1f495</item>
+ <item>1f496</item>
+ <item>1f497</item>
+ <item>1f498</item>
+ <item>1f49d</item>
+ <item>1f49e</item>
+ <item>1f49f</item>
+ <item>1f44d</item>
+ <item>1f44e</item>
+ <item>1f44c</item>
+ <item>270a</item>
+ <item>270c</item>
+ <item>270b</item>
+ <item>1f44a</item>
+ <item>261d</item>
+ <item>1f446</item>
+ <item>1f447</item>
+ <item>1f448</item>
+ <item>1f449</item>
+ <item>1f44b</item>
+ <item>1f44f</item>
+ <item>1f450</item>
+ </array>
+ <array
+ name="emoji_objects"
+ format="string"
+ >
+ <item>1f530</item>
+ <item>1f484</item>
+ <item>1f45e</item>
+ <item>1f45f</item>
+ <item>1f451</item>
+ <item>1f452</item>
+ <item>1f3a9</item>
+ <item>1f393</item>
+ <item>1f453</item>
+ <item>231a</item>
+ <item>1f454</item>
+ <item>1f455</item>
+ <item>1f456</item>
+ <item>1f457</item>
+ <item>1f458</item>
+ <item>1f459</item>
+ <item>1f460</item>
+ <item>1f461</item>
+ <item>1f462</item>
+ <item>1f45a</item>
+ <item>1f45c</item>
+ <item>1f4bc</item>
+ <item>1f392</item>
+ <item>1f45d</item>
+ <item>1f45b</item>
+ <item>1f4b0</item>
+ <item>1f4b3</item>
+ <item>1f4b2</item>
+ <item>1f4b5</item>
+ <item>1f4b4</item>
+ <item>1f4b6</item>
+ <item>1f4b7</item>
+ <item>1f4b8</item>
+ <item>1f4b1</item>
+ <item>1f4b9</item>
+ <item>1f52b</item>
+ <item>1f52a</item>
+ <item>1f4a3</item>
+ <item>1f489</item>
+ <item>1f48a</item>
+ <item>1f6ac</item>
+ <item>1f514</item>
+ <item>1f515</item>
+ <item>1f6aa</item>
+ <item>1f52c</item>
+ <item>1f52d</item>
+ <item>1f52e</item>
+ <item>1f526</item>
+ <item>1f50b</item>
+ <item>1f50c</item>
+ <item>1f4dc</item>
+ <item>1f4d7</item>
+ <item>1f4d8</item>
+ <item>1f4d9</item>
+ <item>1f4da</item>
+ <item>1f4d4</item>
+ <item>1f4d2</item>
+ <item>1f4d1</item>
+ <item>1f4d3</item>
+ <item>1f4d5</item>
+ <item>1f4d6</item>
+ <item>1f4f0</item>
+ <item>1f4db</item>
+ <item>1f383</item>
+ <item>1f384</item>
+ <item>1f380</item>
+ <item>1f381</item>
+ <item>1f382</item>
+ <item>1f388</item>
+ <item>1f386</item>
+ <item>1f387</item>
+ <item>1f389</item>
+ <item>1f38a</item>
+ <item>1f38d</item>
+ <item>1f38f</item>
+ <item>1f38c</item>
+ <item>1f390</item>
+ <item>1f38b</item>
+ <item>1f38e</item>
+ <item>1f4f1</item>
+ <item>1f4f2</item>
+ <item>1f4df</item>
+ <item>260e</item>
+ <item>1f4de</item>
+ <item>1f4e0</item>
+ <item>1f4e6</item>
+ <item>2709</item>
+ <item>1f4e8</item>
+ <item>1f4e9</item>
+ <item>1f4ea</item>
+ <item>1f4eb</item>
+ <item>1f4ed</item>
+ <item>1f4ec</item>
+ <item>1f4ee</item>
+ <item>1f4e4</item>
+ <item>1f4e5</item>
+ <item>1f4ef</item>
+ <item>1f4e2</item>
+ <item>1f4e3</item>
+ <item>1f4e1</item>
+ <item>1f4ac</item>
+ <item>1f4ad</item>
+ <item>2712</item>
+ <item>270f</item>
+ <item>1f4dd</item>
+ <item>1f4cf</item>
+ <item>1f4d0</item>
+ <item>1f4cd</item>
+ <item>1f4cc</item>
+ <item>1f4ce</item>
+ <item>2702</item>
+ <item>1f4ba</item>
+ <item>1f4bb</item>
+ <item>1f4bd</item>
+ <item>1f4be</item>
+ <item>1f4bf</item>
+ <item>1f4c6</item>
+ <item>1f4c5</item>
+ <item>1f4c7</item>
+ <item>1f4cb</item>
+ <item>1f4c1</item>
+ <item>1f4c2</item>
+ <item>1f4c3</item>
+ <item>1f4c4</item>
+ <item>1f4ca</item>
+ <item>1f4c8</item>
+ <item>1f4c9</item>
+ <item>26fa</item>
+ <item>1f3a1</item>
+ <item>1f3a2</item>
+ <item>1f3a0</item>
+ <item>1f3aa</item>
+ <item>1f3a8</item>
+ <item>1f3ac</item>
+ <item>1f3a5</item>
+ <item>1f4f7</item>
+ <item>1f4f9</item>
+ <item>1f3a6</item>
+ <item>1f3ad</item>
+ <item>1f3ab</item>
+ <item>1f3ae</item>
+ <item>1f3b2</item>
+ <item>1f3b0</item>
+ <item>1f0cf</item>
+ <item>1f3b4</item>
+ <item>1f004</item>
+ <item>1f3af</item>
+ <item>1f4fa</item>
+ <item>1f4fb</item>
+ <item>1f4c0</item>
+ <item>1f4fc</item>
+ <item>1f3a7</item>
+ <item>1f3a4</item>
+ <item>1f3b5</item>
+ <item>1f3b6</item>
+ <item>1f3bc</item>
+ <item>1f3bb</item>
+ <item>1f3b9</item>
+ <item>1f3b7</item>
+ <item>1f3ba</item>
+ <item>1f3b8</item>
+ <item>303d</item>
+ </array>
+ <array
+ name="emoji_places"
+ format="string"
+ >
+ <item>1f3e0</item>
+ <item>1f3e1</item>
+ <item>1f3e2</item>
+ <item>1f3e3</item>
+ <item>1f3e4</item>
+ <item>1f3e5</item>
+ <item>1f3e6</item>
+ <item>1f3e7</item>
+ <item>1f3e8</item>
+ <item>1f3e9</item>
+ <item>1f3ea</item>
+ <item>1f3eb</item>
+ <item>26ea</item>
+ <item>26f2</item>
+ <item>1f3ec</item>
+ <item>1f3ef</item>
+ <item>1f3f0</item>
+ <item>1f3ed</item>
+ <item>1f5fb</item>
+ <item>1f5fc</item>
+ <item>1f5fd</item>
+ <item>1f5fe</item>
+ <item>1f5ff</item>
+ <item>2693</item>
+ <item>1f3ee</item>
+ <item>1f488</item>
+ <item>1f527</item>
+ <item>1f528</item>
+ <item>1f529</item>
+ <item>1f6bf</item>
+ <item>1f6c1</item>
+ <item>1f6c0</item>
+ <item>1f6bd</item>
+ <item>1f6be</item>
+ <item>1f3bd</item>
+ <item>1f3a3</item>
+ <item>1f3b1</item>
+ <item>1f3b3</item>
+ <item>26be</item>
+ <item>26f3</item>
+ <item>1f3be</item>
+ <item>26bd</item>
+ <item>1f3bf</item>
+ <item>1f3c0</item>
+ <item>1f3c1</item>
+ <item>1f3c2</item>
+ <item>1f3c3</item>
+ <item>1f3c4</item>
+ <item>1f3c6</item>
+ <item>1f3c7</item>
+ <item>1f40e</item>
+ <item>1f3c8</item>
+ <item>1f3c9</item>
+ <item>1f3ca</item>
+ <item>1f682</item>
+ <item>1f683</item>
+ <item>1f684</item>
+ <item>1f685</item>
+ <item>1f686</item>
+ <item>1f687</item>
+ <item>24c2</item>
+ <item>1f688</item>
+ <item>1f68a</item>
+ <item>1f68b</item>
+ <item>1f68c</item>
+ <item>1f68d</item>
+ <item>1f68e</item>
+ <item>1f68f</item>
+ <item>1f690</item>
+ <item>1f691</item>
+ <item>1f692</item>
+ <item>1f693</item>
+ <item>1f694</item>
+ <item>1f695</item>
+ <item>1f696</item>
+ <item>1f697</item>
+ <item>1f698</item>
+ <item>1f699</item>
+ <item>1f69a</item>
+ <item>1f69b</item>
+ <item>1f69c</item>
+ <item>1f69d</item>
+ <item>1f69e</item>
+ <item>1f69f</item>
+ <item>1f6a0</item>
+ <item>1f6a1</item>
+ <item>1f6a2</item>
+ <item>1f6a3</item>
+ <item>1f681</item>
+ <item>2708</item>
+ <item>1f6c2</item>
+ <item>1f6c3</item>
+ <item>1f6c4</item>
+ <item>1f6c5</item>
+ <item>26f5</item>
+ <item>1f6b2</item>
+ <item>1f6b3</item>
+ <item>1f6b4</item>
+ <item>1f6b5</item>
+ <item>1f6b7</item>
+ <item>1f6b8</item>
+ <item>1f689</item>
+ <item>1f680</item>
+ <item>1f6a4</item>
+ <item>1f6b6</item>
+ <item>26fd</item>
+ <item>1f17f</item>
+ <item>1f6a5</item>
+ <item>1f6a6</item>
+ <item>1f6a7</item>
+ <item>1f6a8</item>
+ <item>2668</item>
+ <item>1f48c</item>
+ <item>1f48d</item>
+ <item>1f48e</item>
+ <item>1f490</item>
+ <item>1f492</item>
+ <item>fe4e5|1f1ef,1f1f5</item>
+ <item>fe4e6|1f1fa,1f1f8</item>
+ <item>fe4e7|1f1eb,1f1f7</item>
+ <item>fe4e8|1f1e9,1f1ea</item>
+ <item>fe4e9|1f1ee,1f1f9</item>
+ <item>fe4ea|1f1ec,1f1e7</item>
+ <item>fe4eb|1f1ea,1f1f8</item>
+ <item>fe4ec|1f1f7,1f1fa</item>
+ <item>fe4ed|1f1e8,1f1f3</item>
+ <item>fe4ee|1f1f0,1f1f7</item>
+ </array>
+ <array
+ name="emoji_emoticons"
+ format="string"
+ >
+ <item>=-O</item>
+ <item>:-P</item>
+ <item>;-)</item>
+ <item>:-(</item>
+ <item>:-)</item>
+ <item>:-!</item>
+ <item>:-$</item>
+ <item>B-)</item>
+ <item>:O</item>
+ <item>:-*</item>
+ <item>:-D</item>
+ <item>:\'(</item>
+ <item>:-\\</item>
+ <item>O:-)</item>
+ <item>:-[</item>
+ </array>
+</resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 67b140ef3..e08d1c6b9 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Bảng chữ cái (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Bảng chữ cái (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Bảng chữ cái (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"Biểu tượng cảm xúc"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Kiểu nhập tùy chỉnh"</string>
<string name="add_style" msgid="6163126614514489951">"Thêm kiểu"</string>
<string name="add" msgid="8299699805688017798">"Thêm"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 461d326b1..5980cbf13 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"自定义输入风格"</string>
<string name="add_style" msgid="6163126614514489951">"添加样式"</string>
<string name="add" msgid="8299699805688017798">"添加"</string>
diff --git a/java/res/values-zh-rHK/strings-appname.xml b/java/res/values-zh-rHK/strings-appname.xml
new file mode 100644
index 000000000..8761a98d0
--- /dev/null
+++ b/java/res/values-zh-rHK/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">"Android 鍵盤 (AOSP)"</string>
+ <string name="spell_checker_service_name" msgid="1254221805440242662">"Android 拼字檢查工具 (AOSP)"</string>
+ <string name="english_ime_settings" msgid="5760361067176802794">"Android 鍵盤設定 (AOSP)"</string>
+ <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android 拼字檢查工具設定 (AOSP)"</string>
+</resources>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000..74be1e453
--- /dev/null
+++ b/java/res/values-zh-rHK/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">"從 Shift 鍵或符號鍵開始滑動時顯示視覺提示"</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_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="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"開始"</string>
+ <string name="label_next_key" msgid="362972844525672568">"下一步"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"上一步"</string>
+ <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
+ <string name="label_send_key" msgid="2815056534433717444">"發送"</string>
+ <string name="label_pause_key" msgid="181098308428035340">"暫停"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"等候"</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_description_unknown" msgid="3197434010402179157">"按鍵代碼 %d"</string>
+ <string name="spoken_description_shift" msgid="244197883292549308">"Shift 鍵"</string>
+ <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 鍵已開啟 (輕按即可停用)"</string>
+ <string name="spoken_description_caps_lock" msgid="3276478269526304432">"大寫鎖定已開啟 (輕按即可停用)"</string>
+ <string name="spoken_description_delete" msgid="8740376944276199801">"刪除"</string>
+ <string name="spoken_description_to_symbol" msgid="5486340107500448969">"符號"</string>
+ <string name="spoken_description_to_alpha" msgid="23129338819771807">"字母"</string>
+ <string name="spoken_description_to_numeric" msgid="591752092685161732">"數字"</string>
+ <string name="spoken_description_settings" msgid="4627462689603838099">"設定"</string>
+ <string name="spoken_description_tab" msgid="2667716002663482248">"Tab 鍵"</string>
+ <string name="spoken_description_space" msgid="2582521050049860859">"空白鍵"</string>
+ <string name="spoken_description_mic" msgid="615536748882611950">"語音輸入"</string>
+ <string name="spoken_description_smiley" msgid="2256309826200113918">"笑臉"</string>
+ <string name="spoken_description_return" msgid="8178083177238315647">"Return 鍵"</string>
+ <string name="spoken_description_search" msgid="1247236163755920808">"搜尋"</string>
+ <string name="spoken_description_dot" msgid="40711082435231673">"點"</string>
+ <string name="spoken_description_language_switch" msgid="5507091328222331316">"切換語言"</string>
+ <string name="spoken_description_action_next" msgid="8636078276664150324">"下一步"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"上一步"</string>
+ <string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 鍵已啟用"</string>
+ <string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大寫鎖定已啟用"</string>
+ <string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 鍵已停用"</string>
+ <string name="spoken_description_mode_symbol" msgid="7183343879909747642">"符號模式"</string>
+ <string name="spoken_description_mode_alpha" msgid="3528307674390156956">"字母模式"</string>
+ <string name="spoken_description_mode_phone" msgid="6520207943132026264">"撥號模式"</string>
+ <string name="spoken_description_mode_phone_shift" msgid="5499629753962641227">"符號撥號模式"</string>
+ <string name="announce_keyboard_hidden" msgid="8718927835531429807">"鍵盤已隱藏"</string>
+ <string name="announce_keyboard_mode" msgid="4729081055438508321">"目前顯示的是<xliff:g id="MODE">%s</xliff:g>鍵盤"</string>
+ <string name="keyboard_mode_date" msgid="3137520166817128102">"日期"</string>
+ <string name="keyboard_mode_date_time" msgid="339593358488851072">"日期和時間"</string>
+ <string name="keyboard_mode_email" msgid="6216248078128294262">"電郵"</string>
+ <string name="keyboard_mode_im" msgid="1137405089766557048">"短訊"</string>
+ <string name="keyboard_mode_number" msgid="7991623440699957069">"數字"</string>
+ <string name="keyboard_mode_phone" msgid="6851627527401433229">"電話"</string>
+ <string name="keyboard_mode_text" msgid="6479436687899701619">"文字"</string>
+ <string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
+ <string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string>
+ <string name="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">"自動傳送使用統計資料和當機報告,協助改良這個輸入法編輯器"</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="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_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">"Emoji"</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="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">"現在,您可以在所有最愛的應用程式中使用「<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="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> 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_description" msgid="1075194169443163487">"按下即可查看並下載"</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">"確定"</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-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 8d7b155c7..b14a01a0a 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -25,15 +25,15 @@
<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="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" 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>
@@ -44,7 +44,7 @@
<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" msgid="4435317977804180815">"建議聯絡人姓名"</string>
<string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string>
<string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string>
<string name="use_double_space_period_summary" msgid="6532892187247952799">"輕按兩下空格鍵可插入句號另加一個空格"</string>
@@ -57,7 +57,7 @@
<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_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>
@@ -74,13 +74,13 @@
<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="label_go_key" msgid="1635148082137219148">"開始"</string>
- <string name="label_next_key" msgid="362972844525672568">"繼續"</string>
- <string name="label_previous_key" msgid="1211868118071386787">"上一步"</string>
+ <string name="label_go_key" msgid="1635148082137219148">"前往"</string>
+ <string name="label_next_key" msgid="362972844525672568">"下一頁"</string>
+ <string name="label_previous_key" msgid="1211868118071386787">"上一頁"</string>
<string name="label_done_key" msgid="2441578748772529288">"完成"</string>
<string name="label_send_key" msgid="2815056534433717444">"傳送"</string>
<string name="label_pause_key" msgid="181098308428035340">"暫停"</string>
- <string name="label_wait_key" msgid="6402152600878093134">"等候"</string>
+ <string name="label_wait_key" msgid="6402152600878093134">"等待"</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>
@@ -101,8 +101,8 @@
<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_action_next" msgid="8636078276664150324">"下一頁"</string>
+ <string name="spoken_description_action_previous" msgid="800872415009336208">"上一頁"</string>
<string name="spoken_description_shiftmode_on" msgid="5700440798609574589">"Shift 鍵已啟用"</string>
<string name="spoken_description_shiftmode_locked" msgid="593175803181701830">"大寫鎖定已啟用"</string>
<string name="spoken_description_shiftmode_off" msgid="657219998449174808">"Shift 鍵已停用"</string>
@@ -117,7 +117,7 @@
<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_phone" msgid="6851627527401433229">"電話號碼"</string>
<string name="keyboard_mode_text" msgid="6479436687899701619">"文字"</string>
<string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
<string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string>
@@ -133,16 +133,17 @@
<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="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_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_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>
@@ -150,6 +151,7 @@
<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="custom_input_styles_title" msgid="8429952441821251512">"自訂輸入樣式"</string>
<string name="add_style" msgid="6163126614514489951">"新增樣式"</string>
<string name="add" msgid="8299699805688017798">"新增"</string>
@@ -171,7 +173,7 @@
<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_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>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 38a5c27bf..9ed88a00f 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -143,6 +143,7 @@
<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_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>
@@ -150,6 +151,7 @@
<string name="subtype_no_language_dvorak" msgid="1564494667584718094">"Alfabhethi (Dvorak)"</string>
<string name="subtype_no_language_colemak" msgid="5837418400010302623">"Alfabhethi (Colemak)"</string>
<string name="subtype_no_language_pcqwerty" msgid="5354918232046200018">"Alfabhethi (PC)"</string>
+ <string name="subtype_emoji" msgid="7483586578074549196">"I-Emoji"</string>
<string name="custom_input_styles_title" msgid="8429952441821251512">"Izitayela zokufaka ngokwezifiso"</string>
<string name="add_style" msgid="6163126614514489951">"Engeza isitayela"</string>
<string name="add" msgid="8299699805688017798">"Engeza"</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 5c59f5f68..09782143f 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -1,17 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+<!--
+/*
+**
+** 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>
@@ -22,15 +26,18 @@
<attr name="keyboardViewStyle" format="reference" />
<!-- MainKeyboardView style -->
<attr name="mainKeyboardViewStyle" format="reference" />
+ <!-- EmojiKeyboardView style -->
+ <attr name="emojiKeyboardViewStyle" format="reference" />
<!-- MoreKeysKeyboard style -->
<attr name="moreKeysKeyboardStyle" format="reference" />
<!-- MoreKeysKeyboardView style -->
<attr name="moreKeysKeyboardViewStyle" format="reference" />
- <attr name="moreKeysKeyboardPanelStyle" format="reference" />
+ <!-- MoreKeysKeyboardView container style -->
+ <attr name="moreKeysKeyboardContainerStyle" format="reference" />
<!-- Suggestions strip style -->
<attr name="suggestionStripViewStyle" format="reference" />
- <attr name="moreSuggestionsViewStyle" format="reference" />
- <attr name="suggestionBackgroundStyle" format="reference" />
+ <!-- Suggestion word style -->
+ <attr name="suggestionWordStyle" format="reference" />
</declare-styleable>
<declare-styleable name="KeyboardView">
@@ -38,6 +45,8 @@
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" />
<!-- Horizontal padding of left/right aligned key label to the edge of the key. -->
<attr name="keyLabelHorizontalPadding" format="dimension" />
@@ -158,6 +167,10 @@
<attr name="suppressKeyPreviewAfterBatchInputDuration" format="integer" />
</declare-styleable>
+ <declare-styleable name="EmojiKeyboardView">
+ <attr name="emojiTabLabelColor" format="reference" />
+ </declare-styleable>
+
<declare-styleable name="SuggestionStripView">
<attr name="suggestionStripOption" format="integer">
<!-- This should be aligned with SuggestionStripLayoutHelper.AUTO_CORRECT_* and etc. -->
@@ -169,10 +182,6 @@
<attr name="colorTypedWord" format="color" />
<attr name="colorAutoCorrect" format="color" />
<attr name="colorSuggested" format="color" />
- <attr name="alphaValidTypedWord" format="fraction" />
- <attr name="alphaTypedWord" format="fraction" />
- <attr name="alphaAutoCorrect" format="fraction" />
- <attr name="alphaSuggested" format="fraction" />
<attr name="alphaObsoleted" format="fraction" />
<attr name="suggestionsCountInStrip" format="integer" />
<attr name="centerSuggestionPercentile" format="fraction" />
@@ -216,9 +225,15 @@
<attr name="iconLanguageSwitchKey" format="reference" />
<attr name="iconZwnjKey" format="reference" />
<attr name="iconZwjKey" format="reference" />
+ <attr name="iconImeKey" format="reference" />
<attr name="iconEmojiKey" format="reference" />
</declare-styleable>
+ <declare-styleable name="Keyboard_GridRows">
+ <attr name="codesArray" format="reference" />
+ <attr name="textsArray" format="reference" />
+ </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
@@ -366,6 +381,7 @@
</declare-styleable>
<declare-styleable name="Keyboard_Case">
+ <attr name="keyboardLayoutSet" format="string" />
<!-- This should be aligned with KeyboardLayoutSet_Element's elementName. -->
<attr name="keyboardLayoutSetElement" format="enum|string">
<enum name="alphabet" value="0" />
@@ -378,6 +394,13 @@
<enum name="phone" value="7" />
<enum name="phoneSymbols" value="8" />
<enum name="number" value="9" />
+ <enum name="emojiRecents" value="10" />
+ <enum name="emojiCategory1" value="11" />
+ <enum name="emojiCategory2" value="12" />
+ <enum name="emojiCategory3" value="13" />
+ <enum name="emojiCategory4" value="14" />
+ <enum name="emojiCategory5" value="15" />
+ <enum name="emojiCategory6" value="16" />
</attr>
<!-- This should be aligned with KeyboardId.MODE_* -->
<attr name="mode" format="enum|string">
@@ -433,6 +456,13 @@
<enum name="phone" value="7" />
<enum name="phoneSymbols" value="8" />
<enum name="number" value="9" />
+ <enum name="emojiRecents" value="10" />
+ <enum name="emojiCategory1" value="11" />
+ <enum name="emojiCategory2" value="12" />
+ <enum name="emojiCategory3" value="13" />
+ <enum name="emojiCategory4" value="14" />
+ <enum name="emojiCategory5" value="15" />
+ <enum name="emojiCategory6" value="16" />
</attr>
<attr name="elementKeyboard" format="reference"/>
<!-- Enable proximity characters correction. Disabled by default. -->
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index daa167c8a..3803cb776 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -1,47 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Color resources for default, and Gingerbread theme. -->
- <color name="highlight_color_default">#FFFCAE00</color>
- <color name="highlight_translucent_color_default">#99FCAE00</color>
- <color name="key_text_color_default">@android:color/white</color>
- <color name="key_text_shadow_color_default">#BB000000</color>
- <color name="key_text_inactivated_color_default">@android:color/white</color>
- <color name="key_hint_letter_color_default">#80000000</color>
- <color name="key_hint_label_color_default">#E0E0E4E5</color>
- <color name="key_shifted_letter_hint_inactivated_color_default">#66E0E4E5</color>
- <color name="key_shifted_letter_hint_activated_color_default">#CCE0E4E5</color>
- <color name="spacebar_text_color_default">#FFC0C0C0</color>
- <color name="spacebar_text_shadow_color_default">#80000000</color>
- <color name="typed_word_color_default">@android:color/white</color>
- <color name="gesture_floating_preview_color_default">#C0000000</color>
- <!-- Color resources for Stone theme. -->
- <color name="key_text_color_stone">@android:color/black</color>
- <color name="key_text_shadow_color_stone">@android:color/white</color>
- <color name="key_text_inactivated_color_stone">#FF808080</color>
- <color name="key_hint_letter_color_stone">#80000000</color>
- <color name="key_hint_label_color_stone">#E0000000</color>
- <color name="key_shifted_letter_hint_inactivated_color_stone">#66000000</color>
- <color name="key_shifted_letter_hint_activated_color_stone">#CC000000</color>
- <color name="spacebar_text_color_stone">@android:color/black</color>
- <color name="spacebar_text_shadow_color_stone">#D0FFFFFF</color>
- <!-- Color resources for IceCreamSandwich theme. -->
+ <!-- Color resources for Gingerbread theme. -->
+ <color name="highlight_color_gb">#FFFCAE00</color>
+ <color name="typed_word_color_gb">@android:color/white</color>
+ <color name="highlight_translucent_color_gb">#99FCAE00</color>
+ <color name="key_text_color_gb">@android:color/white</color>
+ <color name="key_text_shadow_color_gb">#BB000000</color>
+ <color name="key_text_inactivated_color_gb">#66E0E4E5</color>
+ <color name="key_hint_letter_color_gb">#80000000</color>
+ <color name="key_hint_label_color_gb">#E0E0E4E5</color>
+ <color name="key_shifted_letter_hint_inactivated_color_gb">#66E0E4E5</color>
+ <color name="key_shifted_letter_hint_activated_color_gb">#CCE0E4E5</color>
+ <color name="spacebar_text_color_gb">#FFC0C0C0</color>
+ <color name="spacebar_text_shadow_color_gb">#80000000</color>
+ <color name="gesture_floating_preview_color_gb">#C0000000</color>
+ <!-- Color resources for IceCreamSandwich theme. Base color = 33B5E5 -->
<!-- android:color/holo_blue_light value is #FF33B5E5 -->
- <color name="highlight_color_ics">@android:color/holo_blue_light</color>
+ <color name="highlight_color_ics">#FF33B5E5</color>
+ <color name="typed_word_color_ics">#D833B5E5</color>
+ <color name="suggested_word_color_ics">#B233B5E5</color>
<color name="highlight_translucent_color_ics">#9933B5E5</color>
<color name="key_text_color_ics">@android:color/white</color>
<color name="key_text_shadow_color_ics">@android:color/transparent</color>
@@ -52,11 +48,22 @@
<color name="key_shifted_letter_hint_activated_color_ics">@android:color/white</color>
<color name="spacebar_text_color_ics">#FFC0C0C0</color>
<color name="spacebar_text_shadow_color_ics">#80000000</color>
- <color name="typed_word_color_ics">@color/highlight_color_ics</color>
+ <color name="gesture_floating_preview_color_ics">#C0000000</color>
+ <!-- Color resources for KLP theme. Base color = F0F0F0 -->
+ <color name="highlight_color_holo">#FFF0F0F0</color>
+ <color name="typed_word_color_holo">#D8F0F0F0</color>
+ <color name="suggested_word_color_holo">#B2F0F0F0</color>
+ <color name="highlight_translucent_color_holo">#99E0E0E0</color>
<!-- Color resources for setup wizard and tutorial -->
<color name="setup_background">#FFEBEBEB</color>
<color name="setup_text_dark">#FF707070</color>
<color name="setup_text_action">@android:color/holo_blue_light</color>
<color name="setup_step_background">@android:color/background_light</color>
<color name="setup_welcome_video_margin_color">#FFCCCCCC</color>
+ <color name="emoji_category_page_id_view_background">#FF000000</color>
+ <color name="emoji_category_page_id_view_foreground">#80FFFFFF</color>
+
+ <!-- TODO: Color which should be included in the theme -->
+ <color name="emoji_key_background_color">#00000000</color>
+ <color name="emoji_key_pressed_background_color">#30FFFFFF</color>
</resources>
diff --git a/java/res/values/config-additional-features.xml b/java/res/values/config-additional-features.xml
new file mode 100644
index 000000000..47eb7724c
--- /dev/null
+++ b/java/res/values/config-additional-features.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>
+ <!-- Whether phrase gestures are enabled by default -->
+ <bool name="config_default_phrase_gesture_enabled">false</bool>
+</resources>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index d3a21f2aa..465d52cec 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -42,7 +42,7 @@
<integer name="config_keyboard_grid_height">16</integer>
<integer name="config_double_space_period_timeout">1100</integer>
<!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
- <string name="config_default_keyboard_theme_index" translatable="false">5</string>
+ <string name="config_default_keyboard_theme_index" translatable="false">0</string>
<integer name="config_max_more_keys_column">5</integer>
<!--
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 98ae76cb1..4e3b2f567 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -29,18 +29,11 @@
<dimen name="more_keys_keyboard_key_horizontal_padding">8dp</dimen>
- <fraction name="keyboard_top_padding">1.556%p</fraction>
- <fraction name="keyboard_bottom_padding">4.669%p</fraction>
<fraction name="keyboard_left_padding">0%p</fraction>
<fraction name="keyboard_right_padding">0%p</fraction>
- <fraction name="key_bottom_gap">6.250%p</fraction>
- <fraction name="key_horizontal_gap">1.352%p</fraction>
-
- <fraction name="keyboard_top_padding_stone">1.556%p</fraction>
- <fraction name="keyboard_bottom_padding_stone">0.778%p</fraction>
- <fraction name="key_bottom_gap_stone">7.506%p</fraction>
- <fraction name="key_horizontal_gap_stone">1.739%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>
@@ -48,13 +41,12 @@
<fraction name="keyboard_bottom_padding_ics">4.669%p</fraction>
<fraction name="key_bottom_gap_ics">6.127%p</fraction>
<fraction name="key_horizontal_gap_ics">1.739%p</fraction>
- <dimen name="more_keys_keyboard_horizontal_edges_padding_ics">4dp</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">63.36dp</dimen>
<!-- popup_key_height x -1.0 -->
- <dimen name="more_keys_keyboard_vertical_correction">-52.8dp</dimen>
+ <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>
@@ -67,7 +59,7 @@
<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">-8.0dp</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>
@@ -121,10 +113,20 @@
<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">3dp</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">90%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 e352f082b..42e692d2f 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -18,6 +18,8 @@
*/
-->
<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) -->
@@ -29,6 +31,8 @@
<string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
<string name="symbols_word_connectors">\'-</string>
+ <!-- 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>
@@ -94,29 +98,17 @@
<string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string>
<!-- Keyboard theme names -->
- <string name="layout_basic">Basic</string>
- <string name="layout_high_contrast">Basic (High Contrast)</string>
- <string name="layout_stone_bold">Stone (bold)</string>
- <string name="layout_stone_normal">Stone (normal)</string>
<string name="layout_gingerbread">Gingerbread</string>
<string name="layout_ics">IceCreamSandwich</string>
<!-- For keyboard theme switcher dialog -->
<string-array name="keyboard_layout_modes">
- <item>@string/layout_basic</item>
- <item>@string/layout_high_contrast</item>
- <item>@string/layout_stone_normal</item>
- <item>@string/layout_stone_bold</item>
- <item>@string/layout_gingerbread</item>
<item>@string/layout_ics</item>
+ <item>@string/layout_gingerbread</item>
</string-array>
<string-array name="keyboard_layout_modes_values">
<item>0</item>
<item>1</item>
- <item>2</item>
- <item>3</item>
- <item>4</item>
- <item>5</item>
</string-array>
<!-- Subtype locale display name exceptions.
@@ -166,47 +158,47 @@
<!-- Compatibility map from subtypeLocale:subtypeExtraValue to keyboardLayoutSet -->
<string-array name="locale_and_extra_value_to_keyboard_layout_set_map">
- <item>en_US:TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>en_US:TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>en_GB:TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>en_GB:TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>ar:SupportTouchPositionCorrection</item>
+ <item>ar:SupportTouchPositionCorrection,EmojiCapable</item>
<item>arabic</item>
- <item>cs:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>cs:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwertz</item>
- <item>da:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>da:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>nordic</item>
- <item>de:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>de:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwertz</item>
- <item>es:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>es:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>spanish</item>
- <item>fi:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>fi:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>nordic</item>
- <item>fr:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>fr:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>azerty</item>
- <item>fr_CA:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>fr_CA:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>hr:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>hr:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwertz</item>
- <item>hu:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>hu:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwertz</item>
- <item>it:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>it:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>iw:SupportTouchPositionCorrection</item>
+ <item>iw:SupportTouchPositionCorrection,EmojiCapable</item>
<item>hebrew</item>
- <item>nb:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>nb:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>nordic</item>
- <item>nl:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>nl:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>pl:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>pl:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
- <item>ru:SupportTouchPositionCorrection</item>
+ <item>ru:SupportTouchPositionCorrection,EmojiCapable</item>
<item>east_slavic</item>
- <item>sr:SupportTouchPositionCorrection</item>
+ <item>sr:SupportTouchPositionCorrection,EmojiCapable</item>
<item>south_slavic</item>
- <item>sv:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>sv:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>nordic</item>
- <item>tr:AsciiCapable,SupportTouchPositionCorrection</item>
+ <item>tr:AsciiCapable,SupportTouchPositionCorrection,EmojiCapable</item>
<item>qwerty</item>
</string-array>
diff --git a/java/res/values/emoji-categories.xml b/java/res/values/emoji-categories.xml
new file mode 100644
index 000000000..ce82a8b40
--- /dev/null
+++ b/java/res/values/emoji-categories.xml
@@ -0,0 +1,127 @@
+<?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.
+*/
+-->
+
+<!-- Note: This emoji code point list is valid prior to JB-MR2 (API < 18).
+ There is another emoji code point list for JB-MR2 and KLP and later under
+ res/xml/values-v1[89].-->
+<resources>
+ <!-- Dummy codeArrays for recents emoji keyboard.
+ Do not remove these keys, because they are used as a template. -->
+ <array
+ name="emoji_recents"
+ format="string"
+ >
+ <!-- These code point should be aligned with {@link RecentsKeyboard#TEMPLATE_KEY_CODE_*. -->
+ <item>30</item>
+ <item>31</item>
+ </array>
+ <array
+ name="emoji_nature"
+ format="string"
+ >
+ <item>2744</item> <!-- SNOWFLAKE -->
+ </array>
+ <array
+ name="emoji_symbols"
+ format="string"
+ >
+ <item>2460</item> <!-- CIRCLED DIGIT ONE -->
+ <item>2461</item> <!-- CIRCLED DIGIT TWO -->
+ <item>2462</item> <!-- CIRCLED DIGIT THREE -->
+ <item>2463</item> <!-- CIRCLED DIGIT FOUR -->
+ <item>2464</item> <!-- CIRCLED DIGIT FIVE -->
+ <item>2465</item> <!-- CIRCLED DIGIT SIX -->
+ <item>2466</item> <!-- CIRCLED DIGIT SEVEN -->
+ <item>2467</item> <!-- CIRCLED DIGIT EIGHT -->
+ <item>2468</item> <!-- CIRCLED DIGIT NINE -->
+ <item>2469</item> <!-- CIRCLED DIGIT TEN -->
+ <item>00ae</item> <!-- REGISTERED SIGN -->
+ <item>00a9</item> <!-- COPYRIGHT SIGN -->
+ <item>2122</item> <!-- TRADE MARK SIGN -->
+ <item>2734</item> <!-- EIGHT POINTED BLACK STAR -->
+ <item>2733</item> <!-- EIGHT POINTED PINWHEEL STAR -->
+ <item>2716</item> <!-- HEAVY MULTIPLICATION MARK -->
+ <item>2195</item> <!-- UP DOWN ARROW -->
+ <item>2197</item> <!-- NORTH EAST ARROW -->
+ <item>27a1</item> <!-- BLACK RIGHTWARDS ARROW -->
+ <item>2198</item> <!-- SOUTH EAST ARROW -->
+ <item>2199</item> <!-- SOUTH WEST ARROW -->
+ <item>2196</item> <!-- NORTH EAST ARROW -->
+ <item>2194</item> <!-- LEFT RIGHT ARROW -->
+ <item>25c0</item> <!-- BLACK LEFT-POINTING TRIANGLE -->
+ <item>25b6</item> <!-- BLACK ROGHT-POINTING TRIANGLE -->
+ <item>2747</item> <!-- SPARKLE -->
+ <item>25aa</item> <!-- BLACK SMALL SQUARE -->
+ <item>203c</item> <!-- DOUBLE EXCLAMATION MARK -->
+ <item>2660</item> <!-- BLACK SPADE SUIT -->
+ <item>2665</item> <!-- BLACK HEART SUIT -->
+ <item>2663</item> <!-- BLACK CLUB SUIT -->
+ <item>2666</item> <!-- BLACK DIAMOND SUIT -->
+ <item>21a9</item> <!-- LEFTWARDS ARROW WITH HOOK -->
+ <item>21aa</item> <!-- RIGHTWARDS ARROW WITH HOOK -->
+ </array>
+ <array
+ name="emoji_faces"
+ format="string"
+ >
+ <item>270C</item> <!-- VICTORY HAND -->
+ <item>2764</item> <!-- HEAVY BLACK HEART -->
+ </array>
+ <array
+ name="emoji_objects"
+ format="string"
+ >
+ <item>260e</item> <!-- BLACK TELEPHONE -->
+ <item>2709</item> <!-- ENVELOPE -->
+ <item>2712</item> <!-- BLACK NIB -->
+ <item>270f</item> <!-- PENCIL -->
+ <item>2702</item> <!-- BLACK SCISSORS -->
+ <item>2669</item> <!-- QUARTER NOTE -->
+ <item>266a</item> <!-- EIGHTH NOTE -->
+ <item>266c</item> <!-- BEAMED SIXTEENTH NOTES -->
+ </array>
+ <array
+ name="emoji_places"
+ format="string"
+ >
+ <item>2708</item> <!-- AIRPLANE -->
+ <item>2668</item> <!-- HOT SPRINGS -->
+ </array>
+ <array
+ name="emoji_emoticons"
+ format="string"
+ >
+ <item>=-O</item>
+ <item>:-P</item>
+ <item>;-)</item>
+ <item>:-(</item>
+ <item>:-)</item>
+ <item>:-!</item>
+ <item>:-$</item>
+ <item>B-)</item>
+ <item>:O</item>
+ <item>:-*</item>
+ <item>:-D</item>
+ <item>:\'(</item>
+ <item>:-\\</item>
+ <item>O:-)</item>
+ <item>:-[</item>
+ </array>
+</resources>
diff --git a/java/res/values/keyboard-icons-black.xml b/java/res/values/keyboard-icons-black.xml
deleted file mode 100644
index c1b1b6573..000000000
--- a/java/res/values/keyboard-icons-black.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardIcons.Black">
- <!-- Keyboard icons -->
- <!-- TODO: The following holo icon for phone (drawable-hdpi and drawable-xhdpi) are too
- ambiguous.
- sym_bkeyboard_voice_off
- -->
- <item name="iconShiftKey">@drawable/sym_bkeyboard_shift</item>
- <item name="iconDeleteKey">@drawable/sym_bkeyboard_delete</item>
- <item name="iconSettingsKey">@drawable/sym_bkeyboard_settings</item>
- <item name="iconSpaceKey">@drawable/sym_bkeyboard_space</item>
- <item name="iconEnterKey">@drawable/sym_bkeyboard_return</item>
- <item name="iconSearchKey">@drawable/sym_bkeyboard_search</item>
- <item name="iconTabKey">@drawable/sym_bkeyboard_tab</item>
- <item name="iconShortcutKey">@drawable/sym_bkeyboard_mic</item>
- <item name="iconShortcutForLabel">@drawable/sym_bkeyboard_label_mic</item>
- <item name="iconSpaceKeyForNumberLayout">@drawable/sym_bkeyboard_space</item>
- <item name="iconShiftKeyShifted">@drawable/sym_bkeyboard_shift_locked</item>
- <item name="iconShortcutKeyDisabled">@drawable/sym_bkeyboard_voice_off</item>
- <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
- <!-- TODO: Needs dedicated black theme globe icon -->
- <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item>
- <!-- TODO: Needs dedicated black theme ZWNJ and ZWJ icons -->
- <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo</item>
- <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo</item>
- <item name="iconEmojiKey">@drawable/ic_emoji_light</item>
- </style>
-</resources>
diff --git a/java/res/values/keyboard-icons-ics.xml b/java/res/values/keyboard-icons-ics.xml
deleted file mode 100644
index 5ada27ae8..000000000
--- a/java/res/values/keyboard-icons-ics.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardIcons.IceCreamSandwich">
- <!-- Keyboard icons -->
- <!-- TODO: The following holo icon for phone (drawable-hdpi and drawable-xhdpi) are missing.
- sym_keyboard_123_mic_holo
- -->
- <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo</item>
- <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo</item>
- <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo</item>
- <item name="iconSpaceKey">@null</item>
- <item name="iconEnterKey">@drawable/sym_keyboard_return_holo</item>
- <item name="iconSearchKey">@drawable/sym_keyboard_search_holo</item>
- <item name="iconTabKey">@drawable/sym_keyboard_tab_holo</item>
- <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo</item>
- <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo</item>
- <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo</item>
- <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo</item>
- <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo</item>
- <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
- <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item>
- <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo</item>
- <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo</item>
- <item name="iconEmojiKey">@drawable/ic_emoji_light</item>
- </style>
-</resources>
diff --git a/java/res/values/keyboard-icons-white.xml b/java/res/values/keyboard-icons-white.xml
deleted file mode 100644
index 7c6de42fa..000000000
--- a/java/res/values/keyboard-icons-white.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardIcons">
- <!-- Keyboard icons -->
- <item name="iconShiftKey">@drawable/sym_keyboard_shift</item>
- <item name="iconDeleteKey">@drawable/sym_keyboard_delete</item>
- <item name="iconSettingsKey">@drawable/sym_keyboard_settings</item>
- <item name="iconSpaceKey">@drawable/sym_keyboard_space</item>
- <item name="iconEnterKey">@drawable/sym_keyboard_return</item>ZZ
- <item name="iconSearchKey">@drawable/sym_keyboard_search</item>
- <item name="iconTabKey">@drawable/sym_keyboard_tab</item>
- <item name="iconShortcutKey">@drawable/sym_keyboard_mic</item>
- <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic</item>
- <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item>
- <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked</item>
- <!-- TODO: Needs non-holo disabled shortcut icon drawable -->
- <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo</item>
- <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
- <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch</item>
- <!-- TODO: Needs dedicated black theme ZWNJ and ZWJ icons -->
- <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo</item>
- <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo</item>
- <item name="iconEmojiKey">@drawable/ic_emoji_dark</item>
- </style>
-</resources>
diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml
index 53448c3e1..ee0ac003c 100644
--- a/java/res/values/keypress-vibration-durations.xml
+++ b/java/res/values/keypress-vibration-durations.xml
@@ -55,8 +55,8 @@
<item>MODEL=HTL22:MANUFACTURER=HTC,15</item>
<!-- Motorola Razor M -->
<item>MODEL=XT907:MANUFACTURER=motorola,30</item>
- <!-- Sony Xperia Z -->
- <item>MODEL=C6603:MANUFACTURER=Sony,35</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>
diff --git a/java/res/values/setup-styles.xml b/java/res/values/setup-styles.xml
index 1ffe8ca46..c968b2fc6 100644
--- a/java/res/values/setup-styles.xml
+++ b/java/res/values/setup-styles.xml
@@ -1,17 +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.
+<!--
+/*
+**
+** 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">
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index aae5b0b70..69da1e862 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -371,6 +371,8 @@
<!-- 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>
+ <!-- Description for Nepali (Traditional) keyboard subtype [CHAR LIMIT=25] -->
+ <string name="subtype_nepali_traditional"><xliff:g id="language">%s</xliff:g> (Traditional)</string>
<!-- TODO: Uncomment once we can handle IETF language tag with script name specified.
Description for Serbian Cyrillic keyboard subtype [CHAR LIMIT=25]
<string name="subtype_serbian_cyrillic">Serbian (Cyrillic)</string>
@@ -457,6 +459,8 @@ language among those that use the Latin alphabet. This keyboard is laid out in t
disposition that offers additional keys, but smaller keys compared to other common dispositions for
mobile devices. [CHAR LIMIT=25] -->
<string name="subtype_no_language_pcqwerty">Alphabet (PC)</string>
+ <!-- Description for Emoji keyboard subtype [CHAR LIMIT=25] -->
+ <string name="subtype_emoji">Emoji</string>
<!-- Title of the preference settings for custom input styles (language and keyboard layout pairs) [CHAR LIMIT=35]-->
<string name="custom_input_styles_title">Custom input styles</string>
@@ -493,6 +497,8 @@ mobile devices. [CHAR LIMIT=25] -->
<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] -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
deleted file mode 100644
index 37c6a9553..000000000
--- a/java/res/values/styles.xml
+++ /dev/null
@@ -1,415 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Theme "Basic" -->
- <style name="Keyboard">
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">0</item>
- <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="keyboardTopPadding">@fraction/keyboard_top_padding</item>
- <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding</item>
- <item name="keyboardLeftPadding">@fraction/keyboard_left_padding</item>
- <item name="keyboardRightPadding">@fraction/keyboard_right_padding</item>
- <item name="horizontalGap">@fraction/key_horizontal_gap</item>
- <item name="verticalGap">@fraction/key_bottom_gap</item>
- <item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item>
- </style>
- <style name="KeyboardView">
- <item name="android:background">@drawable/keyboard_background</item>
- <item name="keyBackground">@drawable/btn_keyboard_key</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="keyTypeface">normal</item>
- <item name="keyTextColor">@color/key_text_color_default</item>
- <item name="keyTextInactivatedColor">@color/key_text_color_default</item>
- <item name="keyHintLetterColor">@color/key_hint_letter_color_default</item>
- <item name="keyHintLabelColor">@color/key_hint_label_color_default</item>
- <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_default</item>
- <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_default</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="keyPreviewTextColor">@color/key_text_color_default</item>
- <item name="keyPreviewTextRatio">@fraction/key_preview_text_ratio</item>
- <item name="verticalCorrection">@dimen/keyboard_vertical_correction</item>
- <item name="keyTextShadowColor">@color/key_text_shadow_color_default</item>
- <item name="keyTextShadowRadius">2.75</item>
- <item name="backgroundDimAlpha">128</item>
- <item name="gestureFloatingPreviewTextSize">@dimen/gesture_floating_preview_text_size</item>
- <item name="gestureFloatingPreviewTextColor">@color/highlight_color_default</item>
- <item name="gestureFloatingPreviewTextOffset">@dimen/gesture_floating_preview_text_offset</item>
- <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_default</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="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="gestureTrailColor">@color/highlight_color_default</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>
- <!-- 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="slidingKeyInputPreviewColor">@color/highlight_translucent_color_default</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>
- <item name="keyRepeatStartTimeout">@integer/config_key_repeat_start_timeout</item>
- <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="keyPreviewLayout">@layout/key_preview</item>
- <item name="keyPreviewOffset">@dimen/key_preview_offset</item>
- <item name="keyPreviewHeight">@dimen/key_preview_height</item>
- <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="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.
- <item name="altCodeKeyWhileTypingFadeoutAnimator">@anim/alt_code_key_while_typing_fadeout</item>
- <item name="altCodeKeyWhileTypingFadeinAnimator">@anim/alt_code_key_while_typing_fadein</item>
- -->
- <!-- Common attributes of MainKeyboardView for gesture typing detection and recognition -->
- <item name="gestureFloatingPreviewTextLingerTimeout">@integer/config_gesture_floating_preview_text_linger_timeout</item>
- <item name="gestureStaticTimeThresholdAfterFastTyping">@integer/config_gesture_static_time_threshold_after_fast_typing</item>
- <item name="gestureDetectFastMoveSpeedThreshold">@fraction/config_gesture_detect_fast_move_speed_threshold</item>
- <item name="gestureDynamicThresholdDecayDuration">@integer/config_gesture_dynamic_threshold_decay_duration</item>
- <item name="gestureDynamicTimeThresholdFrom">@integer/config_gesture_dynamic_time_threshold_from</item>
- <item name="gestureDynamicTimeThresholdTo">@integer/config_gesture_dynamic_time_threshold_to</item>
- <item name="gestureDynamicDistanceThresholdFrom">@fraction/config_gesture_dynamic_distance_threshold_from</item>
- <item name="gestureDynamicDistanceThresholdTo">@fraction/config_gesture_dynamic_distance_threshold_to</item>
- <item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
- <item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
- <item name="gestureRecognitionUpdateTime">@integer/config_gesture_recognition_update_time</item>
- <item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
- <item name="suppressKeyPreviewAfterBatchInputDuration">@integer/config_suppress_key_preview_after_batch_input_duration</item>
- </style>
- <style
- name="MainKeyboardView"
- parent="KeyboardView">
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
- </style>
- <style
- name="MoreKeysKeyboard"
- parent="Keyboard"
- >
- <item name="keyboardTopPadding">0%p</item>
- <item name="keyboardBottomPadding">0%p</item>
- <item name="horizontalGap">0%p</item>
- <item name="touchPositionCorrectionData">@null</item>
- </style>
- <style
- name="MoreKeysKeyboardView"
- parent="KeyboardView"
- >
- <item name="keyBackground">@drawable/btn_keyboard_key_popup</item>
- <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction</item>
- </style>
- <style name="MoreKeysKeyboardPanelStyle">
- <item name="android:background">@drawable/keyboard_popup_panel_background</item>
- </style>
- <style
- name="SuggestionStripViewStyle"
- >
- <item name="android:background">@drawable/keyboard_suggest_strip</item>
- <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
- <item name="colorValidTypedWord">@color/highlight_color_default</item>
- <item name="colorTypedWord">@color/typed_word_color_default</item>
- <item name="colorAutoCorrect">@color/highlight_color_default</item>
- <item name="colorSuggested">@color/highlight_color_default</item>
- <item name="alphaObsoleted">50%</item>
- <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>
- </style>
- <style
- name="MoreSuggestionsViewStyle"
- parent="MoreKeysKeyboardView"
- >
- </style>
- <style name="SuggestionBackgroundStyle">
- <item name="android:background">@drawable/btn_suggestion</item>
- </style>
- <!-- Theme "Basic high contrast" -->
- <style
- name="Keyboard.HighContrast"
- parent="Keyboard"
- >
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">1</item>
- </style>
- <style
- name="KeyboardView.HighContrast"
- parent="KeyboardView"
- >
- <item name="android:background">@android:color/black</item>
- <item name="keyBackground">@drawable/btn_keyboard_key3</item>
- </style>
- <style
- name="MainKeyboardView.HighContrast"
- parent="KeyboardView.HighContrast"
- >
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
- </style>
- <!-- Theme "Stone" -->
- <style
- name="Keyboard.Stone"
- parent="Keyboard"
- >
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">6</item>
- <item name="keyboardTopPadding">@fraction/keyboard_top_padding_stone</item>
- <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_stone</item>
- <item name="horizontalGap">@fraction/key_horizontal_gap_stone</item>
- <item name="verticalGap">@fraction/key_bottom_gap_stone</item>
- </style>
- <style
- name="KeyboardView.Stone"
- parent="KeyboardView"
- >
- <item name="keyBackground">@drawable/btn_keyboard_key_stone</item>
- <item name="keyTextColor">@color/key_text_color_stone</item>
- <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_stone</item>
- <item name="keyHintLetterColor">@color/key_hint_letter_color_stone</item>
- <item name="keyHintLabelColor">@color/key_hint_label_color_stone</item>
- <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_stone</item>
- <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_stone</item>
- <item name="keyTextShadowColor">@color/key_text_shadow_color_stone</item>
- </style>
- <style
- name="MainKeyboardView.Stone"
- parent="KeyboardView.Stone"
- >
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_stone</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_stone</item>
- </style>
- <style
- name="MoreKeysKeyboard.Stone"
- parent="Keyboard.Stone"
- >
- <item name="keyboardTopPadding">0%p</item>
- <item name="keyboardBottomPadding">0%p</item>
- <item name="horizontalGap">0%p</item>
- <item name="touchPositionCorrectionData">@null</item>
- </style>
- <style
- name="MoreKeysKeyboardView.Stone"
- parent="MoreKeysKeyboardView"
- >
- <item name="keyBackground">@drawable/btn_keyboard_key_stone</item>
- <item name="keyTextColor">@color/key_text_color_stone</item>
- <item name="keyTextShadowColor">@color/key_text_shadow_color_stone</item>
- </style>
- <!-- Theme "Stone bold" -->
- <style
- name="Keyboard.Stone.Bold"
- parent="Keyboard.Stone"
- >
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">7</item>
- </style>
- <style
- name="KeyboardView.Stone.Bold"
- parent="KeyboardView.Stone"
- >
- <item name="keyTypeface">bold</item>
- </style>
- <style
- name="MainKeyboardView.Stone.Bold"
- parent="KeyboardView.Stone.Bold"
- >
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_stone</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_stone</item>
- </style>
- <!-- Theme "Gingerbread" -->
- <style
- name="Keyboard.Gingerbread"
- parent="Keyboard"
- >
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">8</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_gingerbread</item>
- <item name="horizontalGap">@fraction/key_horizontal_gap_gb</item>
- <item name="verticalGap">@fraction/key_bottom_gap_gb</item>
- </style>
- <style
- name="KeyboardView.Gingerbread"
- parent="KeyboardView"
- >
- <item name="android:background">@drawable/keyboard_dark_background</item>
- <item name="keyBackground">@drawable/btn_keyboard_key_gingerbread</item>
- <item name="keyTypeface">bold</item>
- </style>
- <style
- name="MainKeyboardView.Gingerbread"
- parent="KeyboardView.Gingerbread"
- >
- <item name="autoCorrectionSpacebarLedEnabled">true</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_default</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_default</item>
- </style>
- <style
- name="MoreKeysKeyboard.Gingerbread"
- parent="Keyboard.Gingerbread"
- >
- <item name="keyboardTopPadding">0%p</item>
- <item name="keyboardBottomPadding">0%p</item>
- <item name="horizontalGap">0%p</item>
- <item name="touchPositionCorrectionData">@null</item>
- </style>
- <style
- name="MoreKeysKeyboardView.Gingerbread"
- parent="MoreKeysKeyboardView"
- >
- <item name="android:background">@null</item>
- </style>
- <!-- Theme "IceCreamSandwich" -->
- <style
- name="Keyboard.IceCreamSandwich"
- parent="Keyboard"
- >
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">5</item>
- <item name="keyboardTopPadding">@fraction/keyboard_top_padding_ics</item>
- <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_ics</item>
- <item name="horizontalGap">@fraction/key_horizontal_gap_ics</item>
- <item name="verticalGap">@fraction/key_bottom_gap_ics</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_ice_cream_sandwich</item>
- </style>
- <style
- name="KeyboardView.IceCreamSandwich"
- parent="KeyboardView"
- >
- <item name="android:background">@drawable/keyboard_background_holo</item>
- <item name="keyBackground">@drawable/btn_keyboard_key_ics</item>
- <item name="keyTypeface">bold</item>
- <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_ics</item>
- <item name="keyHintLetterColor">@color/key_hint_letter_color_ics</item>
- <item name="keyHintLabelColor">@color/key_hint_label_color_ics</item>
- <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_ics</item>
- <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_ics</item>
- <item name="keyPreviewLayout">@layout/key_preview_ics</item>
- <item name="keyPreviewTextColor">@color/key_text_color_ics</item>
- <item name="keyPreviewOffset">@dimen/key_preview_offset_ics</item>
- <item name="keyTextShadowColor">@color/key_text_shadow_color_ics</item>
- <item name="keyTextShadowRadius">0.0</item>
- <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_ics</item>
- <item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item>
- <item name="gestureTrailColor">@color/highlight_color_ics</item>
- </style>
- <style
- name="MainKeyboardView.IceCreamSandwich"
- parent="KeyboardView.IceCreamSandwich"
- >
- <item name="autoCorrectionSpacebarLedEnabled">false</item>
- <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
- <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item>
- <item name="spacebarTextColor">@color/spacebar_text_color_ics</item>
- <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_ics</item>
- </style>
- <style
- name="MoreKeysKeyboard.IceCreamSandwich"
- parent="Keyboard.IceCreamSandwich"
- >
- <item name="keyboardTopPadding">0%p</item>
- <item name="keyboardBottomPadding">0%p</item>
- <item name="horizontalGap">0%p</item>
- <item name="touchPositionCorrectionData">@null</item>
- </style>
- <style
- name="MoreKeysKeyboardView.IceCreamSandwich"
- parent="MoreKeysKeyboardView"
- >
- <item name="android:background">@null</item>
- <item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item>
- <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction_ics</item>
- </style>
- <style name="MoreKeysKeyboardPanelStyle.IceCreamSandwich">
- <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item>
- </style>
- <style
- name="SuggestionStripViewStyle.IceCreamSandwich"
- >
- <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
- <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
- <item name="colorValidTypedWord">@color/highlight_color_ics</item>
- <item name="colorTypedWord">@color/highlight_color_ics</item>
- <item name="colorAutoCorrect">@color/highlight_color_ics</item>
- <item name="colorSuggested">@color/highlight_color_ics</item>
- <item name="alphaValidTypedWord">85%</item>
- <item name="alphaTypedWord">85%</item>
- <item name="alphaSuggested">70%</item>
- <item name="alphaObsoleted">70%</item>
- <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>
- </style>
- <style
- name="MoreSuggestionsViewStyle.IceCreamSandwich"
- parent="MoreKeysKeyboardView.IceCreamSandwich"
- >
- </style>
- <style name="SuggestionBackgroundStyle.IceCreamSandwich">
- <item name="android:background">@drawable/btn_suggestion_ics</item>
- </style>
- <style
- name="SuggestionPreviewBackgroundStyle.IceCreamSandwich"
- parent="MoreKeysKeyboardPanelStyle.IceCreamSandwich"
- >
- </style>
- <style name="MoreKeysKeyboardAnimation">
- <item name="android:windowEnterAnimation">@anim/more_keys_keyboard_fadein</item>
- <item name="android:windowExitAnimation">@anim/more_keys_keyboard_fadeout</item>
- </style>
-</resources>
diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml
deleted file mode 100644
index e81d47386..000000000
--- a/java/res/values/themes-basic-highcontrast.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardTheme.HighContrast" parent="KeyboardIcons">
- <item name="keyboardStyle">@style/Keyboard.HighContrast</item>
- <item name="keyboardViewStyle">@style/KeyboardView.HighContrast</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView.HighContrast</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- </style>
-</resources>
diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml
deleted file mode 100644
index c44f0f614..000000000
--- a/java/res/values/themes-basic.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardTheme" parent="KeyboardIcons">
- <item name="keyboardStyle">@style/Keyboard</item>
- <item name="keyboardViewStyle">@style/KeyboardView</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- </style>
-</resources>
diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml
new file mode 100644
index 000000000..8e9cfc90b
--- /dev/null
+++ b/java/res/values/themes-common.xml
@@ -0,0 +1,131 @@
+<?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">
+ <style name="KeyboardIcons" />
+ <!-- Default theme values -->
+ <style name="Keyboard">
+ <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="maxMoreKeysColumn">@integer/config_max_more_keys_column</item>
+ </style>
+ <style name="KeyboardView">
+ <item name="keyBackground">@drawable/btn_keyboard_key_ics</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="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="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="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>
+ <!-- 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="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>
+ <item name="keyRepeatStartTimeout">@integer/config_key_repeat_start_timeout</item>
+ <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="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="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.
+ <item name="altCodeKeyWhileTypingFadeoutAnimator">@anim/alt_code_key_while_typing_fadeout</item>
+ <item name="altCodeKeyWhileTypingFadeinAnimator">@anim/alt_code_key_while_typing_fadein</item>
+ -->
+ <!-- Common attributes of MainKeyboardView for gesture typing detection and recognition -->
+ <item name="gestureFloatingPreviewTextLingerTimeout">@integer/config_gesture_floating_preview_text_linger_timeout</item>
+ <item name="gestureStaticTimeThresholdAfterFastTyping">@integer/config_gesture_static_time_threshold_after_fast_typing</item>
+ <item name="gestureDetectFastMoveSpeedThreshold">@fraction/config_gesture_detect_fast_move_speed_threshold</item>
+ <item name="gestureDynamicThresholdDecayDuration">@integer/config_gesture_dynamic_threshold_decay_duration</item>
+ <item name="gestureDynamicTimeThresholdFrom">@integer/config_gesture_dynamic_time_threshold_from</item>
+ <item name="gestureDynamicTimeThresholdTo">@integer/config_gesture_dynamic_time_threshold_to</item>
+ <item name="gestureDynamicDistanceThresholdFrom">@fraction/config_gesture_dynamic_distance_threshold_from</item>
+ <item name="gestureDynamicDistanceThresholdTo">@fraction/config_gesture_dynamic_distance_threshold_to</item>
+ <item name="gestureSamplingMinimumDistance">@fraction/config_gesture_sampling_minimum_distance</item>
+ <item name="gestureRecognitionMinimumTime">@integer/config_gesture_recognition_minimum_time</item>
+ <item name="gestureRecognitionUpdateTime">@integer/config_gesture_recognition_update_time</item>
+ <item name="gestureRecognitionSpeedThreshold">@fraction/config_gesture_recognition_speed_threshold</item>
+ <item name="suppressKeyPreviewAfterBatchInputDuration">@integer/config_suppress_key_preview_after_batch_input_duration</item>
+ </style>
+ <style
+ name="MainKeyboardView"
+ parent="KeyboardView" />
+ <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+ for instance delete button, need themed {@link KeyboardView} attributes. -->
+ <style
+ name="EmojiKeyboardView"
+ parent="KeyboardView"
+ >
+ <item name="emojiTabLabelColor">@color/emoji_tab_label_color_ics</item>
+ </style>
+ <style name="MoreKeysKeyboard" />
+ <style
+ name="MoreKeysKeyboardView"
+ 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>
+ </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
diff --git a/java/res/values/themes-gb.xml b/java/res/values/themes-gb.xml
new file mode 100644
index 000000000..d9ac4acb2
--- /dev/null
+++ b/java/res/values/themes-gb.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <style name="KeyboardTheme.GB" parent="KeyboardIcons.GB">
+ <item name="keyboardStyle">@style/Keyboard.GB</item>
+ <item name="keyboardViewStyle">@style/KeyboardView.GB</item>
+ <item name="mainKeyboardViewStyle">@style/MainKeyboardView.GB</item>
+ <item name="emojiKeyboardViewStyle">@style/EmojiKeyboardView.GB</item>
+ <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.GB</item>
+ <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.GB</item>
+ <item name="moreKeysKeyboardContainerStyle">@style/MoreKeysKeyboardContainer.GB</item>
+ <item name="suggestionStripViewStyle">@style/SuggestionStripView.GB</item>
+ <item name="suggestionWordStyle">@style/SuggestionWord.GB</item>
+ </style>
+ <style name="KeyboardIcons.GB">
+ <!-- Keyboard icons -->
+ <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item>
+ <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item>
+ <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item>
+ <item name="iconSpaceKey">@drawable/sym_keyboard_space_holo_dark</item>
+ <item name="iconEnterKey">@drawable/sym_keyboard_return_holo_dark</item>
+ <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item>
+ <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item>
+ <item name="iconShortcutKey">@drawable/sym_keyboard_mic_holo_dark</item>
+ <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo_dark</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item>
+ <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item>
+ <!-- TODO: Needs non-holo disabled shortcut icon drawable -->
+ <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo_dark</item>
+ <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
+ <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_dark</item>
+ <!-- TODO: Needs dedicated black theme ZWNJ and ZWJ icons -->
+ <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo_dark</item>
+ <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item>
+ <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_holo_dark</item>
+ </style>
+ <style
+ name="Keyboard.GB"
+ parent="Keyboard"
+ >
+ <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
+ <item name="themeId">1</item>
+ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_gb</item>
+ <item name="keyboardTopPadding">@fraction/keyboard_top_padding_gb</item>
+ <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_gb</item>
+ <item name="horizontalGap">@fraction/key_horizontal_gap_gb</item>
+ <item name="verticalGap">@fraction/key_bottom_gap_gb</item>
+ </style>
+ <style
+ name="KeyboardView.GB"
+ parent="KeyboardView"
+ >
+ <item name="android:background">@drawable/keyboard_background_gb</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_gb</item>
+ <item name="keyTypeface">bold</item>
+ <item name="keyTextColor">@color/key_text_color_gb</item>
+ <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_gb</item>
+ <item name="keyHintLetterColor">@color/key_hint_letter_color_gb</item>
+ <item name="keyHintLabelColor">@color/key_hint_label_color_gb</item>
+ <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_gb</item>
+ <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_gb</item>
+ <item name="keyPreviewTextColor">@color/key_text_color_gb</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_gb</item>
+ <item name="keyTextShadowRadius">2.75</item>
+ </style>
+ <style
+ name="MainKeyboardView.GB"
+ parent="KeyboardView.GB"
+ >
+ <item name="keyPreviewLayout">@layout/key_preview_gb</item>
+ <item name="keyPreviewOffset">@dimen/key_preview_offset_gb</item>
+ <item name="gestureFloatingPreviewTextColor">@color/highlight_color_gb</item>
+ <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_gb</item>
+ <item name="gestureTrailColor">@color/highlight_color_gb</item>
+ <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_gb</item>
+ <item name="autoCorrectionSpacebarLedEnabled">true</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_gb</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_gb</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_gb</item>
+ </style>
+ <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+ for instance delete button, need themed {@link KeyboardView} attributes. -->
+ <style
+ name="EmojiKeyboardView.GB"
+ parent="KeyboardView.GB"
+ >
+ <item name="keyBackground">@drawable/btn_keyboard_key_functional_gb</item>
+ <item name="emojiTabLabelColor">@color/emoji_tab_label_color_gb</item>
+ </style>
+ <style
+ name="MoreKeysKeyboard.GB"
+ parent="Keyboard.GB"
+ >
+ <item name="keyboardTopPadding">0%p</item>
+ <item name="keyboardBottomPadding">0%p</item>
+ <item name="horizontalGap">0%p</item>
+ <item name="touchPositionCorrectionData">@null</item>
+ </style>
+ <style
+ name="MoreKeysKeyboardView.GB"
+ parent="KeyboardView.GB"
+ >
+ <item name="android:background">@null</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_popup_gb</item>
+ <item name="keyTypeface">normal</item>
+ <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction_gb</item>
+ </style>
+ <style
+ name="MoreKeysKeyboardContainer.GB"
+ >
+ <item name="android:background">@drawable/keyboard_popup_panel_background_gb</item>
+ </style>
+ <style
+ name="SuggestionStripView.GB"
+ parent="SuggestionStripView"
+ >
+ <item name="android:background">@drawable/keyboard_suggest_strip_gb</item>
+ <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
+ <item name="colorValidTypedWord">@color/highlight_color_gb</item>
+ <item name="colorTypedWord">@color/typed_word_color_gb</item>
+ <item name="colorAutoCorrect">@color/highlight_color_gb</item>
+ <item name="colorSuggested">@color/highlight_color_gb</item>
+ <item name="alphaObsoleted">50%</item>
+ </style>
+ <style name="SuggestionWord.GB">
+ <item name="android:background">@drawable/btn_suggestion_gb</item>
+ </style>
+</resources>
diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml
deleted file mode 100644
index 129afdf5b..000000000
--- a/java/res/values/themes-gingerbread.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardTheme.Gingerbread" parent="KeyboardIcons">
- <item name="keyboardStyle">@style/Keyboard.Gingerbread</item>
- <item name="keyboardViewStyle">@style/KeyboardView.Gingerbread</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView.Gingerbread</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Gingerbread</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Gingerbread</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- </style>
-</resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 1264831f3..33dd50c2c 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -1,29 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
-->
-<resources>
- <style name="KeyboardTheme.IceCreamSandwich" parent="KeyboardIcons.IceCreamSandwich">
- <item name="keyboardStyle">@style/Keyboard.IceCreamSandwich</item>
- <item name="keyboardViewStyle">@style/KeyboardView.IceCreamSandwich</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView.IceCreamSandwich</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.IceCreamSandwich</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.IceCreamSandwich</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle.IceCreamSandwich</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle.IceCreamSandwich</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle.IceCreamSandwich</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle.IceCreamSandwich</item>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="KeyboardTheme.ICS" parent="KeyboardIcons.ICS">
+ <item name="keyboardStyle">@style/Keyboard.ICS</item>
+ <item name="keyboardViewStyle">@style/KeyboardView.ICS</item>
+ <item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item>
+ <item name="emojiKeyboardViewStyle">@style/EmojiKeyboardView.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>
+ <style name="KeyboardIcons.ICS">
+ <!-- Keyboard icons -->
+ <!-- TODO: The following holo icon for phone (drawable-hdpi and drawable-xhdpi) are missing.
+ sym_keyboard_123_mic_holo
+ -->
+ <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item>
+ <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item>
+ <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item>
+ <item name="iconSpaceKey">@null</item>
+ <item name="iconEnterKey">@drawable/sym_keyboard_return_holo_dark</item>
+ <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item>
+ <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item>
+ <item name="iconShortcutKey">@drawable/sym_keyboard_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>
+ <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
+ <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_dark</item>
+ <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo_dark</item>
+ <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item>
+ <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_holo_dark</item>
+ </style>
+ <style
+ name="Keyboard.ICS"
+ parent="Keyboard"
+ >
+ <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
+ <item name="themeId">0</item>
+ <item name="keyboardTopPadding">@fraction/keyboard_top_padding_ics</item>
+ <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_ics</item>
+ <item name="horizontalGap">@fraction/key_horizontal_gap_ics</item>
+ <item name="verticalGap">@fraction/key_bottom_gap_ics</item>
+ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_ics</item>
+ </style>
+ <style
+ name="KeyboardView.ICS"
+ parent="KeyboardView"
+ >
+ <item name="android:background">@drawable/keyboard_background_holo</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_ics</item>
+ <item name="keyTypeface">bold</item>
+ <item name="keyTextColor">@color/key_text_color_ics</item>
+ <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_ics</item>
+ <item name="keyHintLetterColor">@color/key_hint_letter_color_ics</item>
+ <item name="keyHintLabelColor">@color/key_hint_label_color_ics</item>
+ <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_ics</item>
+ <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_ics</item>
+ <item name="keyPreviewTextColor">@color/key_text_color_ics</item>
+ <item name="keyTextShadowColor">@color/key_text_shadow_color_ics</item>
+ <item name="keyTextShadowRadius">0.0</item>
+ </style>
+ <style
+ name="MainKeyboardView.ICS"
+ parent="KeyboardView.ICS"
+ >
+ <item name="keyPreviewLayout">@layout/key_preview_ics</item>
+ <item name="keyPreviewOffset">@dimen/key_preview_offset_ics</item>
+ <item name="gestureFloatingPreviewTextColor">@color/highlight_color_holo</item>
+ <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_ics</item>
+ <item name="gestureTrailColor">@color/highlight_color_holo</item>
+ <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_holo</item>
+ <item name="autoCorrectionSpacebarLedEnabled">false</item>
+ <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
+ <item name="spacebarTextColor">@color/spacebar_text_color_ics</item>
+ <item name="spacebarTextShadowColor">@color/spacebar_text_shadow_color_ics</item>
+ </style>
+ <!-- Though {@link EmojiKeyboardView} doesn't extend {@link KeyboardView}, some views inside it,
+ for instance delete button, need themed {@link KeyboardView} attributes. -->
+ <style
+ name="EmojiKeyboardView.ICS"
+ parent="KeyboardView.ICS"
+ >
+ <item name="keyBackgroundEmojiFunctional">@drawable/btn_keyboard_key_functional_ics</item>
+ <item name="emojiTabLabelColor">@color/emoji_tab_label_color_ics</item>
+ </style>
+ <style
+ name="MoreKeysKeyboard.ICS"
+ parent="Keyboard.ICS"
+ >
+ <item name="keyboardTopPadding">0%p</item>
+ <item name="keyboardBottomPadding">0%p</item>
+ <item name="horizontalGap">0%p</item>
+ <item name="touchPositionCorrectionData">@null</item>
+ </style>
+ <style
+ name="MoreKeysKeyboardView.ICS"
+ parent="KeyboardView.ICS"
+ >
+ <item name="android:background">@null</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_ics</item>
+ </style>
+ <style
+ name="MoreKeysKeyboardContainer.ICS"
+ >
+ <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item>
+ </style>
+ <style
+ name="SuggestionStripView.ICS"
+ parent="SuggestionStripView"
+ >
+ <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
+ <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item>
+ <item name="colorValidTypedWord">@color/typed_word_color_holo</item>
+ <item name="colorTypedWord">@color/typed_word_color_holo</item>
+ <item name="colorAutoCorrect">@color/highlight_color_holo</item>
+ <item name="colorSuggested">@color/suggested_word_color_holo</item>
+ <item name="alphaObsoleted">70%</item>
+ </style>
+ <style name="SuggestionWord.ICS">
+ <item name="android:background">@drawable/btn_suggestion_ics</item>
</style>
</resources>
diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml
deleted file mode 100644
index 196f3ef9f..000000000
--- a/java/res/values/themes-stone-bold.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardTheme.Stone.Bold" parent="KeyboardIcons.Black">
- <item name="keyboardStyle">@style/Keyboard.Stone.Bold</item>
- <item name="keyboardViewStyle">@style/KeyboardView.Stone.Bold</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView.Stone.Bold</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- </style>
-</resources>
diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml
deleted file mode 100644
index d0d35c28d..000000000
--- a/java/res/values/themes-stone.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources>
- <style name="KeyboardTheme.Stone" parent="KeyboardIcons.Black">
- <item name="keyboardStyle">@style/Keyboard.Stone</item>
- <item name="keyboardViewStyle">@style/KeyboardView.Stone</item>
- <item name="mainKeyboardViewStyle">@style/MainKeyboardView.Stone</item>
- <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item>
- <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item>
- <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
- <item name="suggestionStripViewStyle">@style/SuggestionStripViewStyle</item>
- <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
- <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
- </style>
-</resources>
diff --git a/java/res/values/touch-position-correction.xml b/java/res/values/touch-position-correction.xml
index 7df86f467..9df517b32 100644
--- a/java/res/values/touch-position-correction.xml
+++ b/java/res/values/touch-position-correction.xml
@@ -37,7 +37,7 @@
</string-array>
<string-array
- name="touch_position_correction_data_gingerbread"
+ name="touch_position_correction_data_gb"
translatable="false"
>
<!-- First row -->
@@ -57,7 +57,7 @@
</string-array>
<string-array
- name="touch_position_correction_data_ice_cream_sandwich"
+ name="touch_position_correction_data_ics"
translatable="false"
>
<!-- First row -->
diff --git a/java/res/xml-sw600dp/key_apostrophe.xml b/java/res/xml-sw600dp/key_apostrophe.xml
deleted file mode 100644
index 2aec34729..000000000
--- a/java/res/xml-sw600dp/key_apostrophe.xml
+++ /dev/null
@@ -1,49 +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:mode="email|url"
- >
- <Key
- latin:keyLabel="-" />
- </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:keyStyle="hasShiftedLetterHintStyle" />
- </case>
- <default>
- <Key
- latin:keyLabel="!text/keylabel_for_apostrophe"
- latin:keyHintLabel="!text/keyhintlabel_for_apostrophe"
- latin:moreKeys="!text/more_keys_for_apostrophe"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </default>
- </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_dash.xml b/java/res/xml-sw600dp/key_dash.xml
deleted file mode 100644
index b139c29c8..000000000
--- a/java/res/xml-sw600dp/key_dash.xml
+++ /dev/null
@@ -1,49 +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:mode="email|url"
- >
- <Key
- latin:keyLabel="_" />
- </case>
- <case
- latin:languageCode="ar|fa"
- >
- <Key
- latin:keyLabel="."
- latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics"
- latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!text/more_keys_for_arabic_diacritics"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </case>
- <default>
- <Key
- latin:keyLabel="-"
- latin:keyHintLabel="_"
- latin:moreKeys="_"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </default>
- </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_f1.xml b/java/res/xml-sw600dp/key_f1.xml
index 77afe4e64..ac0053236 100644
--- a/java/res/xml-sw600dp/key_f1.xml
+++ b/java/res/xml-sw600dp/key_f1.xml
@@ -53,10 +53,7 @@
</case>
<default>
<Key
- latin:keyLabel="/"
- latin:keyHintLabel="\@"
- latin:moreKeys="\@"
- latin:keyStyle="hasShiftedLetterHintStyle" />
+ latin:keyLabel="/" />
</default>
</switch>
</merge>
diff --git a/java/res/xml-sw600dp/key_f2.xml b/java/res/xml-sw600dp/key_f2.xml
deleted file mode 100644
index ca3b30b54..000000000
--- a/java/res/xml-sw600dp/key_f2.xml
+++ /dev/null
@@ -1,45 +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:mode="email|url"
- >
- <Key
- latin:keyStyle="comKeyStyle" />
- </case>
- <case
- latin:imeAction="actionSearch"
- >
- <Key
- latin:keyLabel=":"
- latin:keyHintLabel="+"
- latin:moreKeys="+"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </case>
- <default>
- <Key
- latin:keyStyle="smileyKeyStyle" />
- </default>
- </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_space.xml b/java/res/xml-sw600dp/key_space_5kw.xml
index 86af89f50..86af89f50 100644
--- a/java/res/xml-sw600dp/key_space.xml
+++ b/java/res/xml-sw600dp/key_space_5kw.xml
diff --git a/java/res/xml/kbd_thai_symbols.xml b/java/res/xml-sw600dp/key_space_symbols.xml
index 4d9861b73..07aa7d179 100644
--- a/java/res/xml/kbd_thai_symbols.xml
+++ b/java/res/xml-sw600dp/key_space_symbols.xml
@@ -18,10 +18,9 @@
*/
-->
-<Keyboard
+<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_symbols" />
-</Keyboard>
+ 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 f407ba346..d817add11 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -123,7 +123,8 @@
latin:styleName="emojiKeyStyle"
latin:code="!code/key_emoji"
latin:keyIcon="!icon/emoji_key"
- latin:keyActionFlags="noKeyPreview" />
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="functional" />
<key-style
latin:styleName="settingsKeyStyle"
latin:code="!code/key_settings"
diff --git a/java/res/xml-sw600dp/keys_comma_period.xml b/java/res/xml-sw600dp/keys_comma_period.xml
deleted file mode 100644
index 752f75b5f..000000000
--- a/java/res/xml-sw600dp/keys_comma_period.xml
+++ /dev/null
@@ -1,46 +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:mode="email"
- >
- <Key
- latin:keyLabel="," />
- <Key
- latin:keyLabel="." />
- </case>
- <default>
- <Key
- latin:keyLabel="!text/keylabel_for_tablet_comma"
- latin:keyHintLabel="!text/keyhintlabel_for_tablet_comma"
- latin:moreKeys="!text/more_keys_for_tablet_comma"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="."
- latin:keyHintLabel="!text/keyhintlabel_for_tablet_period"
- latin:moreKeys="!text/more_keys_for_tablet_period"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </default>
- </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/keys_exclamation_question.xml b/java/res/xml-sw600dp/keys_exclamation_question.xml
new file mode 100644
index 000000000..983ef3897
--- /dev/null
+++ b/java/res/xml-sw600dp/keys_exclamation_question.xml
@@ -0,0 +1,28 @@
+<?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:keyLabel="\?" />
+ <Key
+ latin:keyLabel="!" />
+</merge>
diff --git a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
index 0a27ca70c..324e025ed 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty2_right3.xml
@@ -23,36 +23,32 @@
>
<switch>
<case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
latin:keyLabel="["
- latin:moreKeys="{" />
- <Key
- latin:keyLabel="]"
- latin:moreKeys="}" />
- <!-- U+00A6: "¦" BROKEN BAR -->
- <Key
- latin:keyLabel="\\"
- latin:moreKeys="\\|,&#x00A6;" />
- </case>
- <default>
- <Key
- latin:keyLabel="["
latin:keyHintLabel="{"
- latin:moreKeys="{"
+ latin:additionalMoreKeys="{"
latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
latin:keyLabel="]"
latin:keyHintLabel="}"
- latin:moreKeys="}"
+ latin:additionalMoreKeys="}"
latin:keyStyle="hasShiftedLetterHintStyle" />
- <!-- U+00A6: "¦" BROKEN BAR -->
<Key
latin:keyLabel="\\"
latin:keyHintLabel="|"
- latin:moreKeys="\\|,&#x00A6;"
+ latin:additionalMoreKeys="\\|"
latin:keyStyle="hasShiftedLetterHintStyle" />
+ </case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
+ <default>
+ <Key
+ latin:keyLabel="{" />
+ <Key
+ latin:keyLabel="}" />
+ <Key
+ latin:keyLabel="|" />
</default>
</switch>
-</merge>
+</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 0e3013afe..254b5e571 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty3_right2.xml
@@ -23,26 +23,27 @@
>
<switch>
<case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
<Key
latin:keyLabel=";"
- latin:moreKeys=":" />
+ latin:keyHintLabel=":"
+ latin:additionalMoreKeys=":"
+ latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
latin:keyLabel="\'"
- latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" />
+ latin:keyHintLabel="&quot;"
+ latin:additionalMoreKeys="&quot;"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,%,!text/single_quotes" />
</case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<Key
- latin:keyLabel=";"
- latin:keyHintLabel=":"
- latin:moreKeys=":"
- latin:keyStyle="hasShiftedLetterHintStyle" />
+ latin:keyLabel=":" />
<Key
- latin:keyLabel="\'"
- latin:keyHintLabel="&quot;"
- latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,&quot;,!text/single_quotes"
- latin:keyStyle="hasShiftedLetterHintStyle" />
+ latin:keyLabel="&quot;"
+ latin:moreKeys="!fixedColumnOrder!3,!text/double_quotes,!text/single_quotes" />
</default>
</switch>
</merge>
diff --git a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
index ee5271abe..774ff8d05 100644
--- a/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
+++ b/java/res/xml-sw600dp/keys_pcqwerty4_right3.xml
@@ -23,28 +23,26 @@
>
<switch>
<case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
>
- <!-- 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 -->
- <Key
+ <Key
latin:keyLabel=","
+ latin:keyHintLabel="&lt;"
latin:additionalMoreKeys="&lt;"
- latin:moreKeys="!fixedColumnOrder!4,&#x2039;,&#x2064;,&#x00AB;" />
+ latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
latin:keyLabel="."
+ latin:keyHintLabel="&gt;"
latin:additionalMoreKeys="&gt;"
- latin:moreKeys="!fixedColumnOrder!4,&#x203A;,&#x2065;,&#x00BB;" />
- <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
+ latin:keyStyle="hasShiftedLetterHintStyle" />
<Key
latin:keyLabel="/"
+ latin:keyHintLabel="\?"
latin:additionalMoreKeys="\?"
- latin:moreKeys="&#x00BF;" />
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_question" />
</case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<!-- U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
@@ -53,24 +51,14 @@
U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
<Key
- latin:keyLabel=","
- latin:keyHintLabel="&lt;"
- latin:additionalMoreKeys="&lt;"
- latin:moreKeys="!fixedColumnOrder!4,&#x2039;,&#x2264;,&#x00AB;"
- latin:keyStyle="hasShiftedLetterHintStyle" />
+ latin:keyLabel="&lt;"
+ latin:moreKeys="!fixedColumnOrder!3,&#x2039;,&#x2264;,&#x00AB;" />
<Key
- latin:keyLabel="."
- latin:keyHintLabel="&gt;"
- latin:additionalMoreKeys="&gt;"
- latin:moreKeys="!fixedColumnOrder!4,&#x203A;,&#x2265;,&#x00BB;"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
+ latin:keyLabel="&gt;"
+ latin:moreKeys="!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;" />
<Key
- latin:keyLabel="/"
- latin:keyHintLabel="\?"
- latin:additionalMoreKeys="\?"
- latin:moreKeys="&#x00BF;"
- latin:keyStyle="hasShiftedLetterHintStyle" />
+ latin:keyLabel="\?"
+ latin:moreKeys="!text/more_keys_for_symbols_question" />
</default>
</switch>
</merge>
diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml
index 969cc145e..11b403452 100644
--- a/java/res/xml-sw600dp/row_dvorak4.xml
+++ b/java/res/xml-sw600dp/row_dvorak4.xml
@@ -34,12 +34,15 @@
latin:keyboardLayout="@xml/key_f1" />
<include
latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space"
+ latin:keyboardLayout="@xml/key_space_5kw"
latin:backgroundType="normal" />
<include
latin:keyboardLayout="@xml/key_question_exclamation" />
- <include
- latin:keyboardLayout="@xml/key_dash" />
+ <Key
+ latin:keyLabel="-"
+ latin:keyHintLabel="_"
+ latin:moreKeys="_"
+ latin:keyStyle="hasShiftedLetterHintStyle" />
<include
latin:keyboardLayout="@xml/key_f2" />
</Row>
diff --git a/java/res/xml-sw600dp/row_hebrew4.xml b/java/res/xml-sw600dp/row_hebrew4.xml
deleted file mode 100644
index f429f97fb..000000000
--- a/java/res/xml-sw600dp/row_hebrew4.xml
+++ /dev/null
@@ -1,44 +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"
->
- <Row
- latin:keyWidth="9.0%p"
- latin:backgroundType="functional"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyWidth="10.0%p" />
- <include
- latin:keyboardLayout="@xml/key_shortcut" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <include
- latin:keyboardLayout="@xml/key_f2" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw600dp/row_pcqwerty5.xml b/java/res/xml-sw600dp/row_pcqwerty5.xml
index 3c4a46660..b854f1051 100644
--- a/java/res/xml-sw600dp/row_pcqwerty5.xml
+++ b/java/res/xml-sw600dp/row_pcqwerty5.xml
@@ -38,9 +38,23 @@
latin:keyStyle="spaceKeyStyle"
latin:keyXPos="25.5%p"
latin:keyWidth="49.0%p" />
- <include
- latin:keyXPos="-9.0%p"
- latin:keyWidth="fillRight"
- latin:keyboardLayout="@xml/key_shortcut" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+ >
+ <include
+ latin:keyXPos="-9.0%p"
+ latin:keyWidth="9.0%p"
+ latin:keyboardLayout="@xml/key_shortcut" />
+ </case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
+ <default>
+ <include
+ latin:keyXPos="-9.0%p"
+ latin:keyWidth="9.0%p"
+ latin:backgroundType="functional"
+ latin:keyboardLayout="@xml/key_f2" />
+ </default>
+ </switch>
</Row>
</merge>
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index fa433635e..7969dd8a5 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -34,12 +34,10 @@
latin:keyboardLayout="@xml/key_f1" />
<include
latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space"
+ latin:keyboardLayout="@xml/key_space_5kw"
latin:backgroundType="normal" />
<include
- latin:keyboardLayout="@xml/key_apostrophe" />
- <include
- latin:keyboardLayout="@xml/key_dash" />
+ latin:keyboardLayout="@xml/keys_comma_period" />
<include
latin:keyboardLayout="@xml/key_f2" />
</Row>
diff --git a/java/res/xml-sw600dp/row_symbols4.xml b/java/res/xml-sw600dp/row_symbols4.xml
deleted file mode 100644
index f138d8ef4..000000000
--- a/java/res/xml-sw600dp/row_symbols4.xml
+++ /dev/null
@@ -1,48 +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"
->
- <Row
- latin:keyWidth="9.0%p"
- latin:backgroundType="functional"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="10.0%p" />
- <Key
- latin:keyLabel="/" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <Key
- latin:keyLabel="&quot;"
- latin:moreKeys="!text/more_keys_for_tablet_double_quote" />
- <Key
- latin:keyLabel="_" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw600dp/row_symbols_shift4.xml b/java/res/xml-sw600dp/row_symbols_shift4.xml
deleted file mode 100644
index 29befa92a..000000000
--- a/java/res/xml-sw600dp/row_symbols_shift4.xml
+++ /dev/null
@@ -1,40 +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"
->
- <Row
- latin:keyWidth="9.0%p"
- latin:backgroundType="functional"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="10.0%p" />
- <!-- Here is empty space. -->
- <include
- latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
index b11bbba1b..254d3fdba 100644
--- a/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
+++ b/java/res/xml-sw600dp/rowkeys_pcqwerty1.xml
@@ -21,93 +21,87 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <include
- latin:keyboardLayout="@xml/keys_pcqwerty_symbols1" />
- </case>
- <!-- keyboardLayoutSetElement="alphabet*" -->
- <default>
- <!-- U+00AC: "¬" NOT SIGN -->
- <Key
- latin:keyLabel="`"
- latin:keyHintLabel="~"
- latin:additionalMoreKeys="~"
- latin:moreKeys="&#x00AC;"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <!-- U+00A1: "¡" NVERTED EXCLAMATION MARK -->
- <Key
- latin:keyLabel="1"
- latin:keyHintLabel="!"
- latin:additionalMoreKeys="!"
- latin:moreKeys="&#x00A1;,!text/more_keys_for_symbols_1"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="2"
- latin:keyHintLabel="\@"
- latin:additionalMoreKeys="\@"
- latin:moreKeys="!text/more_keys_for_symbols_2"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="3"
- latin:keyHintLabel="\#"
- latin:additionalMoreKeys="\#"
- latin:moreKeys="!text/more_keys_for_symbols_3"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="4"
- latin:keyHintLabel="$"
- latin:additionalMoreKeys="$"
- latin:moreKeys="!text/more_keys_for_symbols_4"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="5"
- latin:keyHintLabel="%"
- latin:additionalMoreKeys="\\%"
- latin:moreKeys="!text/more_keys_for_symbols_5"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="6"
- latin:keyHintLabel="^"
- latin:additionalMoreKeys="^"
- latin:moreKeys="!text/more_keys_for_symbols_6"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="7"
- latin:keyHintLabel="&amp;"
- latin:additionalMoreKeys="&amp;"
- latin:moreKeys="!text/more_keys_for_symbols_7"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="8"
- latin:keyHintLabel="*"
- latin:additionalMoreKeys="*"
- latin:moreKeys="!text/more_keys_for_symbols_8"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="9"
- latin:keyHintLabel="("
- latin:additionalMoreKeys="("
- latin:moreKeys="!text/more_keys_for_symbols_9"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="0"
- latin:keyHintLabel=")"
- latin:additionalMoreKeys=")"
- latin:moreKeys="!text/more_keys_for_symbols_0"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="-"
- latin:keyHintLabel="_"
- latin:moreKeys="_"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <Key
- latin:keyLabel="="
- latin:keyHintLabel="+"
- latin:moreKeys="+"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </default>
- </switch>
+ <Key
+ latin:keyLabel="`"
+ latin:keyHintLabel="~"
+ latin:additionalMoreKeys="~"
+ latin:keyStyle="hasShiftedLetterHintStyle" />
+ <Key
+ latin:keyLabel="1"
+ latin:keyHintLabel="!"
+ latin:additionalMoreKeys="!"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_exclamation,!text/more_keys_for_symbols_1" />
+ <Key
+ latin:keyLabel="2"
+ latin:keyHintLabel="\@"
+ latin:additionalMoreKeys="\@"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_2" />
+ <Key
+ latin:keyLabel="3"
+ latin:keyHintLabel="\#"
+ latin:additionalMoreKeys="\#"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_3" />
+ <Key
+ latin:keyLabel="4"
+ latin:keyHintLabel="$"
+ latin:additionalMoreKeys="$"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_4" />
+ <Key
+ latin:keyLabel="5"
+ latin:keyHintLabel="%"
+ latin:additionalMoreKeys="\\%"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_5" />
+ <Key
+ latin:keyLabel="6"
+ latin:keyHintLabel="^"
+ latin:additionalMoreKeys="^"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_6" />
+ <Key
+ latin:keyLabel="7"
+ latin:keyHintLabel="&amp;"
+ latin:additionalMoreKeys="&amp;"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_7" />
+ <Key
+ latin:keyLabel="8"
+ latin:keyHintLabel="*"
+ latin:additionalMoreKeys="*"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_8" />
+ <Key
+ latin:keyLabel="9"
+ latin:keyHintLabel="("
+ latin:additionalMoreKeys="("
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_9" />
+ <Key
+ latin:keyLabel="0"
+ latin:keyHintLabel=")"
+ latin:additionalMoreKeys=")"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="!text/more_keys_for_symbols_0" />
+ <!-- U+2013: "–" EN DASH
+ U+2014: "—" EM DASH
+ U+00B7: "·" MIDDLE DOT -->
+ <Key
+ latin:keyLabel="-"
+ latin:keyHintLabel="_"
+ latin:additionalMoreKeys="_"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
+ <!-- U+221E: "∞" INFINITY
+ U+2260: "≠" NOT EQUAL TO
+ U+2248: "≈" ALMOST EQUAL TO -->
+ <Key
+ latin:keyLabel="="
+ latin:keyHintLabel="+"
+ latin:additionalMoreKeys="+"
+ latin:keyStyle="hasShiftedLetterHintStyle"
+ latin:moreKeys="&#x221E;,&#x2260;,&#x2248;" />
</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols2.xml b/java/res/xml-sw600dp/rowkeys_symbols2.xml
deleted file mode 100644
index 14abb42f9..000000000
--- a/java/res/xml-sw600dp/rowkeys_symbols2.xml
+++ /dev/null
@@ -1,75 +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="fa"
- >
- <!-- U+066C: "٬" ARABIC THOUSANDS SEPARATOR -->
- <Key
- latin:keyLabel="&#x066C;"
- latin:keyHintLabel="&amp;"
- latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
- latin:moreKeys="&amp;" />
- </case>
- <default>
- <Key
- latin:keyLabel="\#" />
- </default>
- </switch>
- <Key
- latin:keyStyle="currencyKeyStyle" />
- <Key
- latin:keyLabel="!text/keylabel_for_symbols_percent"
- latin:moreKeys="!text/more_keys_for_symbols_percent" />
- <switch>
- <case
- latin:languageCode="fa"
- >
- <!-- U+066B: "٫" ARABIC DECIMAL SEPARATOR -->
- <Key
- latin:keyLabel="&#x066B;"
- latin:keyHintLabel="\#"
- latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
- latin:moreKeys="\#" />
- </case>
- <default>
- <Key
- latin:keyLabel="&amp;" />
- </default>
- </switch>
- <Key
- latin:keyLabel="*"
- latin:moreKeys="!text/more_keys_for_star" />
- <!-- U+2013: "–" EN DASH
- U+2014: "—" EM DASH
- U+00B7: "·" MIDDLE DOT -->
- <Key
- latin:keyLabel="-"
- latin:moreKeys="_,&#x2013;,&#x2014;,&#x00B7;" />
- <Key
- latin:keyLabel="+"
- latin:moreKeys="!text/more_keys_for_plus" />
- <include
- latin:keyboardLayout="@xml/keys_parentheses" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols3.xml b/java/res/xml-sw600dp/rowkeys_symbols3.xml
deleted file mode 100644
index 30fba3812..000000000
--- a/java/res/xml-sw600dp/rowkeys_symbols3.xml
+++ /dev/null
@@ -1,57 +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"
->
- <include
- latin:keyboardLayout="@xml/keys_less_greater" />
- <!-- U+2260: "≠" NOT EQUAL TO
- U+2248: "≈" ALMOST EQUAL TO -->
- <Key
- latin:keyLabel="="
- latin:moreKeys="&#x2260;,&#x2248;" />
- <switch>
- <case
- latin:mode="url"
- >
- <Key
- latin:keyLabel="\'" />
- </case>
- <default>
- <Key
- latin:keyLabel=":" />
- </default>
- </switch>
- <Key
- latin:keyLabel="!text/keylabel_for_symbols_semicolon"
- latin:moreKeys="!text/more_keys_for_symbols_semicolon" />
- <Key
- latin:keyLabel="!text/keylabel_for_comma"
- latin:moreKeys="!text/more_keys_for_comma" />
- <Key
- latin:keyLabel="." />
- <Key
- latin:keyLabel="!"
- latin:moreKeys="!text/more_keys_for_symbols_exclamation" />
- <Key
- latin:keyLabel="!text/keylabel_for_symbols_question"
- latin:moreKeys="!text/more_keys_for_symbols_question" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml b/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml
deleted file mode 100644
index 3549fdda4..000000000
--- a/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml
+++ /dev/null
@@ -1,56 +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"
->
- <Key
- latin:keyLabel="~" />
- <Key
- latin:keyLabel="`" />
- <Key
- latin:keyLabel="|" />
- <!-- U+2022: "•" BULLET -->
- <Key
- latin:keyLabel="&#x2022;"
- latin:moreKeys="!text/more_keys_for_bullet" />
- <!-- U+221A: "√" SQUARE ROOT -->
- <Key
- latin:keyLabel="&#x221A;" />
- <!-- U+03C0: "π" GREEK SMALL LETTER PI
- U+03A0: "Π" GREEK CAPITAL LETTER PI -->
- <Key
- latin:keyLabel="&#x03C0;"
- latin:moreKeys="&#x03A0;" />
- <!-- U+00F7: "÷" DIVISION SIGN -->
- <Key
- latin:keyLabel="&#x00F7;" />
- <!-- U+00D7: "×" MULTIPLICATION SIGN -->
- <Key
- latin:keyLabel="&#x00D7;" />
- <!-- U+00A7: "§" SECTION SIGN
- U+00B6: "¶" PILCROW SIGN -->
- <Key
- latin:keyLabel="&#x00A7;"
- latin:moreKeys="&#x00B6;" />
- <!-- U+0394: "Δ" GREEK CAPITAL LETTER DELTA -->
- <Key
- latin:keyLabel="&#x0394;" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols_shift2.xml b/java/res/xml-sw600dp/rowkeys_symbols_shift2.xml
deleted file mode 100644
index 2048b7335..000000000
--- a/java/res/xml-sw600dp/rowkeys_symbols_shift2.xml
+++ /dev/null
@@ -1,52 +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"
->
- <Key
- latin:keyStyle="moreCurrency1KeyStyle" />
- <Key
- latin:keyStyle="moreCurrency2KeyStyle" />
- <Key
- latin:keyStyle="moreCurrency3KeyStyle" />
- <Key
- latin:keyStyle="moreCurrency4KeyStyle" />
- <!-- U+2191: "↑" UPWARDS ARROW
- U+2193: "↓" DOWNWARDS ARROW
- U+2190: "←" LEFTWARDS ARROW
- U+2192: "→" RIGHTWARDS ARROW -->
- <Key
- latin:keyLabel="^"
- latin:moreKeys="&#x2191;,&#x2193;,&#x2190;,&#x2192;" />
- <!-- U+00B0: "°" DEGREE SIGN
- U+2032: "′" PRIME
- U+2033: "″" DOUBLE PRIME -->
- <Key
- latin:keyLabel="&#x00B0;"
- latin:moreKeys="&#x2032;,&#x2033;" />
- <!-- U+00B1: "±" PLUS-MINUS SIGN
- U+221E: "∞" INFINITY -->
- <Key
- latin:keyLabel="&#x00B1;"
- latin:moreKeys="&#x221E;" />
- <include
- latin:keyboardLayout="@xml/keys_curly_brackets" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols_shift3.xml b/java/res/xml-sw600dp/rowkeys_symbols_shift3.xml
deleted file mode 100644
index 8bd865639..000000000
--- a/java/res/xml-sw600dp/rowkeys_symbols_shift3.xml
+++ /dev/null
@@ -1,46 +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"
->
- <Key
- latin:keyLabel="\\" />
- <!-- U+00A9: "©" COPYRIGHT SIGN -->
- <Key
- latin:keyLabel="&#x00A9;" />
- <!-- U+00AE: "®" REGISTERED SIGN -->
- <Key
- latin:keyLabel="&#x00AE;" />
- <!-- U+2122: "™" TRADE MARK SIGN -->
- <Key
- latin:keyLabel="&#x2122;" />
- <!-- U+2105: "℅" CARE OF -->
- <Key
- latin:keyLabel="&#x2105;" />
- <include
- latin:keyboardLayout="@xml/keys_square_brackets" />
- <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK -->
- <Key
- latin:keyLabel="&#x00A1;" />
- <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
- <Key
- latin:keyLabel="&#x00BF;" />
-</merge>
diff --git a/java/res/xml-sw600dp/rows_10_10_7_symbols_shift.xml b/java/res/xml-sw600dp/rows_10_10_7_symbols_shift.xml
deleted file mode 100644
index 3d3b59f22..000000000
--- a/java/res/xml-sw600dp/rows_10_10_7_symbols_shift.xml
+++ /dev/null
@@ -1,60 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="9.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="9.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="9.0%p"
- >
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="10.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift3" />
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_colemak.xml b/java/res/xml-sw600dp/rows_armenian_phonetic.xml
index 073f812e5..9bc2a1821 100644
--- a/java/res/xml-sw768dp/rows_colemak.xml
+++ b/java/res/xml-sw600dp/rows_armenian_phonetic.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.
@@ -24,43 +24,43 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="8.282%p"
+ latin:keyWidth="9.0%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_colemak1" />
<include
- latin:keyboardLayout="@xml/key_colemak_colon" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic1" />
<Key
latin:keyStyle="deleteKeyStyle"
latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="9.0%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic2" />
+ <include
+ latin:keyboardLayout="@xml/key_armenian_xeh" />
</Row>
<Row
- latin:keyWidth="8.125%p"
+ latin:keyWidth="9.0%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_colemak2" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic3" />
+ <include
+ latin:keyboardLayout="@xml/key_armenian_sha" />
<Key
latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="8.047%p"
+ latin:keyWidth="8.8889%p"
>
<Key
latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
+ latin:keyWidth="10.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_colemak3" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic4" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_azerty.xml b/java/res/xml-sw600dp/rows_azerty.xml
index 5a5a7d12f..cdc91857f 100644
--- a/java/res/xml-sw600dp/rows_azerty.xml
+++ b/java/res/xml-sw600dp/rows_azerty.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_azerty3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_bulgarian.xml b/java/res/xml-sw600dp/rows_bulgarian.xml
index 263562095..c73aa1c1a 100644
--- a/java/res/xml-sw600dp/rows_bulgarian.xml
+++ b/java/res/xml-sw600dp/rows_bulgarian.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_bulgarian3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_bulgarian_bds.xml b/java/res/xml-sw600dp/rows_bulgarian_bds.xml
index 9439a6346..bc773ee58 100644
--- a/java/res/xml-sw600dp/rows_bulgarian_bds.xml
+++ b/java/res/xml-sw600dp/rows_bulgarian_bds.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_bulgarian_bds3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_colemak.xml b/java/res/xml-sw600dp/rows_colemak.xml
index 98a24e451..ab059da83 100644
--- a/java/res/xml-sw600dp/rows_colemak.xml
+++ b/java/res/xml-sw600dp/rows_colemak.xml
@@ -52,7 +52,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_colemak3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_east_slavic.xml b/java/res/xml-sw600dp/rows_east_slavic.xml
index b4160d64b..c5045fffc 100644
--- a/java/res/xml-sw600dp/rows_east_slavic.xml
+++ b/java/res/xml-sw600dp/rows_east_slavic.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_east_slavic3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_georgian.xml b/java/res/xml-sw600dp/rows_georgian.xml
index b0e9e35fd..891cbc109 100644
--- a/java/res/xml-sw600dp/rows_georgian.xml
+++ b/java/res/xml-sw600dp/rows_georgian.xml
@@ -51,7 +51,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_georgian3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_greek.xml b/java/res/xml-sw600dp/rows_greek.xml
index de214c67f..066dc47fb 100644
--- a/java/res/xml-sw600dp/rows_greek.xml
+++ b/java/res/xml-sw600dp/rows_greek.xml
@@ -53,7 +53,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_greek3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_hebrew.xml b/java/res/xml-sw600dp/rows_hebrew.xml
index 9945dee35..852e17683 100644
--- a/java/res/xml-sw600dp/rows_hebrew.xml
+++ b/java/res/xml-sw600dp/rows_hebrew.xml
@@ -49,5 +49,5 @@
latin:keyXPos="10.0%p" />
</Row>
<include
- latin:keyboardLayout="@xml/row_hebrew4" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml-sw600dp/rows_hindi.xml b/java/res/xml-sw600dp/rows_hindi.xml
index 2a9a419f8..ca581be14 100644
--- a/java/res/xml-sw600dp/rows_hindi.xml
+++ b/java/res/xml-sw600dp/rows_hindi.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_hindi3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw768dp/rows_azerty.xml b/java/res/xml-sw600dp/rows_khmer.xml
index cf4bc92fa..2824a5c2f 100644
--- a/java/res/xml-sw768dp/rows_azerty.xml
+++ b/java/res/xml-sw600dp/rows_khmer.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.
@@ -24,44 +24,48 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="8.282%p"
+ latin:keyWidth="7.5%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_azerty1" />
+ latin:keyboardLayout="@xml/rowkeys_khmer1" />
<Key
latin:keyStyle="deleteKeyStyle"
latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_khmer2" />
</Row>
<Row
- latin:keyWidth="8.125%p"
+ latin:keyWidth="7.5%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_azerty2" />
+ latin:keyboardLayout="@xml/rowkeys_khmer3" />
<Key
latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="8.047%p"
+ latin:keyWidth="7.5%p"
>
<Key
latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
+ latin:keyWidth="10.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_azerty3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_khmer4" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <Spacer />
+ </case>
+ <default>
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
+ </default>
+ </switch>
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw768dp/rows_georgian.xml b/java/res/xml-sw600dp/rows_lao.xml
index 3f8bd4569..446d9bd5a 100644
--- a/java/res/xml-sw768dp/rows_georgian.xml
+++ b/java/res/xml-sw600dp/rows_lao.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -24,44 +24,48 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="8.282%p"
+ latin:keyWidth="7.5%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_georgian1" />
+ latin:keyboardLayout="@xml/rowkeys_lao1" />
<Key
latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao2" />
</Row>
<Row
- latin:keyWidth="8.125%p"
+ latin:keyWidth="7.5%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
<include
- latin:keyboardLayout="@xml/rowkeys_georgian2" />
+ latin:keyboardLayout="@xml/rowkeys_lao3" />
<Key
latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="8.047%p"
+ latin:keyWidth="7.5%p"
>
<Key
latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_georgian3" />
+ latin:keyWidth="10.0%p" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_lao4" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <Spacer />
+ </case>
+ <default>
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
+ </default>
+ </switch>
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_mongolian.xml b/java/res/xml-sw600dp/rows_mongolian.xml
index dc0c1fe5c..8e39e625a 100644
--- a/java/res/xml-sw600dp/rows_mongolian.xml
+++ b/java/res/xml-sw600dp/rows_mongolian.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_mongolian3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_10_10_7_symbols.xml b/java/res/xml-sw600dp/rows_nepali_romanized.xml
index 0e4710c37..21d1dc6e0 100644
--- a/java/res/xml-sw600dp/rows_10_10_7_symbols.xml
+++ b/java/res/xml-sw600dp/rows_nepali_romanized.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -23,38 +23,35 @@
>
<include
latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
<Row
- latin:keyWidth="9.0%p"
+ latin:keyWidth="8.182%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_symbols1" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized1" />
<Key
latin:keyStyle="deleteKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="9.0%p"
+ latin:keyWidth="8.182%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_symbols2" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized2" />
<Key
latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="9.0%p"
+ latin:keyWidth="8.182%p"
>
<Key
- latin:keyStyle="toMoreSymbolKeyStyle"
+ latin:keyStyle="shiftKeyStyle"
latin:keyWidth="10.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_symbols3" />
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized3" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
- latin:keyboardLayout="@xml/row_symbols4" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml-sw768dp/rows_farsi.xml b/java/res/xml-sw600dp/rows_nepali_traditional.xml
index 8d3fb0579..90703da76 100644
--- a/java/res/xml-sw768dp/rows_farsi.xml
+++ b/java/res/xml-sw600dp/rows_nepali_traditional.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -24,38 +24,34 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="7.375%p"
+ latin:keyWidth="8.182%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_farsi1" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional1" />
<Key
latin:keyStyle="deleteKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="7.227%p"
+ latin:keyWidth="8.182%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_farsi2" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional2" />
<Key
latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="7.227%p"
+ latin:keyWidth="8.182%p"
>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_farsi3"
- latin:keyXPos="13.829%p" />
- </Row>
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_left6" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_right5" />
+ </Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml-sw600dp/rows_nordic.xml b/java/res/xml-sw600dp/rows_nordic.xml
index 299bf8908..56fa4066f 100644
--- a/java/res/xml-sw600dp/rows_nordic.xml
+++ b/java/res/xml-sw600dp/rows_nordic.xml
@@ -52,7 +52,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_qwerty3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyXPos="-10.0%p"
diff --git a/java/res/xml-sw600dp/rows_pcqwerty.xml b/java/res/xml-sw600dp/rows_pcqwerty.xml
index fa6080a19..8714815ef 100644
--- a/java/res/xml-sw600dp/rows_pcqwerty.xml
+++ b/java/res/xml-sw600dp/rows_pcqwerty.xml
@@ -26,8 +26,19 @@
<Row
latin:keyWidth="7.0%p"
>
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
+ </case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
+ </default>
+ </switch>
<Key
latin:keyStyle="deleteKeyStyle"
latin:keyWidth="fillRight" />
@@ -44,9 +55,7 @@
<Row
latin:keyWidth="7.0%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabel="!text/label_to_symbol_key_pcqwerty"
+ <Spacer
latin:keyWidth="12.0%p" />
<include
latin:keyboardLayout="@xml/rowkeys_pcqwerty3" />
diff --git a/java/res/xml-sw600dp/rows_qwerty.xml b/java/res/xml-sw600dp/rows_qwerty.xml
index 722f9d138..58ba1d713 100644
--- a/java/res/xml-sw600dp/rows_qwerty.xml
+++ b/java/res/xml-sw600dp/rows_qwerty.xml
@@ -51,7 +51,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_qwerty3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_qwertz.xml b/java/res/xml-sw600dp/rows_qwertz.xml
index f2f832ce7..3b59dec54 100644
--- a/java/res/xml-sw600dp/rows_qwertz.xml
+++ b/java/res/xml-sw600dp/rows_qwertz.xml
@@ -51,7 +51,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_qwertz3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_south_slavic.xml b/java/res/xml-sw600dp/rows_south_slavic.xml
index 6ef664342..5053988cc 100644
--- a/java/res/xml-sw600dp/rows_south_slavic.xml
+++ b/java/res/xml-sw600dp/rows_south_slavic.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_south_slavic3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_spanish.xml b/java/res/xml-sw600dp/rows_spanish.xml
index bca9bba3a..1092c268e 100644
--- a/java/res/xml-sw600dp/rows_spanish.xml
+++ b/java/res/xml-sw600dp/rows_spanish.xml
@@ -50,7 +50,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_qwerty3" />
<include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
<Key
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml
index 3d0593dab..fbd8492cd 100644
--- a/java/res/xml-sw600dp/rows_symbols.xml
+++ b/java/res/xml-sw600dp/rows_symbols.xml
@@ -50,12 +50,23 @@
<Key
latin:keyStyle="toMoreSymbolKeyStyle"
latin:keyWidth="10.0%p" />
+ <Key
+ latin:keyLabel="\\" />
+ <Key
+ latin:keyLabel="=" />
<include
latin:keyboardLayout="@xml/rowkeys_symbols3" />
<Key
latin:keyStyle="toMoreSymbolKeyStyle"
latin:keyWidth="fillRight" />
</Row>
- <include
- latin:keyboardLayout="@xml/row_symbols4" />
+ <Row
+ latin:keyWidth="9.0%p"
+ >
+ <Key
+ latin:keyStyle="toAlphaKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/row_symbols4" />
+ </Row>
</merge>
diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml
index 0050c0c15..aad047ff6 100644
--- a/java/res/xml-sw600dp/rows_symbols_shift.xml
+++ b/java/res/xml-sw600dp/rows_symbols_shift.xml
@@ -52,10 +52,23 @@
latin:keyWidth="10.0%p" />
<include
latin:keyboardLayout="@xml/rowkeys_symbols_shift3" />
+ <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK -->
+ <Key
+ latin:keyLabel="&#x00A1;" />
+ <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
+ <Key
+ latin:keyLabel="&#x00BF;" />
<Key
latin:keyStyle="backFromMoreSymbolKeyStyle"
latin:keyWidth="fillRight" />
</Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
+ <Row
+ latin:keyWidth="9.0%p"
+ >
+ <Key
+ latin:keyStyle="toAlphaKeyStyle"
+ latin:keyWidth="10%p" />
+ <include
+ latin:keyboardLayout="@xml/row_symbols_shift4" />
+ </Row>
</merge>
diff --git a/java/res/xml-sw600dp/rows_thai.xml b/java/res/xml-sw600dp/rows_thai.xml
index bc89640ac..7738c7f04 100644
--- a/java/res/xml-sw600dp/rows_thai.xml
+++ b/java/res/xml-sw600dp/rows_thai.xml
@@ -59,8 +59,17 @@
latin:keyWidth="10.0%p" />
<include
latin:keyboardLayout="@xml/rowkeys_thai4" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <Spacer />
+ </case>
+ <default>
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
+ </default>
+ </switch>
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw768dp-land/kbd_phone_symbols.xml b/java/res/xml-sw768dp-land/kbd_phone_symbols.xml
deleted file mode 100644
index 6038b1f1e..000000000
--- a/java/res/xml-sw768dp-land/kbd_phone_symbols.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<Keyboard
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyboardLeftPadding="10%p"
- latin:keyboardRightPadding="10%p"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
- <!-- Tablet doesn't have phone symbols keyboard -->
- <include
- latin:keyboardLayout="@xml/rows_phone" />
-</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_number.xml b/java/res/xml-sw768dp/kbd_number.xml
deleted file mode 100644
index 1b46edd50..000000000
--- a/java/res/xml-sw768dp/kbd_number.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<Keyboard
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
- <include
- latin:keyboardLayout="@xml/rows_number" />
-</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_phone.xml b/java/res/xml-sw768dp/kbd_phone.xml
deleted file mode 100644
index 947ede050..000000000
--- a/java/res/xml-sw768dp/kbd_phone.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<Keyboard
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
- <include
- latin:keyboardLayout="@xml/rows_phone" />
-</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_phone_symbols.xml b/java/res/xml-sw768dp/kbd_phone_symbols.xml
deleted file mode 100644
index dd9a6aebd..000000000
--- a/java/res/xml-sw768dp/kbd_phone_symbols.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<Keyboard
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
- <!-- Tablet doesn't have phone symbols keyboard -->
- <include
- latin:keyboardLayout="@xml/rows_phone" />
-</Keyboard>
diff --git a/java/res/xml-sw768dp/key_space.xml b/java/res/xml-sw768dp/key_space.xml
deleted file mode 100644
index 58e71d807..000000000
--- a/java/res/xml-sw768dp/key_space.xml
+++ /dev/null
@@ -1,63 +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="fa"
- latin:languageSwitchKeyEnabled="true"
- >
- <Key
- latin:keyStyle="languageSwitchKeyStyle" />
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="24.141%p" />
- <Key
- latin:keyStyle="zwnjKeyStyle" />
- </case>
- <case
- latin:languageCode="fa"
- latin:languageSwitchKeyEnabled="false"
- >
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="32.188%p" />
- <Key
- latin:keyStyle="zwnjKeyStyle" />
- </case>
- <case
- latin:languageSwitchKeyEnabled="true"
- >
- <Key
- latin:keyStyle="languageSwitchKeyStyle" />
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="32.188%p" />
- </case>
- <!-- languageSwitchKeyEnabled="false" -->
- <default>
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="40.235%p" />
- </default>
- </switch>
-</merge>
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
deleted file mode 100644
index 7c0a82a71..000000000
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ /dev/null
@@ -1,186 +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.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <switch>
- <case
- latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
- >
- <key-style
- latin:styleName="hasShiftedLetterHintStyle"
- latin:keyLabelFlags="hasShiftedLetterHint|shiftedLetterActivated" />
- </case>
- <default>
- <key-style
- latin:styleName="hasShiftedLetterHintStyle"
- latin:keyLabelFlags="hasShiftedLetterHint" />
- </default>
- </switch>
- <!-- 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" />
- <switch>
- <case
- latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetAutomaticShifted"
- >
- <key-style
- latin:styleName="shiftKeyStyle"
- latin:keyIcon="!icon/shift_key_shifted"
- latin:backgroundType="stickyOff"
- latin:parentStyle="baseForShiftKeyStyle" />
- </case>
- <case
- latin:keyboardLayoutSetElement="alphabetShiftLocked|alphabetShiftLockShifted"
- >
- <key-style
- latin:styleName="shiftKeyStyle"
- latin:keyIcon="!icon/shift_key_shifted"
- latin:backgroundType="stickyOn"
- latin:parentStyle="baseForShiftKeyStyle" />
- </case>
- <default>
- <key-style
- latin:styleName="shiftKeyStyle"
- latin:keyIcon="!icon/shift_key"
- latin:backgroundType="stickyOff"
- latin:parentStyle="baseForShiftKeyStyle" />
- </default>
- </switch>
- <key-style
- latin:styleName="deleteKeyStyle"
- latin:code="!code/key_delete"
- latin:keyIcon="!icon/delete_key"
- latin:keyActionFlags="isRepeatable|noKeyPreview"
- latin:backgroundType="functional" />
- <include
- latin:keyboardLayout="@xml/key_styles_enter" />
- <key-style
- latin:styleName="spaceKeyStyle"
- latin:code="!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: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: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: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" />
- <key-style
- latin:styleName="settingsKeyStyle"
- latin:code="!code/key_settings"
- latin:keyIcon="!icon/settings_key"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
- <switch>
- <case
- latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
- latin:navigatePrevious="true"
- >
- <key-style
- latin:styleName="tabKeyStyle"
- latin:code="!code/key_action_previous"
- latin:keyLabel="!text/label_tab_key"
- latin:keyLabelFlags="fontNormal|preserveCase"
- latin:backgroundType="functional" />
- </case>
- <case
- latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted|alphabetShiftLocked"
- latin:navigateNext="true"
- >
- <key-style
- latin:styleName="tabKeyStyle"
- latin:code="!code/key_action_next"
- latin:keyLabel="!text/label_tab_key"
- latin:keyLabelFlags="fontNormal|preserveCase"
- latin:backgroundType="functional" />
- </case>
- <default>
- <key-style
- latin:styleName="tabKeyStyle"
- latin:code="!code/key_tab"
- latin:keyLabel="!text/label_tab_key"
- latin:keyLabelFlags="fontNormal|preserveCase"
- latin:backgroundType="functional" />
- </default>
- </switch>
- <key-style
- latin:styleName="baseForLayoutSwitchKeyStyle"
- latin:keyLabelFlags="fontNormal|preserveCase"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional" />
- <key-style
- latin:styleName="toSymbolKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
- latin:keyLabel="!text/label_to_symbol_key"
- latin:parentStyle="baseForLayoutSwitchKeyStyle" />
- <key-style
- latin:styleName="toAlphaKeyStyle"
- latin:code="!code/key_switch_alpha_symbol"
- latin:keyLabel="!text/label_to_alpha_key"
- latin:parentStyle="baseForLayoutSwitchKeyStyle" />
- <key-style
- latin:styleName="toMoreSymbolKeyStyle"
- latin:code="!code/key_shift"
- latin:keyLabel="!text/label_to_more_symbol_for_tablet_key"
- latin:parentStyle="baseForLayoutSwitchKeyStyle" />
- <key-style
- latin:styleName="backFromMoreSymbolKeyStyle"
- latin:code="!code/key_shift"
- latin:keyLabel="!text/label_to_symbol_key"
- latin:parentStyle="baseForLayoutSwitchKeyStyle" />
- <key-style
- latin:styleName="comKeyStyle"
- latin:keyLabel="!text/keylabel_for_popular_domain"
- latin:keyLabelFlags="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-sw768dp/row_dvorak4.xml b/java/res/xml-sw768dp/row_dvorak4.xml
deleted file mode 100644
index 8f9230d4a..000000000
--- a/java/res/xml-sw768dp/row_dvorak4.xml
+++ /dev/null
@@ -1,51 +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"
->
- <Row
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional"
- >
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="5.782%p" />
- <include
- latin:keyboardLayout="@xml/key_settings" />
- <include
- latin:keyboardLayout="@xml/key_shortcut" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="29.923%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/key_question_exclamation" />
- <include
- latin:keyboardLayout="@xml/key_dash" />
- <include
- latin:keyboardLayout="@xml/key_f2" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/row_hebrew4.xml b/java/res/xml-sw768dp/row_hebrew4.xml
deleted file mode 100644
index ae14f0296..000000000
--- a/java/res/xml-sw768dp/row_hebrew4.xml
+++ /dev/null
@@ -1,49 +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"
->
- <Row
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional"
- >
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="5.782%p" />
- <include
- latin:keyboardLayout="@xml/key_settings" />
- <include
- latin:keyboardLayout="@xml/key_shortcut" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="29.923%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <include
- latin:keyboardLayout="@xml/key_f2" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/row_pcqwerty5.xml b/java/res/xml-sw768dp/row_pcqwerty5.xml
deleted file mode 100644
index e27ec878b..000000000
--- a/java/res/xml-sw768dp/row_pcqwerty5.xml
+++ /dev/null
@@ -1,59 +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"
->
- <Row
- latin:keyWidth="8.047%p"
- >
- <include
- latin:keyboardLayout="@xml/key_settings" />
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <Spacer
- latin:keyXPos="15.0%p"
- latin:keyWidth="10.5%p" />
- </case>
- <case
- latin:mode="email|url"
- >
- <Key
- latin:keyStyle="comKeyStyle"
- latin:keyXPos="15.0%p"
- latin:keyWidth="10.5%p" />
- </case>
- <default>
- <Spacer
- latin:keyXPos="15.0%p"
- latin:keyWidth="10.5%p" />
- </default>
- </switch>
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="49.0%p" />
- <include
- latin:keyXPos="-8.047%p"
- latin:keyWidth="fillRight"
- latin:keyboardLayout="@xml/key_shortcut" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/row_qwerty4.xml b/java/res/xml-sw768dp/row_qwerty4.xml
deleted file mode 100644
index f1f4214ca..000000000
--- a/java/res/xml-sw768dp/row_qwerty4.xml
+++ /dev/null
@@ -1,51 +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.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <Row
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional"
- >
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="5.782%p" />
- <include
- latin:keyboardLayout="@xml/key_settings" />
- <include
- latin:keyboardLayout="@xml/key_shortcut" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="29.923%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/key_apostrophe" />
- <include
- latin:keyboardLayout="@xml/key_dash" />
- <include
- latin:keyboardLayout="@xml/key_f2" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/row_symbols4.xml b/java/res/xml-sw768dp/row_symbols4.xml
deleted file mode 100644
index b801a12a7..000000000
--- a/java/res/xml-sw768dp/row_symbols4.xml
+++ /dev/null
@@ -1,48 +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"
->
- <Row
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional"
- >
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="13.829%p" />
- <Key
- latin:keyLabel="/" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyXPos="29.923%p"
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <Key
- latin:keyLabel="&quot;"
- latin:moreKeys="!text/more_keys_for_tablet_double_quote" />
- <Key
- latin:keyLabel="_" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/row_symbols_shift4.xml b/java/res/xml-sw768dp/row_symbols_shift4.xml
deleted file mode 100644
index f71864bc3..000000000
--- a/java/res/xml-sw768dp/row_symbols_shift4.xml
+++ /dev/null
@@ -1,38 +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"
->
- <Row
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional"
- >
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="29.923%p" />
- <include
- latin:keyboardLayout="@xml/key_space"
- latin:backgroundType="normal" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/rows_10_10_7_symbols.xml b/java/res/xml-sw768dp/rows_10_10_7_symbols.xml
deleted file mode 100644
index d9b0d2383..000000000
--- a/java/res/xml-sw768dp/rows_10_10_7_symbols.xml
+++ /dev/null
@@ -1,69 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols3" />
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_10_10_7_symbols_shift.xml b/java/res/xml-sw768dp/rows_10_10_7_symbols_shift.xml
deleted file mode 100644
index a317dbf84..000000000
--- a/java/res/xml-sw768dp/rows_10_10_7_symbols_shift.xml
+++ /dev/null
@@ -1,69 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift3" />
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_bulgarian.xml b/java/res/xml-sw768dp/rows_bulgarian.xml
deleted file mode 100644
index bdc1262f3..000000000
--- a/java/res/xml-sw768dp/rows_bulgarian.xml
+++ /dev/null
@@ -1,68 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.186%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_bulgarian_bds.xml b/java/res/xml-sw768dp/rows_bulgarian_bds.xml
deleted file mode 100644
index 58c46113e..000000000
--- a/java/res/xml-sw768dp/rows_bulgarian_bds.xml
+++ /dev/null
@@ -1,68 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian_bds1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian_bds2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_bulgarian_bds3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_dvorak.xml b/java/res/xml-sw768dp/rows_dvorak.xml
deleted file mode 100644
index 60d5dd604..000000000
--- a/java/res/xml-sw768dp/rows_dvorak.xml
+++ /dev/null
@@ -1,66 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_dvorak1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_dvorak2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_dvorak3" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_dvorak4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_east_slavic.xml b/java/res/xml-sw768dp/rows_east_slavic.xml
deleted file mode 100644
index 420307d3e..000000000
--- a/java/res/xml-sw768dp/rows_east_slavic.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_east_slavic1" />
- <Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row1_12" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_east_slavic2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_east_slavic3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_greek.xml b/java/res/xml-sw768dp/rows_greek.xml
deleted file mode 100644
index 9e1e00b73..000000000
--- a/java/res/xml-sw768dp/rows_greek.xml
+++ /dev/null
@@ -1,70 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/key_greek_semicolon" />
- <include
- latin:keyboardLayout="@xml/rowkeys_greek1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_greek2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_greek3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_hebrew.xml b/java/res/xml-sw768dp/rows_hebrew.xml
deleted file mode 100644
index a5f6dfe09..000000000
--- a/java/res/xml-sw768dp/rows_hebrew.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_hebrew1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_hebrew2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_hebrew3"
- latin:keyXPos="13.829%p" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_hebrew4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_hindi.xml b/java/res/xml-sw768dp/rows_hindi.xml
deleted file mode 100644
index 6baf09e10..000000000
--- a/java/res/xml-sw768dp/rows_hindi.xml
+++ /dev/null
@@ -1,68 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_hindi1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_hindi2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_hindi3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_mongolian.xml b/java/res/xml-sw768dp/rows_mongolian.xml
deleted file mode 100644
index 5f37f8773..000000000
--- a/java/res/xml-sw768dp/rows_mongolian.xml
+++ /dev/null
@@ -1,68 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_mongolian1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_mongolian2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_mongolian3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_nordic.xml b/java/res/xml-sw768dp/rows_nordic.xml
deleted file mode 100644
index 13d9399e8..000000000
--- a/java/res/xml-sw768dp/rows_nordic.xml
+++ /dev/null
@@ -1,71 +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.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_nordic1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_nordic2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <Spacer
- latin:keyWidth="3.689%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
deleted file mode 100644
index de49aba91..000000000
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ /dev/null
@@ -1,175 +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"
->
- <Row>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <Key
- latin:keyLabel="-"
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="13.829%p"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="+"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="."
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="1"
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyLabel="2"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyLabel="3"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="13.829%p" />
- <Key
- latin:keyStyle="numStarKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="/"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <switch>
- <case
- latin:mode="time|datetime"
- >
- <Key
- latin:keyLabel=","
- latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!text/more_keys_for_am_pm"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- </case>
- <default>
- <Key
- latin:keyLabel=","
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- </default>
- </switch>
- <Key
- latin:keyLabel="4"
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyLabel="5"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyLabel="6"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="13.829%p" />
- <Key
- latin:keyLabel="("
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel=")"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <switch>
- <case
- latin:mode="time|datetime"
- >
- <Key
- latin:keyLabel=":"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- </case>
- <default>
- <Key
- latin:keyLabel="="
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- </default>
- </switch>
- <Key
- latin:keyLabel="7"
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyLabel="8"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyLabel="9"
- latin:keyStyle="numKeyStyle" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer />
- </Row>
- <Row>
- <include
- latin:keyboardLayout="@xml/key_settings"
- latin:keyWidth="8.047%p" />
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyXPos="13.829%p"
- latin:keyWidth="24.140%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="numStarKeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyLabel="0"
- latin:keyStyle="numKeyStyle" />
- <Key
- latin:keyLabel="\#"
- latin:keyStyle="numKeyStyle" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/rows_number_password.xml b/java/res/xml-sw768dp/rows_number_password.xml
deleted file mode 100644
index cfa221491..000000000
--- a/java/res/xml-sw768dp/rows_number_password.xml
+++ /dev/null
@@ -1,79 +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"
->
- <Row>
- <Key
- latin:keyStyle="numTabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <Key
- latin:keyStyle="num1KeyStyle"
- latin:keyXPos="32.076%p" />
- <Key
- latin:keyStyle="num2KeyStyle" />
- <Key
- latin:keyStyle="num3KeyStyle" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="32.076%p" />
- <Key
- latin:keyStyle="num4KeyStyle" />
- <Key
- latin:keyStyle="num5KeyStyle" />
- <Key
- latin:keyStyle="num6KeyStyle" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="32.076%p" />
- <Key
- latin:keyStyle="num7KeyStyle" />
- <Key
- latin:keyStyle="num8KeyStyle" />
- <Key
- latin:keyStyle="num9KeyStyle" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer />
- </Row>
- <Row>
- <include
- latin:keyboardLayout="@xml/key_settings"
- latin:keyWidth="8.047%p" />
- <Key
- latin:keyXPos="45.326%p"
- latin:keyStyle="num0KeyStyle" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/rows_pcqwerty.xml b/java/res/xml-sw768dp/rows_pcqwerty.xml
deleted file mode 100644
index a8447288f..000000000
--- a/java/res/xml-sw768dp/rows_pcqwerty.xml
+++ /dev/null
@@ -1,71 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyWidth="9.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty2" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabel="!text/label_to_symbol_key_pcqwerty"
- latin:keyWidth="12.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty3" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="15.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty4" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_pcqwerty5" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_pcqwerty_symbols.xml b/java/res/xml-sw768dp/rows_pcqwerty_symbols.xml
deleted file mode 100644
index 956da97fb..000000000
--- a/java/res/xml-sw768dp/rows_pcqwerty_symbols.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="7.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyWidth="9.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty2" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="12.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty3" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty4"
- latin:keyXPos="15.0%p" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_pcqwerty5" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_phone.xml b/java/res/xml-sw768dp/rows_phone.xml
deleted file mode 100644
index d06a63b2c..000000000
--- a/java/res/xml-sw768dp/rows_phone.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_number" />
- <Row>
- <Key
- latin:keyStyle="numTabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <Key
- latin:keyLabel="-"
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="13.829%p"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="+"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="numPauseKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="num1KeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyStyle="num2KeyStyle" />
- <Key
- latin:keyStyle="num3KeyStyle" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="13.829%p" />
- <Key
- latin:keyLabel=","
- latin:keyStyle="numKeyStyle"
- latin:keyXPos="13.829%p"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="."
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="numWaitKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="num4KeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyStyle="num5KeyStyle" />
- <Key
- latin:keyStyle="num6KeyStyle" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyXPos="-11.172%p"
- latin:keyWidth="fillRight" />
- </Row>
- <Row>
- <!-- Note: This Spacer prevents the below key from being marked as a left edge key. -->
- <Spacer
- latin:keyWidth="13.829%p" />
- <Key
- latin:keyLabel="("
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel=")"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyLabel="N"
- latin:keyStyle="numKeyStyle"
- latin:keyWidth="8.047%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="num7KeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyStyle="num8KeyStyle" />
- <Key
- latin:keyStyle="num9KeyStyle" />
- <!-- Note: This Spacer prevents the above key from being marked as a right edge key. -->
- <Spacer />
- </Row>
- <Row>
- <include
- latin:keyboardLayout="@xml/key_settings"
- latin:keyWidth="8.047%p" />
- <Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyXPos="13.829%p"
- latin:keyWidth="24.140%p"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="numStarKeyStyle"
- latin:keyXPos="43.125%p" />
- <Key
- latin:keyStyle="num0KeyStyle" />
- <Key
- latin:keyLabel="\#"
- latin:keyStyle="numKeyStyle" />
- </Row>
-</merge>
diff --git a/java/res/xml-sw768dp/rows_qwerty.xml b/java/res/xml-sw768dp/rows_qwerty.xml
deleted file mode 100644
index 8af18ed72..000000000
--- a/java/res/xml-sw768dp/rows_qwerty.xml
+++ /dev/null
@@ -1,68 +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.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_qwertz.xml b/java/res/xml-sw768dp/rows_qwertz.xml
deleted file mode 100644
index 0dd206d45..000000000
--- a/java/res/xml-sw768dp/rows_qwertz.xml
+++ /dev/null
@@ -1,68 +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.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_qwertz1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_qwertz3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_south_slavic.xml b/java/res/xml-sw768dp/rows_south_slavic.xml
deleted file mode 100644
index 6b44c4e6a..000000000
--- a/java/res/xml-sw768dp/rows_south_slavic.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.375%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_south_slavic1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.227%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_south_slavic2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.000%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_south_slavic3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_spanish.xml b/java/res/xml-sw768dp/rows_spanish.xml
deleted file mode 100644
index 4520c100d..000000000
--- a/java/res/xml-sw768dp/rows_spanish.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="10.167%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_spanish2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty3" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_symbols.xml b/java/res/xml-sw768dp/rows_symbols.xml
deleted file mode 100644
index efd77352b..000000000
--- a/java/res/xml-sw768dp/rows_symbols.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols3" />
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_symbols_shift.xml b/java/res/xml-sw768dp/rows_symbols_shift.xml
deleted file mode 100644
index fd1b93d51..000000000
--- a/java/res/xml-sw768dp/rows_symbols_shift.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift3" />
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_thai.xml b/java/res/xml-sw768dp/rows_thai.xml
deleted file mode 100644
index 5f9b383f8..000000000
--- a/java/res/xml-sw768dp/rows_thai.xml
+++ /dev/null
@@ -1,74 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="7.079%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_thai1"
- latin:keyXPos="3.799%p" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"/>
- </Row>
- <Row
- latin:keyWidth="7.079%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_thai2" />
- <include
- latin:keyboardLayout="@xml/key_thai_kho_khuat" />
- </Row>
- <Row
- latin:keyWidth="7.079%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_thai3" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="7.181%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="13.829%p"/>
- <include
- latin:keyboardLayout="@xml/rowkeys_thai4" />
- <include
- latin:keyboardLayout="@xml/keys_comma_period" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_qwerty4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_thai_symbols.xml b/java/res/xml-sw768dp/rows_thai_symbols.xml
deleted file mode 100644
index 528514182..000000000
--- a/java/res/xml-sw768dp/rows_thai_symbols.xml
+++ /dev/null
@@ -1,76 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_thai_digits"
- latin:keyXPos="7.969%p" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols1" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols3" />
- <Key
- latin:keyStyle="toMoreSymbolKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols4" />
-</merge>
diff --git a/java/res/xml-sw768dp/rows_thai_symbols_shift.xml b/java/res/xml-sw768dp/rows_thai_symbols_shift.xml
deleted file mode 100644
index 9d2694b86..000000000
--- a/java/res/xml-sw768dp/rows_thai_symbols_shift.xml
+++ /dev/null
@@ -1,76 +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"
->
- <include
- latin:keyboardLayout="@xml/key_styles_common" />
- <include
- latin:keyboardLayout="@xml/key_styles_currency" />
- <Row
- latin:keyWidth="8.282%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_thai_digits"
- latin:keyXPos="7.969%p" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.282%p"
- >
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift1" />
- </Row>
- <Row
- latin:keyWidth="8.125%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
- <Row
- latin:keyWidth="8.047%p"
- >
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyWidth="13.829%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_symbols_shift3" />
- <Key
- latin:keyStyle="backFromMoreSymbolKeyStyle"
- latin:keyXPos="-13.750%p"
- latin:keyWidth="fillRight" />
- </Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
-</merge>
diff --git a/java/res/xml-v16/key_hindi3_shift_left.xml b/java/res/xml-v16/key_devanagari_sign_anusvara.xml
index 1eb1768a1..27c7bff5a 100644
--- a/java/res/xml-v16/key_hindi3_shift_left.xml
+++ b/java/res/xml-v16/key_devanagari_sign_anusvara.xml
@@ -20,15 +20,13 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
- U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x0901;"
- latin:moreKeys="&#x0945;"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..03017dd78
--- /dev/null
+++ b/java/res/xml-v16/key_devanagari_sign_candrabindu.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
+ U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ <key-style
+ latin:styleName="moreKeysDevanagariSignCandrabindu"
+ latin:moreKeys="&#x0945;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariSignCandrabindu" />
+ </default>
+ </switch>
+ <!-- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU -->
+ <Key
+ latin:keyStyle="moreKeysDevanagariSignCandrabindu"
+ latin:keyLabel="&#x0901;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/key_hindi3_right.xml b/java/res/xml-v16/key_devanagari_sign_nukta.xml
index 232810f98..09c347706 100644
--- a/java/res/xml-v16/key_hindi3_right.xml
+++ b/java/res/xml-v16/key_devanagari_sign_nukta.xml
@@ -20,17 +20,30 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+093C: "़" DEVANAGARI SIGN NUKTA
- U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
- U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
+ U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariSignNukta"
+ latin:moreKeys="&#x097D;,&#x0970;,&#x093D;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariSignNukta" />
+ </default>
+ </switch>
+ <!-- U+093C: "़" DEVANAGARI SIGN NUKTA -->
<Key
+ latin:keyStyle="moreKeysDevanagariSignNukta"
latin:keyLabel="&#x093C;"
- latin:moreKeys="&#x097D;,&#x0970;,&#x093D;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/keys_hindi3_left2.xml b/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml
index 9474c1763..0316a7bde 100644
--- a/java/res/xml-v16/keys_hindi3_left2.xml
+++ b/java/res/xml-v16/key_devanagari_vowel_sign_candra_o.xml
@@ -20,8 +20,8 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
@@ -29,8 +29,4 @@
<Key
latin:keyLabel="&#x0949;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x0902;"
- 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
new file mode 100644
index 000000000..4dd3e85cc
--- /dev/null
+++ b/java/res/xml-v16/key_devanagari_vowel_sign_vocalic_r.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR"
+ latin:moreKeys="&#x0944;" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+0913: "ओ" DEVANAGARI LETTER O -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR"
+ latin:moreKeys="&#x0913;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR" />
+ </default>
+ </switch>
+ <!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R -->
+ <Key
+ latin:keyStyle="moreKeysDevanagariVowelSignVocalicR"
+ latin:keyLabel="&#x0943;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-v16/keys_hindi1_left5.xml b/java/res/xml-v16/keys_hindi1_left5.xml
deleted file mode 100644
index e3ad299ff..000000000
--- a/java/res/xml-v16/keys_hindi1_left5.xml
+++ /dev/null
@@ -1,75 +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.
-*/
--->
-
-<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU
- U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA
- U+0967: "१" DEVANAGARI DIGIT ONE -->
- <Key
- latin:keyLabel="&#x094C;"
- latin:moreKeys="&#x094C;&#x0902;,%"
- latin:keyHintLabel="1"
- latin:additionalMoreKeys="&#x0967;,1"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0948: "ै" DEVANAGARI VOWEL SIGN AI
- U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA
- U+0968: "२" DEVANAGARI DIGIT TWO -->
- <Key
- latin:keyLabel="&#x0948;"
- latin:moreKeys="&#x0948;&#x0902;,%"
- latin:keyHintLabel="2"
- latin:additionalMoreKeys="&#x0968;,2"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+093E: "ा" DEVANAGARI VOWEL SIGN AA
- U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
- U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU
- U+0969: "३" DEVANAGARI DIGIT THREE -->
- <Key
- latin:keyLabel="&#x093E;"
- latin:moreKeys="&#x093E;&#x0902;,&#x093E;&#x0901;,%"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="&#x0969;,3"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II
- U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA
- U+096A: "४" DEVANAGARI DIGIT FOUR -->
- <Key
- latin:keyLabel="&#x0940;"
- latin:moreKeys="&#x0940;&#x0902;,%"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="&#x096A;,4"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0942: "ू" DEVANAGARI VOWEL SIGN UU
- U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
- U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU
- U+096B: "५" DEVANAGARI DIGIT FIVE -->
- <Key
- latin:keyLabel="&#x0942;"
- latin:moreKeys="&#x0942;&#x0902;,&#x0942;&#x0901;,%"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="&#x096B;,5"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-v16/keys_hindi2_left5.xml b/java/res/xml-v16/keys_hindi2_left5.xml
deleted file mode 100644
index 05c4f57e9..000000000
--- a/java/res/xml-v16/keys_hindi2_left5.xml
+++ /dev/null
@@ -1,59 +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.
-*/
--->
-
-<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+094B: "ो" DEVANAGARI VOWEL SIGN O
- U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
- U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
- <Key
- latin:keyLabel="&#x094B;"
- latin:moreKeys="&#x094B;&#x0902;,&#x0949;,&#x094A;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0947: "े" DEVANAGARI VOWEL SIGN E
- U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x0947;"
- latin:moreKeys="&#x0947;&#x0902;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
- <Key
- latin:keyLabel="&#x094D;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+093F: "ि" DEVANAGARI VOWEL SIGN I
- U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x093F;"
- latin:moreKeys="&#x093F;&#x0902;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0941: "ु" DEVANAGARI VOWEL SIGN U
- U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
- U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
- <Key
- latin:keyLabel="&#x0941;"
- latin:moreKeys="&#x0941;&#x0902;,&#x0941;&#x0901;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-v16/key_hindi3_shift_right.xml b/java/res/xml-v16/keystyle_devanagari_sign_virama.xml
index 0f26cb55c..a2fbf53d3 100644
--- a/java/res/xml-v16/key_hindi3_shift_right.xml
+++ b/java/res/xml-v16/keystyle_devanagari_sign_virama.xml
@@ -20,15 +20,14 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R
- U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
- <Key
- latin:keyLabel="&#x0943;"
- latin:moreKeys="&#x0944;"
+ <!-- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
+ <key-style
+ latin:styleName="baseKeyDevanagariSignVirama"
+ latin:keyLabel="&#x094D;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml-v16/key_hindi1_shift.xml b/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml
index 19b964367..ac56cb77b 100644
--- a/java/res/xml-v16/key_hindi1_shift.xml
+++ b/java/res/xml-v16/keystyle_devanagari_sign_visarga.xml
@@ -20,13 +20,14 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<!-- U+0903: "ः" DEVANAGARI SIGN VISARGA -->
- <Key
+ <key-style
+ latin:styleName="baseKeyDevanagariSignVisarga"
latin:keyLabel="&#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
new file mode 100644
index 000000000..8e256032c
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_aa.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
+ U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAa"
+ latin:moreKeys="&#x093E;&#x0902;,&#x093E;&#x0901;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAa" />
+ </default>
+ </switch>
+ <!-- U+093E: "ा" DEVANAGARI VOWEL SIGN AA -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAa"
+ latin:parentStyle="moreKeysDevanagariVowelSignAa"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..e79033971
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ai.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi"
+ latin:moreKeys="&#x0948;&#x0902;,%" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi"
+ latin:moreKeys="&#x0936;&#x094D;&#x0930;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi" />
+ </default>
+ </switch>
+ <!-- U+0948: "ै" DEVANAGARI VOWEL SIGN AI -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAi"
+ latin:parentStyle="moreKeysDevanagariVowelSignAi"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..43387a388
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_au.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!--U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAu"
+ latin:moreKeys="&#x094C;&#x0902;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAu" />
+ </default>
+ </switch>
+ <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAu"
+ latin:parentStyle="moreKeysDevanagariVowelSignAu"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..c70d9d944
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_e.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.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE"
+ latin:moreKeys="&#x0947;&#x0902;" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+0903: "ः‍" DEVANAGARI SIGN VISARGA
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE"
+ latin:moreKeys="&#x0903;,&#x093D;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE" />
+ </default>
+ </switch>
+ <!-- U+0947: "े" DEVANAGARI VOWEL SIGN E -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignE"
+ latin:parentStyle="moreKeysDevanagariVowelSignE"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..845c1b02e
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_i.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignI"
+ latin:moreKeys="&#x093F;&#x0902;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignI" />
+ </default>
+ </switch>
+ <!-- U+093F: "ि" DEVANAGARI VOWEL SIGN I -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignI"
+ latin:parentStyle="moreKeysDevanagariVowelSignI"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..0de9650be
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_ii.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignIi"
+ latin:moreKeys="&#x0940;&#x0902;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignIi" />
+ </default>
+ </switch>
+ <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignIi"
+ latin:parentStyle="moreKeysDevanagariVowelSignIi"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..06f07fac9
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_o.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
+ U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
+ U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignO"
+ latin:moreKeys="&#x094B;&#x0902;,&#x0949;,&#x094A;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignO" />
+ </default>
+ </switch>
+ <!-- U+094B: "ो" DEVANAGARI VOWEL SIGN O -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignO"
+ latin:parentStyle="moreKeysDevanagariVowelSignO"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..469a27bdf
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_u.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
+ U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignU"
+ latin:moreKeys="&#x0941;&#x0902;,&#x0941;&#x0901;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignU" />
+ </default>
+ </switch>
+ <!-- U+0941: "ु" DEVANAGARI VOWEL SIGN U -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignU"
+ latin:parentStyle="moreKeysDevanagariVowelSignU"
+ latin:keyLabel="&#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
new file mode 100644
index 000000000..25867c086
--- /dev/null
+++ b/java/res/xml-v16/keystyle_devanagari_vowel_sign_uu.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
+ U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignUu"
+ latin:moreKeys="&#x0942;&#x0902;,&#x0942;&#x0901;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignUu" />
+ </default>
+ </switch>
+ <!-- U+0942: "ू" DEVANAGARI VOWEL SIGN UU -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignUu"
+ latin:parentStyle="moreKeysDevanagariVowelSignUu"
+ latin:keyLabel="&#x0942;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml b/java/res/xml/kbd_armenian_phonetic.xml
index 135222b22..1eb3c7e7d 100644
--- a/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml
+++ b/java/res/xml/kbd_armenian_phonetic.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -27,5 +27,5 @@
latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_thai_symbols_shift" />
+ latin:keyboardLayout="@xml/rows_armenian_phonetic" />
</Keyboard>
diff --git a/java/res/xml-sw768dp-land/kbd_phone.xml b/java/res/xml/kbd_emoji_category1.xml
index 890518210..c11a83017 100644
--- a/java/res/xml-sw768dp-land/kbd_phone.xml
+++ b/java/res/xml/kbd_emoji_category1.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.
@@ -20,11 +20,12 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyboardLeftPadding="10%p"
- latin:keyboardRightPadding="10%p"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
>
- <include
- latin:keyboardLayout="@xml/rows_phone" />
+ <GridRows
+ latin:codesArray="@array/emoji_faces"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
</Keyboard>
diff --git a/java/res/xml-sw768dp-land/kbd_number.xml b/java/res/xml/kbd_emoji_category2.xml
index 1cb775ef7..d3e5890ea 100644
--- a/java/res/xml-sw768dp-land/kbd_number.xml
+++ b/java/res/xml/kbd_emoji_category2.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.
@@ -20,11 +20,12 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:keyboardLeftPadding="10%p"
- latin:keyboardRightPadding="10%p"
- latin:keyWidth="13.250%p"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
>
- <include
- latin:keyboardLayout="@xml/rows_number" />
+ <GridRows
+ latin:codesArray="@array/emoji_objects"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
</Keyboard>
diff --git a/java/res/xml-sw600dp/kbd_10_10_7_symbols.xml b/java/res/xml/kbd_emoji_category3.xml
index dd545b5ef..0efafa814 100644
--- a/java/res/xml-sw600dp/kbd_10_10_7_symbols.xml
+++ b/java/res/xml/kbd_emoji_category3.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -20,8 +20,12 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
>
- <include
- latin:keyboardLayout="@xml/rows_10_10_7_symbols" />
+ <GridRows
+ latin:codesArray="@array/emoji_nature"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
</Keyboard>
diff --git a/java/res/xml-sw600dp/kbd_10_10_7_symbols_shift.xml b/java/res/xml/kbd_emoji_category4.xml
index c36f0097e..e5291207f 100644
--- a/java/res/xml-sw600dp/kbd_10_10_7_symbols_shift.xml
+++ b/java/res/xml/kbd_emoji_category4.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -20,8 +20,12 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
>
- <include
- latin:keyboardLayout="@xml/rows_10_10_7_symbols_shift" />
+ <GridRows
+ latin:codesArray="@array/emoji_places"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
</Keyboard>
diff --git a/java/res/xml/kbd_emoji_category5.xml b/java/res/xml/kbd_emoji_category5.xml
new file mode 100644
index 000000000..1836879d6
--- /dev/null
+++ b/java/res/xml/kbd_emoji_category5.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.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
+>
+ <GridRows
+ latin:codesArray="@array/emoji_symbols"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
+</Keyboard>
diff --git a/java/res/xml/kbd_emoji_category6.xml b/java/res/xml/kbd_emoji_category6.xml
new file mode 100644
index 000000000..b47ebfec0
--- /dev/null
+++ b/java/res/xml/kbd_emoji_category6.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.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:keyWidth="@fraction/emoji_keyboard_key_width"
+ latin:keyLetterSize="90%p"
+ latin:keyLabelSize="60%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
+>
+ <GridRows
+ latin:textsArray="@array/emoji_emoticons"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
+</Keyboard>
diff --git a/java/res/xml/kbd_emoji_recents.xml b/java/res/xml/kbd_emoji_recents.xml
new file mode 100644
index 000000000..73926ecc0
--- /dev/null
+++ b/java/res/xml/kbd_emoji_recents.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.
+*/
+-->
+
+<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:keyLabelSize="60%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
+>
+ <GridRows
+ latin:codesArray="@array/emoji_recents"
+ latin:keyLabelFlags="fontNormal"
+ latin:backgroundType="empty" />
+</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_thai_symbols.xml b/java/res/xml/kbd_khmer.xml
index 5ddf57446..7a2337a48 100644
--- a/java/res/xml-sw768dp/kbd_thai_symbols.xml
+++ b/java/res/xml/kbd_khmer.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -27,5 +27,5 @@
latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_thai_symbols" />
+ latin:keyboardLayout="@xml/rows_khmer" />
</Keyboard>
diff --git a/java/res/xml/kbd_pcqwerty_symbols.xml b/java/res/xml/kbd_lao.xml
index bfb39e8aa..2bba330de 100644
--- a/java/res/xml/kbd_pcqwerty_symbols.xml
+++ b/java/res/xml/kbd_lao.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -27,5 +27,5 @@
latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_pcqwerty_symbols" />
+ latin:keyboardLayout="@xml/rows_lao" />
</Keyboard>
diff --git a/java/res/xml/kbd_thai_symbols_shift.xml b/java/res/xml/kbd_nepali_romanized.xml
index a2d67caf4..9e4381364 100644
--- a/java/res/xml/kbd_thai_symbols_shift.xml
+++ b/java/res/xml/kbd_nepali_romanized.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -20,8 +20,7 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_symbols_shift" />
+ latin:keyboardLayout="@xml/rows_nepali_romanized" />
</Keyboard>
diff --git a/java/res/xml/kbd_10_10_7_symbols_shift.xml b/java/res/xml/kbd_nepali_traditional.xml
index a2d67caf4..6854e32bd 100644
--- a/java/res/xml/kbd_10_10_7_symbols_shift.xml
+++ b/java/res/xml/kbd_nepali_traditional.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -20,8 +20,7 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_symbols_shift" />
+ latin:keyboardLayout="@xml/rows_nepali_traditional" />
</Keyboard>
diff --git a/java/res/xml/key_armenian_sha.xml b/java/res/xml/key_armenian_sha.xml
new file mode 100644
index 000000000..3865c1984
--- /dev/null
+++ b/java/res/xml/key_armenian_sha.xml
@@ -0,0 +1,28 @@
+<?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+0577: "շ" ARMENIAN SMALL LETTER SHA -->
+ <Key
+ latin:keyLabel="&#x0577;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/key_armenian_xeh.xml b/java/res/xml/key_armenian_xeh.xml
new file mode 100644
index 000000000..007a5802d
--- /dev/null
+++ b/java/res/xml/key_armenian_xeh.xml
@@ -0,0 +1,28 @@
+<?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+056D: "խ" ARMENIAN SMALL LETTER XEH -->
+ <Key
+ latin:keyLabel="&#x056D;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/key_hindi3_shift_left.xml b/java/res/xml/key_devanagari_sign_anusvara.xml
index c5e2f1386..0acd3bcd4 100644
--- a/java/res/xml/key_hindi3_shift_left.xml
+++ b/java/res/xml/key_devanagari_sign_anusvara.xml
@@ -20,17 +20,15 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<!-- U+25CC: "◌" DOTTED CIRCLE
- U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU
- U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
<Key
- latin:keyLabel="&#x25CC;&#x0901;"
- latin:code="0x0901"
- latin:moreKeys="&#x25CC;&#x0945;|&#x0945;"
+ latin:keyLabel="&#x25CC;&#x0902;"
+ latin:code="0x0902"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
</merge>
diff --git a/java/res/xml/key_hindi3_right.xml b/java/res/xml/key_devanagari_sign_candrabindu.xml
index 5a97355f6..df0c4e054 100644
--- a/java/res/xml/key_hindi3_right.xml
+++ b/java/res/xml/key_devanagari_sign_candrabindu.xml
@@ -20,19 +20,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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0945: "ॅ" DEVANAGARI VOWEL SIGN CANDRA E -->
+ <key-style
+ latin:styleName="moreKeysDevanagariSignCandrabindu"
+ latin:moreKeys="&#x25CC;&#x0945;|&#x0945;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariSignCandrabindu" />
+ </default>
+ </switch>
<!-- U+25CC: "◌" DOTTED CIRCLE
- U+093C: "़" DEVANAGARI SIGN NUKTA
- U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
- U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ U+0901: "ँ" DEVANAGARI SIGN CANDRABINDU -->
<Key
- latin:keyLabel="&#x25CC;&#x093C;"
- latin:code="0x093C"
- latin:moreKeys="&#x25CC;&#x097D;|&#x097D;,&#x25CC;&#x0970;|&#x0970;,&#x25CC;&#x093D;|&#x093D;"
+ latin:keyStyle="moreKeysDevanagariSignCandrabindu"
+ latin:keyLabel="&#x25CC;&#x0901;"
+ latin:code="0x0901"
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
new file mode 100644
index 000000000..f7a03ee90
--- /dev/null
+++ b/java/res/xml/key_devanagari_sign_nukta.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+097D: "ॽ" DEVANAGARI LETTER GLOTTAL STOP
+ U+0970: "॰" DEVANAGARI ABBREVIATION SIGN
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariSignNukta"
+ latin:moreKeys="&#x25CC;&#x097D;|&#x097D;,&#x25CC;&#x0970;|&#x0970;,&#x25CC;&#x093D;|&#x093D;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariSignNukta" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093C: "़" DEVANAGARI SIGN NUKTA -->
+ <Key
+ latin:keyStyle="moreKeysDevanagariSignNukta"
+ latin:keyLabel="&#x25CC;&#x093C;"
+ latin:code="0x093C"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/keys_hindi3_left2.xml b/java/res/xml/key_devanagari_vowel_sign_candra_o.xml
index 4f1ad16ef..370fc5405 100644
--- a/java/res/xml/keys_hindi3_left2.xml
+++ b/java/res/xml/key_devanagari_vowel_sign_candra_o.xml
@@ -20,8 +20,8 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
@@ -31,10 +31,4 @@
latin:keyLabel="&#x25CC;&#x0949;"
latin:code="0x0949"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0902: "ं" DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x25CC;&#x0902;"
- latin:code="0x0902"
- 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
new file mode 100644
index 000000000..f150d7ed9
--- /dev/null
+++ b/java/res/xml/key_devanagari_vowel_sign_vocalic_r.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR"
+ latin:moreKeys="&#x25CC;&#x0944;|&#x0944;" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+0913: "ओ" DEVANAGARI LETTER O -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR"
+ latin:moreKeys="&#x0913;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignVocalicR" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R -->
+ <Key
+ latin:keyStyle="moreKeysDevanagariVowelSignVocalicR"
+ latin:keyLabel="&#x25CC;&#x0943;"
+ latin:code="0x0943"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml-sw768dp/key_settings.xml b/java/res/xml/key_f2.xml
index 0d3bb59a4..473dd210a 100644
--- a/java/res/xml-sw768dp/key_settings.xml
+++ b/java/res/xml/key_f2.xml
@@ -23,13 +23,16 @@
>
<switch>
<case
- latin:clobberSettingsKey="false"
+ latin:mode="email|url"
>
<Key
- latin:keyStyle="settingsKeyStyle" />
+ latin:keyStyle="comKeyStyle"
+ latin:keyWidth="fillRight" />
</case>
<default>
- <Spacer />
+ <Key
+ latin:keyStyle="emojiKeyStyle"
+ latin:keyWidth="fillRight" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/key_nepali_traditional_period.xml b/java/res/xml/key_nepali_traditional_period.xml
new file mode 100644
index 000000000..0f575c50b
--- /dev/null
+++ b/java/res/xml/key_nepali_traditional_period.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of 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"
+ >
+ <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" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVirama"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:moreKeys="!fixedColumnOrder!4,.,!text/more_keys_for_punctuation"
+ latin:backgroundType="functional" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml-sw768dp/key_shortcut.xml b/java/res/xml/key_space_3kw.xml
index 2d09ebbfc..20ec882df 100644
--- a/java/res/xml-sw768dp/key_shortcut.xml
+++ b/java/res/xml/key_space_3kw.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -23,14 +23,19 @@
>
<switch>
<case
- latin:shortcutKeyEnabled="true"
+ latin:languageSwitchKeyEnabled="true"
>
<Key
- latin:keyStyle="shortcutKeyStyle" />
+ latin:keyStyle="languageSwitchKeyStyle" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="20%p" />
</case>
+ <!-- languageSwitchKeyEnabled="false" -->
<default>
- <!-- The empty space instead of shortcut key. -->
- <Spacer />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="30%p" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/key_space.xml b/java/res/xml/key_space_5kw.xml
index 02ee42fd2..b6d38fb33 100644
--- a/java/res/xml/key_space.xml
+++ b/java/res/xml/key_space_5kw.xml
@@ -23,7 +23,7 @@
>
<switch>
<case
- latin:languageCode="fa"
+ latin:languageCode="fa|ne"
latin:languageSwitchKeyEnabled="true"
>
<Key
@@ -35,7 +35,7 @@
latin:keyStyle="zwnjKeyStyle" />
</case>
<case
- latin:languageCode="fa"
+ latin:languageCode="fa|ne"
latin:languageSwitchKeyEnabled="false"
>
<Key
diff --git a/java/res/xml/kbd_10_10_7_symbols.xml b/java/res/xml/key_space_symbols.xml
index 4d9861b73..1efc4ff4e 100644
--- a/java/res/xml/kbd_10_10_7_symbols.xml
+++ b/java/res/xml/key_space_symbols.xml
@@ -18,10 +18,9 @@
*/
-->
-<Keyboard
+<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
>
<include
- latin:keyboardLayout="@xml/rows_symbols" />
-</Keyboard>
+ latin:keyboardLayout="@xml/key_space_3kw" />
+</merge>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 355455e3b..67ed9620d 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -21,6 +21,20 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+ >
+ <key-style
+ latin:styleName="hasShiftedLetterHintStyle"
+ latin:keyLabelFlags="hasShiftedLetterHint|shiftedLetterActivated" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="hasShiftedLetterHintStyle"
+ latin:keyLabelFlags="hasShiftedLetterHint" />
+ </default>
+ </switch>
<!-- Base key style for the key which may have settings or tab key as popup key. -->
<include
latin:keyboardLayout="@xml/key_styles_f1" />
@@ -67,30 +81,6 @@
latin:backgroundType="functional" />
<include
latin:keyboardLayout="@xml/key_styles_enter" />
- <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:keyLabel=":-)"
- latin:keyOutputText=":-) "
- latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!text/more_keys_for_smiley"
- latin:backgroundType="functional" />
- </case>
- </switch>
<key-style
latin:styleName="spaceKeyStyle"
latin:code="!code/key_space"
@@ -129,7 +119,8 @@
latin:styleName="emojiKeyStyle"
latin:code="!code/key_emoji"
latin:keyIcon="!icon/emoji_key"
- latin:keyActionFlags="noKeyPreview" />
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="functional" />
<key-style
latin:styleName="tabKeyStyle"
latin:code="!code/key_tab"
@@ -193,4 +184,11 @@
latin:keyLabelFlags="hasPopupHint"
latin:moreKeys="!text/more_keys_for_punctuation"
latin:backgroundType="functional" />
+ <key-style
+ latin:styleName="comKeyStyle"
+ latin:keyLabel="!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 76fe0e6b0..84c2abc08 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -95,22 +95,26 @@
<!-- fa: Persian (Rial and Afgahni)
hi: Hindi (Indian Rupee)
iw: Hebrew (New Sheqel)
+ lo: Lao (Kip)
mn: Mongolian (Tugrik)
+ ne: Nepali (Nepalese Rupee)
th: Thai (Baht)
uk: Ukrainian (Hryvnia)
vi: Vietnamese (Dong) -->
<!-- TODO: The currency sign of Turkish Lira was created in 2012 and assigned U+20BA for
its unicode, although there is no font glyph for it as of November 2012. -->
+ <!-- TODO: The currency sign of Armenian Dram was created in 2012 and assigned U+058F for
+ its unicode, although there is no font glyph for it as of September 2013. -->
<case
- latin:languageCode="fa|hi|iw|mn|th|uk|vi"
+ latin:languageCode="fa|hi|iw|lo|mn|ne|th|uk|vi"
>
<!-- U+00A3: "£" POUND SIGN
U+20AC: "€" EURO SIGN
U+00A2: "¢" CENT SIGN -->
<key-style
latin:styleName="currencyKeyStyle"
- latin:keyLabel="!text/keylabel_for_currency_generic"
- latin:moreKeys="!text/more_keys_for_currency_generic" />
+ latin:keyLabel="!text/keylabel_for_currency"
+ latin:moreKeys="!text/more_keys_for_currency" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
latin:keyLabel="&#x00A3;" />
diff --git a/java/res/xml/key_symbols_period.xml b/java/res/xml/key_symbols_period.xml
new file mode 100644
index 000000000..6efc9dee3
--- /dev/null
+++ b/java/res/xml/key_symbols_period.xml
@@ -0,0 +1,47 @@
+<?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/keyboard_layout_set_armenian_phonetic.xml b/java/res/xml/keyboard_layout_set_armenian_phonetic.xml
new file mode 100644
index 000000000..35bd43fb9
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_armenian_phonetic.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_armenian_phonetic"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_azerty.xml b/java/res/xml/keyboard_layout_set_azerty.xml
index 4d144edbc..38797f91a 100644
--- a/java/res/xml/keyboard_layout_set_azerty.xml
+++ b/java/res/xml/keyboard_layout_set_azerty.xml
@@ -26,10 +26,10 @@
latin:enableProximityCharsCorrection="true" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keyboard_layout_set_colemak.xml b/java/res/xml/keyboard_layout_set_colemak.xml
index c18f13225..3061872a8 100644
--- a/java/res/xml/keyboard_layout_set_colemak.xml
+++ b/java/res/xml/keyboard_layout_set_colemak.xml
@@ -26,10 +26,10 @@
latin:enableProximityCharsCorrection="true" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keyboard_layout_set_dvorak.xml b/java/res/xml/keyboard_layout_set_dvorak.xml
index eb8e0c539..31aeec525 100644
--- a/java/res/xml/keyboard_layout_set_dvorak.xml
+++ b/java/res/xml/keyboard_layout_set_dvorak.xml
@@ -26,10 +26,10 @@
latin:enableProximityCharsCorrection="true" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keyboard_layout_set_emoji.xml b/java/res/xml/keyboard_layout_set_emoji.xml
new file mode 100644
index 000000000..98e6b6b5c
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_emoji.xml
@@ -0,0 +1,44 @@
+<?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="emojiRecents"
+ latin:elementKeyboard="@xml/kbd_emoji_recents" />
+ <Element
+ latin:elementName="emojiCategory1"
+ latin:elementKeyboard="@xml/kbd_emoji_category1" />
+ <Element
+ latin:elementName="emojiCategory2"
+ latin:elementKeyboard="@xml/kbd_emoji_category2" />
+ <Element
+ latin:elementName="emojiCategory3"
+ latin:elementKeyboard="@xml/kbd_emoji_category3" />
+ <Element
+ latin:elementName="emojiCategory4"
+ latin:elementKeyboard="@xml/kbd_emoji_category4" />
+ <Element
+ latin:elementName="emojiCategory5"
+ latin:elementKeyboard="@xml/kbd_emoji_category5" />
+ <Element
+ latin:elementName="emojiCategory6"
+ latin:elementKeyboard="@xml/kbd_emoji_category6" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_hebrew.xml b/java/res/xml/keyboard_layout_set_hebrew.xml
index 212816dfe..d5b25b36c 100644
--- a/java/res/xml/keyboard_layout_set_hebrew.xml
+++ b/java/res/xml/keyboard_layout_set_hebrew.xml
@@ -26,10 +26,10 @@
latin:enableProximityCharsCorrection="true" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keyboard_layout_set_khmer.xml b/java/res/xml/keyboard_layout_set_khmer.xml
new file mode 100644
index 000000000..181f98b3d
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_khmer.xml
@@ -0,0 +1,58 @@
+<?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_khmer"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_khmer"
+ latin:enableProximityCharsCorrection="true" />
+ <!-- On these shifted alphabet layouts the proximity characters correction should be disabled
+ because the letters on these layouts aren't the ones in different case of the above
+ unshifted layouts. -->
+ <Element
+ latin:elementName="alphabetManualShifted"
+ latin:elementKeyboard="@xml/kbd_khmer" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_khmer" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_khmer" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_lao.xml b/java/res/xml/keyboard_layout_set_lao.xml
new file mode 100644
index 000000000..2ffde45db
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_lao.xml
@@ -0,0 +1,58 @@
+<?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_lao"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_lao"
+ latin:enableProximityCharsCorrection="true" />
+ <!-- On these shifted alphabet layouts the proximity characters correction should be disabled
+ because the letters on these layouts aren't the ones in different case of the above
+ unshifted layouts. -->
+ <Element
+ latin:elementName="alphabetManualShifted"
+ latin:elementKeyboard="@xml/kbd_lao" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_lao" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_lao" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_nepali_romanized.xml b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
new file mode 100644
index 000000000..fbbc6a5a0
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
@@ -0,0 +1,58 @@
+<?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_nepali_romanized"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_romanized"
+ latin:enableProximityCharsCorrection="true" />
+ <!-- On these shifted alphabet layouts the proximity characters correction should be disabled
+ because the letters on these layouts aren't the ones in different case of the above
+ unshifted layouts. -->
+ <Element
+ latin:elementName="alphabetManualShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_romanized" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_nepali_romanized" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_romanized" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_nepali_traditional.xml b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
new file mode 100644
index 000000000..4a3b60153
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
@@ -0,0 +1,58 @@
+<?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_nepali_traditional"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_traditional"
+ latin:enableProximityCharsCorrection="true" />
+ <!-- On these shifted alphabet layouts the proximity characters correction should be disabled
+ because the letters on these layouts aren't the ones in different case of the above
+ unshifted layouts. -->
+ <Element
+ latin:elementName="alphabetManualShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_traditional" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_nepali_traditional" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_nepali_traditional" />
+ <Element
+ latin:elementName="symbols"
+ latin:elementKeyboard="@xml/kbd_symbols" />
+ <Element
+ latin:elementName="symbolsShifted"
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
+ <Element
+ latin:elementName="phone"
+ latin:elementKeyboard="@xml/kbd_phone" />
+ <Element
+ latin:elementName="phoneSymbols"
+ latin:elementKeyboard="@xml/kbd_phone_symbols" />
+ <Element
+ latin:elementName="number"
+ latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/keyboard_layout_set_pcqwerty.xml b/java/res/xml/keyboard_layout_set_pcqwerty.xml
index 9367ed00c..67fbd9159 100644
--- a/java/res/xml/keyboard_layout_set_pcqwerty.xml
+++ b/java/res/xml/keyboard_layout_set_pcqwerty.xml
@@ -25,12 +25,6 @@
latin:elementKeyboard="@xml/kbd_pcqwerty"
latin:enableProximityCharsCorrection="true" />
<Element
- latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_pcqwerty_symbols" />
- <Element
- latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_pcqwerty_symbols" />
- <Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
<Element
diff --git a/java/res/xml/keyboard_layout_set_spanish.xml b/java/res/xml/keyboard_layout_set_spanish.xml
index 57cef5234..c454de3b4 100644
--- a/java/res/xml/keyboard_layout_set_spanish.xml
+++ b/java/res/xml/keyboard_layout_set_spanish.xml
@@ -26,10 +26,10 @@
latin:enableProximityCharsCorrection="true" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_10_10_7_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keyboard_layout_set_thai.xml b/java/res/xml/keyboard_layout_set_thai.xml
index 94713e3d4..b8f99971b 100644
--- a/java/res/xml/keyboard_layout_set_thai.xml
+++ b/java/res/xml/keyboard_layout_set_thai.xml
@@ -42,10 +42,10 @@
latin:elementKeyboard="@xml/kbd_thai" />
<Element
latin:elementName="symbols"
- latin:elementKeyboard="@xml/kbd_thai_symbols" />
+ latin:elementKeyboard="@xml/kbd_symbols" />
<Element
latin:elementName="symbolsShifted"
- latin:elementKeyboard="@xml/kbd_thai_symbols_shift" />
+ latin:elementKeyboard="@xml/kbd_symbols_shift" />
<Element
latin:elementName="phone"
latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/res/xml/keys_comma_period.xml b/java/res/xml/keys_comma_period.xml
new file mode 100644
index 000000000..02b46c23a
--- /dev/null
+++ b/java/res/xml/keys_comma_period.xml
@@ -0,0 +1,103 @@
+<?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: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+0589: "։" ARMENIAN FULL STOP -->
+ <Key
+ latin:keyLabel="&#x0589;"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:backgroundType="functional"
+ latin:moreKeys="!text/more_keys_for_punctuation" />
+ <!-- U+055D: "՝" ARMENIAN COMMA -->
+ <Key
+ latin:keyLabel="&#x055D;"
+ latin:backgroundType="functional" />
+ </case>
+ <default>
+ <Key
+ latin:keyLabel="."
+ latin:keyHintLabel="!text/keyhintlabel_for_tablet_period"
+ latin:backgroundType="functional"
+ latin:moreKeys="!text/more_keys_for_tablet_period" />
+ <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" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/keys_hindi1_left5.xml b/java/res/xml/keys_hindi1_left5.xml
deleted file mode 100644
index 8757afeaf..000000000
--- a/java/res/xml/keys_hindi1_left5.xml
+++ /dev/null
@@ -1,85 +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.
-*/
--->
-
-<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU
- U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA
- U+0967: "१" DEVANAGARI DIGIT ONE -->
- <Key
- latin:keyLabel="&#x25CC;&#x094C;"
- latin:code="0x094C"
- latin:moreKeys="&#x25CC;&#x094C;&#x0902;|&#x094C;&#x0902;,%"
- latin:keyHintLabel="1"
- latin:additionalMoreKeys="&#x0967;,1"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0948: "ै" DEVANAGARI VOWEL SIGN AI
- U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA
- U+0968: "२" DEVANAGARI DIGIT TWO -->
- <Key
- latin:keyLabel="&#x25CC;&#x0948;"
- latin:code="0x0948"
- latin:moreKeys="&#x25CC;&#x0948;&#x0902;|&#x0948;&#x0902;,%"
- latin:keyHintLabel="2"
- latin:additionalMoreKeys="&#x0968;,2"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+093E: "ा" DEVANAGARI VOWEL SIGN AA
- U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
- U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU
- U+0969: "३" DEVANAGARI DIGIT THREE -->
- <Key
- latin:keyLabel="&#x25CC;&#x093E;"
- latin:code="0x093E"
- latin:moreKeys="&#x25CC;&#x093E;&#x0902;|&#x093E;&#x0902;,&#x25CC;&#x093E;&#x0901;|&#x093E;&#x0901;,%"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="&#x0969;,3"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0940: "ी" DEVANAGARI VOWEL SIGN II
- U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA
- U+096A: "४" DEVANAGARI DIGIT FOUR -->
- <Key
- latin:keyLabel="&#x25CC;&#x0940;"
- latin:code="0x0940"
- latin:moreKeys="&#x25CC;&#x0940;&#x0902;|&#x0940;&#x0902;,%"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="&#x096A;,4"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0942: "ू" DEVANAGARI VOWEL SIGN UU
- U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
- U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU
- U+096B: "५" DEVANAGARI DIGIT FIVE -->
- <Key
- latin:keyLabel="&#x25CC;&#x0942;"
- latin:code="0x0942"
- latin:moreKeys="&#x25CC;&#x0942;&#x0902;|&#x0942;&#x0902;,&#x25CC;&#x0942;&#x0901;|&#x0942;&#x0901;,%"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="&#x096B;,5"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
-</merge>
diff --git a/java/res/xml/keys_hindi2_left5.xml b/java/res/xml/keys_hindi2_left5.xml
deleted file mode 100644
index 4c3a5e051..000000000
--- a/java/res/xml/keys_hindi2_left5.xml
+++ /dev/null
@@ -1,69 +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.
-*/
--->
-
-<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+094B: "ो" DEVANAGARI VOWEL SIGN O
- U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
- U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
- U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
- <Key
- latin:keyLabel="&#x25CC;&#x094B;"
- latin:code="0x094B"
- latin:moreKeys="&#x25CC;&#x094B;&#x0902;|&#x094B;&#x0902;,&#x25CC;&#x0949;,&#x094A;|&#x0949;,&#x094A;"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0947: "े" DEVANAGARI VOWEL SIGN E
- U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x25CC;&#x0947;"
- latin:code="0x0947"
- latin:moreKeys="&#x25CC;&#x0947;&#x0902;|&#x0947;&#x0902;"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+094D: "्" DEVANAGARI SIGN VIRAMA -->
- <Key
- latin:keyLabel="&#x25CC;&#x094D;"
- latin:code="0x094D"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+093F: "ि" DEVANAGARI VOWEL SIGN I
- U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
- <Key
- latin:keyLabel="&#x093F;&#x25CC;"
- latin:code="0x093F"
- latin:moreKeys="&#x093F;&#x25CC;&#x0902;|&#x093F;&#x0902;"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
- <!-- U+25CC: "◌" DOTTED CIRCLE
- U+0941: "ु" DEVANAGARI VOWEL SIGN U
- U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
- U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
- <Key
- latin:keyLabel="&#x25CC;&#x0941;"
- latin:code="0x0941"
- latin:moreKeys="&#x25CC;&#x0941;&#x0902;|&#x0941;&#x0902;,&#x25CC;&#x0941;&#x0901;|&#x0941;&#x0901;"
- latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
-</merge>
diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml
index bc9ecdf2f..56d0727dd 100644
--- a/java/res/xml/keys_less_greater.xml
+++ b/java/res/xml/keys_less_greater.xml
@@ -30,20 +30,24 @@
<Key
latin:keyLabel="&#x00AB;"
latin:code="0x00BB"
+ latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_less_than" />
<Key
latin:keyLabel="&#x00BB;"
latin:code="0x00AB"
+ latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_greater_than" />
</case>
<default>
<Key
latin:keyLabel="&lt;"
latin:code="!code/key_less_than"
+ latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_less_than" />
<Key
latin:keyLabel="&gt;"
latin:code="!code/key_greater_than"
+ latin:backgroundType="functional"
latin:moreKeys="!text/more_keys_for_greater_than" />
</default>
</switch>
diff --git a/java/res/xml/keys_pcqwerty2_right3.xml b/java/res/xml/keys_pcqwerty2_right3.xml
index 2065e6b46..6f86477da 100644
--- a/java/res/xml/keys_pcqwerty2_right3.xml
+++ b/java/res/xml/keys_pcqwerty2_right3.xml
@@ -27,25 +27,22 @@
>
<Key
latin:keyLabel="["
- latin:moreKeys="{" />
+ latin:additionalMoreKeys="{" />
<Key
latin:keyLabel="]"
- latin:moreKeys="}" />
- <!-- U+00A6: "¦" BROKEN BAR -->
+ latin:additionalMoreKeys="}" />
<Key
latin:keyLabel="\\"
- latin:moreKeys="\\|,&#x00A6;" />
+ latin:additionalMoreKeys="\\|" />
</case>
- <!-- keyboardLayoutSetElement="alphabet*Shifted|symbols*" -->
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<Key
latin:keyLabel="{" />
<Key
latin:keyLabel="}" />
- <!-- U+00A6: "¦" BROKEN BAR -->
<Key
- latin:keyLabel="|"
- latin:moreKeys="&#x00A6;" />
+ latin:keyLabel="|" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/keys_pcqwerty3_right2.xml b/java/res/xml/keys_pcqwerty3_right2.xml
index aa150afb3..8da145b20 100644
--- a/java/res/xml/keys_pcqwerty3_right2.xml
+++ b/java/res/xml/keys_pcqwerty3_right2.xml
@@ -27,12 +27,13 @@
>
<Key
latin:keyLabel=";"
- latin:moreKeys=":" />
+ latin:additionalMoreKeys=":" />
<Key
latin:keyLabel="\'"
- latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,&quot;,!text/single_quotes" />
+ latin:additionalMoreKeys="&quot;"
+ latin:moreKeys="!fixedColumnOrder!4,!text/double_quotes,%,!text/single_quotes" />
</case>
- <!-- keyboardLayoutSetElement="alphabet*Shifted|symbols*" -->
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<Key
latin:keyLabel=":" />
diff --git a/java/res/xml/keys_pcqwerty4_right3.xml b/java/res/xml/keys_pcqwerty4_right3.xml
index 7795b3d8b..e6084cb45 100644
--- a/java/res/xml/keys_pcqwerty4_right3.xml
+++ b/java/res/xml/keys_pcqwerty4_right3.xml
@@ -27,16 +27,16 @@
>
<Key
latin:keyLabel=","
- latin:moreKeys="&lt;" />
+ latin:additionalMoreKeys="&lt;" />
<Key
latin:keyLabel="."
- latin:moreKeys="&gt;" />
- <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
+ latin:additionalMoreKeys="&gt;" />
<Key
latin:keyLabel="/"
- latin:moreKeys="\?,&#x00BF;" />
+ latin:additionalMoreKeys="\?"
+ latin:moreKeys="!text/more_keys_for_symbols_question" />
</case>
- <!-- keyboardLayoutSetElement="alphabet*Shifted|symbols*" -->
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
<default>
<!-- U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
@@ -50,10 +50,9 @@
<Key
latin:keyLabel="&gt;"
latin:moreKeys="!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;" />
- <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
<Key
latin:keyLabel="\?"
- latin:moreKeys="&#x00BF;" />
+ latin:moreKeys="!text/more_keys_for_symbols_question" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/keys_pcqwerty_symbols2.xml b/java/res/xml/keys_pcqwerty_symbols2.xml
deleted file mode 100644
index d0ea984e8..000000000
--- a/java/res/xml/keys_pcqwerty_symbols2.xml
+++ /dev/null
@@ -1,59 +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"
->
- <!-- U+2022: "•" BULLET -->
- <Key
- latin:keyLabel="&#x2022;"
- latin:moreKeys="!text/more_keys_for_bullet" />
- <!-- U+00B1: "±" PLUS-MINUS SIGN -->
- <Key
- latin:keyLabel="&#x00B1;" />
- <!-- U+00AC: "¬" NOT SIGN -->
- <Key
- latin:keyLabel="&#x00AC;" />
- <!-- U+00A6: "¦" BROKEN BAR -->
- <Key
- latin:keyLabel="&#x00A6;" />
- <!-- U+221A: "√" SQUARE ROOT -->
- <Key
- latin:keyLabel="&#x221A;" />
- <!-- U+03C0: "π" GREEK SMALL LETTER PI
- U+03A0: "Π" GREEK CAPITAL LETTER PI -->
- <Key
- latin:keyLabel="&#x03C0;"
- latin:moreKeys="&#x03A0;" />
- <!-- U+03CC: "σ" GREEK SMALL LETTER SIGMA
- U+03A3: "Σ" GREEK CAPITAL LETTER SIGMA -->
- <Key
- latin:keyLabel="&#x03C3;"
- latin:moreKeys="&#x03A3;" />
- <!-- U+00B5: "µ" MICRO SIGN -->
- <Key
- latin:keyLabel="&#x00B5;" />
- <!-- U+00F7: "÷" DIVISION SIGN -->
- <Key
- latin:keyLabel="&#x00F7;" />
- <!-- U+00D7: "×" MULTIPLICATION SIGN -->
- <Key
- latin:keyLabel="&#x00D7;" />
-</merge>
diff --git a/java/res/xml/keys_pcqwerty_symbols3.xml b/java/res/xml/keys_pcqwerty_symbols3.xml
deleted file mode 100644
index 35279deaf..000000000
--- a/java/res/xml/keys_pcqwerty_symbols3.xml
+++ /dev/null
@@ -1,54 +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"
->
- <!-- U+00A3: "£" POUND SIGN; -->
- <Key
- latin:keyLabel="&#x00A3;" />
- <!-- U+00A2: "¢" CENT SIGN -->
- <Key
- latin:keyLabel="&#x00A2;" />
- <!-- U+20AC: "€" EURO SIGN -->
- <Key
- latin:keyLabel="&#x20AC;" />
- <!-- U+00A5: "¥" YEN SIGN -->
- <Key
- latin:keyLabel="&#x00A5;" />
- <!-- U+00A4: "¤" CURRENCY SIGN -->
- <Key
- latin:keyLabel="&#x00A4;" />
- <!-- U+00B0: "°" DEGREE SIGN
- U+2032: "′" PRIME
- U+2033: "″" DOUBLE PRIME -->
- <Key
- latin:keyLabel="&#x00B0;"
- latin:moreKeys="&#x2032;,&#x2033;" />
- <!-- U+2260: "≠" NOT EQUAL TO -->
- <Key
- latin:keyLabel="&#x2260;" />
- <!-- U+2248: "≈" ALMOST EQUAL TO -->
- <Key
- latin:keyLabel="&#x2248;" />
- <!-- U+221E: "∞" INFINITY -->
- <Key
- latin:keyLabel="&#x221E;" />
-</merge>
diff --git a/java/res/xml/keys_pcqwerty_symbols4.xml b/java/res/xml/keys_pcqwerty_symbols4.xml
deleted file mode 100644
index 3c628f0e0..000000000
--- a/java/res/xml/keys_pcqwerty_symbols4.xml
+++ /dev/null
@@ -1,49 +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"
->
- <!-- U+2122: "™" TRADE MARK SIGN -->
- <Key
- latin:keyLabel="&#x2122;" />
- <!-- U+00AE: "®" REGISTERED SIGN -->
- <Key
- latin:keyLabel="&#x00AE;" />
- <!-- U+00A9: "©" COPYRIGHT SIGN -->
- <Key
- latin:keyLabel="&#x00A9;" />
- <!-- U+00B6: "¶" PILCROW SIGN -->
- <Key
- latin:keyLabel="&#x00B6;" />
- <!-- U+00A7: "§" SECTION SIGN -->
- <Key
- latin:keyLabel="&#x00A7;" />
- <!-- U+2191: "↑" UPWARDS ARROW
- U+2193: "↓" DOWNWARDS ARROW
- U+2190: "←" LEFTWARDS ARROW
- U+2192: "→" RIGHTWARDS ARROW -->
- <Key
- latin:keyLabel="&#x2191;"
- latin:moreKeys="&#x2193;" />
- <Key
- latin:keyLabel="&#x2190;"
- latin:moreKeys="&#x2192;" />
-</merge>
diff --git a/java/res/xml/key_hindi3_shift_right.xml b/java/res/xml/keystyle_devanagari_sign_virama.xml
index 0da116ab8..b22fbe842 100644
--- a/java/res/xml/key_hindi3_shift_right.xml
+++ b/java/res/xml/keystyle_devanagari_sign_virama.xml
@@ -20,17 +20,16 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<!-- U+25CC: "◌" DOTTED CIRCLE
- U+0943: "ृ" DEVANAGARI VOWEL SIGN VOCALIC R
- U+0944: "ॄ" DEVANAGARI VOWEL SIGN VOCALIC RR -->
- <Key
- latin:keyLabel="&#x25CC;&#x0943;"
- latin:code="0x0943"
- latin:moreKeys="&#x25CC;&#x0944;|&#x0944;"
+ U+094D: "्" DEVANAGARI SIGN VIRAMA -->
+ <key-style
+ latin:styleName="baseKeyDevanagariSignVirama"
+ latin:keyLabel="&#x25CC;&#x094D;"
+ latin:code="0x094D"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
-</merge>
+ </merge>
diff --git a/java/res/xml/key_hindi1_shift.xml b/java/res/xml/keystyle_devanagari_sign_visarga.xml
index 0db5ae9af..cb294951f 100644
--- a/java/res/xml/key_hindi1_shift.xml
+++ b/java/res/xml/keystyle_devanagari_sign_visarga.xml
@@ -20,14 +20,15 @@
<!-- 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}_hindi*.xml have this U+25CC hack, although the
- counterpart files named res/xml-v16/{key,keys}_hindi*.xml don't have this hack. -->
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<!-- U+25CC: "◌" DOTTED CIRCLE
U+0903: "ः" DEVANAGARI SIGN VISARGA -->
- <Key
+ <key-style
+ latin:styleName="baseKeyDevanagariSignVisarga"
latin:keyLabel="&#x25CC;&#x0903;"
latin:code="0x0903"
latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
diff --git a/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml b/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml
new file mode 100644
index 000000000..2e78c53ec
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_aa.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093E/U+0902: "ां" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN ANUSVARA
+ U+093E/U+0901: "ाँ" DEVANAGARI VOWEL SIGN AA/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAa"
+ latin:moreKeys="&#x25CC;&#x093E;&#x0902;|&#x093E;&#x0902;,&#x25CC;&#x093E;&#x0901;|&#x093E;&#x0901;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAa" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093E: "ा" DEVANAGARI VOWEL SIGN AA -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAa"
+ latin:parentStyle="moreKeysDevanagariVowelSignAa"
+ latin:keyLabel="&#x25CC;&#x093E;"
+ latin:code="0x093E"
+ 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
new file mode 100644
index 000000000..0554c0e15
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_ai.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0948/U+0902: "ैं" DEVANAGARI VOWEL SIGN AI/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi"
+ latin:moreKeys="&#x25CC;&#x0948;&#x0902;|&#x0948;&#x0902;,%" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+0936/U+094D/U+0930: "श्र" DEVANAGARI LETTER SHA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER RA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi"
+ latin:moreKeys="&#x0936;&#x094D;&#x0930;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAi" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0948: "ै" DEVANAGARI VOWEL SIGN AI -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAi"
+ latin:parentStyle="moreKeysDevanagariVowelSignAi"
+ latin:keyLabel="&#x25CC;&#x0948;"
+ latin:code="0x0948"
+ 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
new file mode 100644
index 000000000..29a11a82e
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_au.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094C/U+0902: "ौं" DEVANAGARI VOWEL SIGN AU/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAu"
+ latin:moreKeys="&#x25CC;&#x094C;&#x0902;|&#x094C;&#x0902;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignAu" />
+ </default>
+ </switch>
+ <!-- U+094C: "ौ" DEVANAGARI VOWEL SIGN AU -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignAu"
+ latin:parentStyle="moreKeysDevanagariVowelSignAu"
+ latin:keyLabel="&#x25CC;&#x094C;"
+ latin:code="0x094C"
+ 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
new file mode 100644
index 000000000..edd29c791
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_e.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0947/U+0902: "ें" DEVANAGARI VOWEL SIGN E/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE"
+ latin:moreKeys="&#x25CC;&#x0947;&#x0902;|&#x0947;&#x0902;" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="nepali_traditional"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0903: "ः‍" DEVANAGARI SIGN VISARGA
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE"
+ latin:moreKeys="&#x25CC;&#x0903;|&#x0903;,&#x093D;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE" />
+ </default>
+ </switch>
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignE"
+ latin:parentStyle="moreKeysDevanagariVowelSignE"
+ latin:keyLabel="&#x25CC;&#x0947;"
+ latin:code="0x0947"
+ 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
new file mode 100644
index 000000000..200fed29f
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_i.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093F/U+0902: "िं" DEVANAGARI VOWEL SIGN I/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignI"
+ latin:moreKeys="&#x093F;&#x25CC;&#x0902;|&#x093F;&#x0902;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignI" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+093F: "ि" DEVANAGARI VOWEL SIGN I -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignI"
+ latin:parentStyle="moreKeysDevanagariVowelSignI"
+ latin:keyLabel="&#x25CC;&#x093F;"
+ latin:code="0x093F"
+ 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
new file mode 100644
index 000000000..6dc9951df
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_ii.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+0940: "ी" DEVANAGARI VOWEL SIGN II
+ U+0940/U+0902: "ीं" DEVANAGARI VOWEL SIGN II/DEVANAGARI SIGN ANUSVARA -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignIi"
+ latin:moreKeys="&#x25CC;&#x0940;&#x0902;|&#x0940;&#x0902;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignIi" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0940: "ी" DEVANAGARI VOWEL SIGN II -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignIi"
+ latin:parentStyle="moreKeysDevanagariVowelSignIi"
+ latin:keyLabel="&#x25CC;&#x0940;"
+ latin:code="0x0940"
+ 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
new file mode 100644
index 000000000..233ac8609
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_o.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094B/U+0902: "қं" DEVANAGARI VOWEL SIGN O/DEVANAGARI SIGN ANUSVARA
+ U+0949: "ॉ" DEVANAGARI VOWEL SIGN CANDRA O
+ U+094A: "ॊ" DEVANAGARI VOWEL SIGN SHORT O -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignO"
+ latin:moreKeys="&#x25CC;&#x094B;&#x0902;|&#x094B;&#x0902;,&#x25CC;&#x0949;|&#x0949;,&#x25CC;&#x094A;|&#x094A;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignO" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+094B: "ो" DEVANAGARI VOWEL SIGN O -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignO"
+ latin:parentStyle="moreKeysDevanagariVowelSignO"
+ latin:keyLabel="&#x25CC;&#x094B;"
+ latin:code="0x094B"
+ 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
new file mode 100644
index 000000000..7291b7099
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_u.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0941/U+0902: "ुं" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN ANUSVARA
+ U+0941/U+0901: "ुँ" DEVANAGARI VOWEL SIGN U/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignU"
+ latin:moreKeys="&#x25CC;&#x0941;&#x0902;|&#x0941;&#x0902;,&#x25CC;&#x0941;&#x0901;|&#x0941;&#x0901;" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignU" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0941: "ु" DEVANAGARI VOWEL SIGN U -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignU"
+ latin:parentStyle="moreKeysDevanagariVowelSignU"
+ latin:keyLabel="&#x25CC;&#x0941;"
+ latin:code="0x0941"
+ 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
new file mode 100644
index 000000000..a95ab822d
--- /dev/null
+++ b/java/res/xml/keystyle_devanagari_vowel_sign_uu.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- The code point U+25CC for key label is needed because the font rendering system prior to
+ API version 16 can't automatically render dotted circle for incomplete combining letter
+ of some scripts. The files named res/xml/key_*.xml have this U+25CC hack, although the
+ counterpart files named res/xml-v16/key_*.xml don't have this hack. -->
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSet="hindi"
+ >
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0942/U+0902: "ूं" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN ANUSVARA
+ U+0942/U+0901: "ूँ" DEVANAGARI VOWEL SIGN UU/DEVANAGARI SIGN CANDRABINDU -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignUu"
+ latin:moreKeys="&#x25CC;&#x0942;&#x0902;|&#x0942;&#x0902;,&#x25CC;&#x0942;&#x0901;|&#x0942;&#x0901;,%" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignUu" />
+ </default>
+ </switch>
+ <!-- U+25CC: "◌" DOTTED CIRCLE
+ U+0942: "ू" DEVANAGARI VOWEL SIGN UU -->
+ <key-style
+ latin:styleName="baseKeyDevanagariVowelSignUu"
+ latin:parentStyle="moreKeysDevanagariVowelSignUu"
+ latin:keyLabel="&#x25CC;&#x0942;"
+ latin:code="0x0942"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+</merge>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 52d715a7a..f0e04c220 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -24,7 +24,7 @@
keyboard_locale: script_name/keyboard_layout_set
af: Afrikaans/qwerty
ar: Arabic/arabic
- (az: Azerbaijani/qwerty) # disabled temporarily. waiting for strnig resources.
+ az: Azerbaijani/qwerty
be: Belarusian/east_slavic
bg: Bulgarian/bulgarian
bg: Bulgarian/bulgarian_bds
@@ -47,19 +47,24 @@
hi: Hindi/hindi
hr: Croatian/qwertz
hu: Hungarian/qwertz
+ hy: Armenian 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: Georgian/georgian
(kk: Kazakh/east_slavic) # disabled temporarily. waiting for strnig resources.
+ km: Khmer/khmer
ky: Kyrgyz/east_slavic
+ lo: Lao/lao
lt: Lithuanian/qwerty
lv: Latvian/qwerty
mk: Macedonian/south_slavic
mn: Mongolian/mongolian
ms: Malay/qwerty
nb: Norwegian Bokmål/nordic
+ ne: Nepali Romanized/nepali_romanized # disabled temporarily
+ ne: Nepali Traditional/nepali_traditional # disabled temporarily
nl: Dutch/qwerty
nl_BE: Dutch Belgium/azerty
pl: Polish/qwerty
@@ -80,6 +85,7 @@
vi: Vietnamese/qwerty
zu: Zulu/qwerty
zz: QWERTY/qwerty
+ (zz: Emoji/emoji)
-->
<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
<!-- Note: SupportTouchPositionCorrection extra value is obsolete and maintained for backward
@@ -89,427 +95,474 @@
<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">
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <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"
+ android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_en_GB"
android:subtypeId="0xb045e755"
android:imeSubtypeLocale="en_GB"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x6f972360"
android:imeSubtypeLocale="af"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x590dde40"
android:imeSubtypeLocale="ar"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
/>
- <!--
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x70b0f974"
android:imeSubtypeLocale="az"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- -->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x1dc3a859"
android:imeSubtypeLocale="be"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x0ba9c0e8"
android:imeSubtypeLocale="bg"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_bulgarian_bds"
android:subtypeId="0x5f51ba9a"
android:imeSubtypeLocale="bg"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xd2e520d5"
android:imeSubtypeLocale="ca"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x2d3d2ed0"
android:imeSubtypeLocale="cs"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x2df4605d"
android:imeSubtypeLocale="da"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x2e2cbe61"
android:imeSubtypeLocale="de"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x0e7802d3"
android:imeSubtypeLocale="el"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=greek"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=greek,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x4090554a"
android:imeSubtypeLocale="eo"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x30a6e00e"
android:imeSubtypeLocale="es"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_es_US"
android:subtypeId="0x84d2efc6"
android:imeSubtypeLocale="es_US"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
/>
<!--
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x623f9286"
android:imeSubtypeLocale="es_419"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
/>
-->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xec2d3955"
android:imeSubtypeLocale="et"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=nordic,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=nordic,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xbe66c254"
android:imeSubtypeLocale="fa"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=farsi"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=farsi,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x31cecda3"
android:imeSubtypeLocale="fi"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x324da12c"
android:imeSubtypeLocale="fr"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xeadbb691"
android:imeSubtypeLocale="fr_CA"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x39753b7f"
android:imeSubtypeLocale="hi"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x35b7526a"
android:imeSubtypeLocale="hr"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x35e198ed"
android:imeSubtypeLocale="hu"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
+ />
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0xe39ac3ca"
+ android:imeSubtypeLocale="hy"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=armenian_phonetic,EmojiCapable"
/>
<!-- Java uses the deprecated "in" code instead of the standard "id" code for Indonesian. -->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x7daea460"
android:imeSubtypeLocale="in"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x7df519e5"
android:imeSubtypeLocale="is"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x37885a0b"
android:imeSubtypeLocale="it"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
<!-- Java uses the deprecated "iw" code instead of the standard "he" code for Hebrew. -->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x66fb18bd"
android:imeSubtypeLocale="iw"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x6e119e6a"
android:imeSubtypeLocale="ka"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=georgian"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=georgian,EmojiCapable"
/>
<!--
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <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"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
/>
-->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0x1365683a"
+ android:imeSubtypeLocale="km"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=khmer,EmojiCapable"
+ />
+ <!-- android:subtypeId="Need this for km" -->
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x2e391c04"
android:imeSubtypeLocale="ky"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
+ />
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0x8315772c"
+ android:imeSubtypeLocale="lo"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=lao,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8321bb43"
android:imeSubtypeLocale="lt"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x833dea45"
android:imeSubtypeLocale="lv"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xaf50ab7c"
android:imeSubtypeLocale="mk"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xcdcfc3ab"
android:imeSubtypeLocale="mn"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x84c87c61"
android:imeSubtypeLocale="ms"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x3f12ee14"
android:imeSubtypeLocale="nb"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <!--
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0xd80a4cee"
+ android:imeSubtypeLocale="ne"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_romanized,EmojiCapable"
+ />
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_nepali_traditional"
+ android:subtypeId="0x5fafea88"
+ android:imeSubtypeLocale="ne"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_traditional,EmojiCapable"
+ />
+ -->
+ <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"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x500ca92c"
android:imeSubtypeLocale="nl_BE"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=azerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=azerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x43098a5c"
android:imeSubtypeLocale="pl"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xcafff4a6"
android:imeSubtypeLocale="pt_BR"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xe2fffc5a"
android:imeSubtypeLocale="pt_PT"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8d185978"
android:imeSubtypeLocale="ro"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x763a8752"
android:imeSubtypeLocale="ru"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8e94d413"
android:imeSubtypeLocale="sk"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8ea2eb94"
android:imeSubtypeLocale="sl"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x77c5196e"
android:imeSubtypeLocale="sr"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
/>
<!-- TODO: Uncomment once we can handle IETF language tag with script name specified.
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_serbian_cyrillic"
android:subtypeId="0xXXXXXXXX"
android:imeSubtypeLocale="sr"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_serbian_latin"
android:subtypeId="0xXXXXXXXX"
android:imeSubtypeLocale="sr-Latn"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
-->
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x48b4ff43"
android:imeSubtypeLocale="sv"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8f3dee1f"
android:imeSubtypeLocale="sw"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x1f94d5d4"
android:imeSubtypeLocale="th"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=thai"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=thai,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xf08285ef"
android:imeSubtypeLocale="tl"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=spanish,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x4a3179de"
android:imeSubtypeLocale="tr"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x3e84492c"
android:imeSubtypeLocale="uk"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x93972eee"
android:imeSubtypeLocale="vi"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x9b13ab76"
android:imeSubtypeLocale="zu"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
/>
- <subtype android:icon="@drawable/ic_subtype_keyboard"
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_no_language_qwerty"
android:subtypeId="0xa239ebad"
android:imeSubtypeLocale="zz"
android:imeSubtypeMode="keyboard"
- android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable,EmojiCapable"
/>
+ <!-- Emoji subtype has to be an addtional subtype added at boot time because ICS doesn't
+ support Emoji. -->
+ <!--
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_emoji"
+ android:subtypeId="0xc14d88b2"
+ android:imeSubtypeLocale="zz"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=emoji,EmojiCapable"
+ />
+ -->
</input-method>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 2a726c438..6c36b0e89 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -42,13 +42,11 @@
android:title="@string/popup_on_keypress"
android:persistent="true"
android:defaultValue="@bool/config_default_key_preview_popup" />
- <ListPreference
- android:key="voice_mode"
+ <CheckBoxPreference
+ android:key="pref_voice_input_key"
android:title="@string/voice_input"
android:persistent="true"
- android:entryValues="@array/voice_input_modes_values"
- android:entries="@array/voice_input_modes"
- android:defaultValue="@string/voice_mode_main" />
+ android:defaultValue="true" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/correction_category"
diff --git a/java/res/xml/row_dvorak4.xml b/java/res/xml/row_dvorak4.xml
index e6d487e1d..02a95acea 100644
--- a/java/res/xml/row_dvorak4.xml
+++ b/java/res/xml/row_dvorak4.xml
@@ -65,7 +65,7 @@
</switch>
<include
latin:keyXPos="25%p"
- latin:keyboardLayout="@xml/key_space" />
+ latin:keyboardLayout="@xml/key_space_5kw" />
<Key
latin:keyLabel="z"
latin:keyLabelFlags="hasPopupHint"
diff --git a/java/res/xml/row_pcqwerty5.xml b/java/res/xml/row_pcqwerty5.xml
index a8940af6e..4ec908ba1 100644
--- a/java/res/xml/row_pcqwerty5.xml
+++ b/java/res/xml/row_pcqwerty5.xml
@@ -24,36 +24,23 @@
<Row
latin:keyWidth="7.692%p"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="11.538%p" />
- </case>
- <!-- keyboardLayoutSetElement="alphabet*" -->
- <default>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyIcon="!icon/undefined"
- latin:keyLabel="!text/label_to_symbol_key_pcqwerty"
- latin:keyWidth="11.538%p" />
- </default>
- </switch>
+ <Spacer
+ latin:keyWidth="11.538%p" />
<switch>
<case
latin:shortcutKeyEnabled="true"
>
<Key
- latin:keyStyle="shortcutKeyStyle" />
- </case>
+ latin:keyStyle="shortcutKeyStyle"
+ latin:keyWidth="11.538%p" />
+ </case>
<case
latin:clobberSettingsKey="false"
>
<Key
- latin:keyStyle="settingsKeyStyle" />
- </case>
+ latin:keyStyle="settingsKeyStyle"
+ latin:keyWidth="11.538%p" />
+ </case>
</switch>
<switch>
<case
@@ -61,21 +48,33 @@
>
<Key
latin:keyStyle="languageSwitchKeyStyle"
- latin:keyXPos="19.230%p" />
+ latin:keyWidth="11.538%p" />
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="53.844%p" />
- </case>
+ latin:keyWidth="38.464%p" />
+ </case>
<!-- languageSwitchKeyEnabled="false" -->
<default>
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyXPos="19.230%p"
- latin:keyWidth="61.536%p" />
+ latin:keyWidth="50.002%p" />
</default>
</switch>
<Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyStyle="defaultEnterKeyStyle"
+ latin:keyWidth="15.384%p" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+ >
+ <Spacer />
+ </case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
+ <default>
+ <Key
+ latin:keyStyle="emojiKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
</Row>
</merge>
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index c29fbf2f1..578bc1234 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -31,7 +31,7 @@
latin:keyboardLayout="@xml/key_f1" />
<include
latin:keyXPos="25%p"
- latin:keyboardLayout="@xml/key_space" />
+ latin:keyboardLayout="@xml/key_space_5kw" />
<switch>
<case
latin:languageCode="ar|fa"
@@ -42,6 +42,21 @@
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" />
diff --git a/java/res/xml/row_symbols4.xml b/java/res/xml/row_symbols4.xml
index 150ad486c..0bf412fff 100644
--- a/java/res/xml/row_symbols4.xml
+++ b/java/res/xml/row_symbols4.xml
@@ -18,38 +18,29 @@
*/
-->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <Row
- latin:keyWidth="10%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="15%p" />
- <switch>
- <case
- latin:hasShortcutKey="true"
- >
- <Key
- latin:keyStyle="shortcutKeyStyle" />
- </case>
- <!-- latin:hasShortcutKey="false" -->
- <default>
- <Key
- latin:keyLabel="!text/keylabel_for_comma"
- latin:keyLabelFlags="hasPopupHint"
- latin:additionalMoreKeys="!text/more_keys_for_comma"
- latin:keyStyle="f1MoreKeysStyle" />
- </default>
- </switch>
- <include
- latin:keyXPos="25%p"
- latin:keyboardLayout="@xml/key_space" />
- <Key
- latin:keyStyle="punctuationKeyStyle" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
+<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" >
+
+ <Key
+ latin:backgroundType="functional"
+ latin:keyLabel="_" />
+ <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" />
+
+ <Key
+ latin:keyStyle="emojiKeyStyle"
+ latin:keyWidth="fillRight" />
+
</merge>
diff --git a/java/res/xml/row_symbols_shift4.xml b/java/res/xml/row_symbols_shift4.xml
index 99a685c45..72d24a321 100644
--- a/java/res/xml/row_symbols_shift4.xml
+++ b/java/res/xml/row_symbols_shift4.xml
@@ -17,31 +17,14 @@
** limitations under the License.
*/
-->
+<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" >
+
+ <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/key_f2" />
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <Row
- latin:keyWidth="10%p"
- >
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="15%p" />
- <!-- U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
- U+201E: "„" DOUBLE LOW-9 QUOTATION MARK -->
- <Key
- latin:keyLabel="&#x201E;"
- latin:moreKeys="&#x201A;"
- latin:backgroundType="functional" />
- <include
- latin:keyXPos="25%p"
- latin:keyboardLayout="@xml/key_space" />
- <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
- <Key
- latin:keyLabel="&#x2026;"
- latin:backgroundType="functional" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
</merge>
diff --git a/java/res/xml/rowkeys_armenian_phonetic1.xml b/java/res/xml/rowkeys_armenian_phonetic1.xml
new file mode 100644
index 000000000..1984fae8a
--- /dev/null
+++ b/java/res/xml/rowkeys_armenian_phonetic1.xml
@@ -0,0 +1,84 @@
+<?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+0567: "է" ARMENIAN SMALL LETTER EH -->
+ <Key
+ latin:keyLabel="&#x0567;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0569: "թ" ARMENIAN SMALL LETTER TO -->
+ <Key
+ latin:keyLabel="&#x0569;"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0583: "փ" ARMENIAN SMALL LETTER PIWR -->
+ <Key
+ latin:keyLabel="&#x0583;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0571: "ձ" ARMENIAN SMALL LETTER JA -->
+ <Key
+ latin:keyLabel="&#x0571;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+057B: "ջ" ARMENIAN SMALL LETTER JHEH -->
+ <Key
+ latin:keyLabel="&#x057B;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0580: "ր" ARMENIAN SMALL LETTER REH -->
+ <Key
+ latin:keyLabel="&#x0580;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0579: "չ" ARMENIAN SMALL LETTER CHA -->
+ <Key
+ latin:keyLabel="&#x0579;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0573: "ճ" ARMENIAN SMALL LETTER CHEH -->
+ <Key
+ latin:keyLabel="&#x0573;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+056A: "ժ" ARMENIAN SMALL LETTER ZHE -->
+ <Key
+ latin:keyLabel="&#x056A;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+056E: "ծ" ARMENIAN SMALL LETTER CA -->
+ <Key
+ latin:keyLabel="&#x056E;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/rowkeys_armenian_phonetic2.xml b/java/res/xml/rowkeys_armenian_phonetic2.xml
new file mode 100644
index 000000000..5dcabc301
--- /dev/null
+++ b/java/res/xml/rowkeys_armenian_phonetic2.xml
@@ -0,0 +1,66 @@
+<?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+0584: "ք" ARMENIAN SMALL LETTER KEH -->
+ <Key
+ latin:keyLabel="&#x0584;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0578: "ո" ARMENIAN SMALL LETTER VO -->
+ <Key
+ latin:keyLabel="&#x0578;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0565: "ե" ARMENIAN SMALL LETTER ECH
+ U+0587: "և" ARMENIAN SMALL LIGATURE ECH YIWN -->
+ <Key
+ latin:keyLabel="&#x0565;"
+ latin:moreKeys="&#x0587;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+057C: "ռ" ARMENIAN SMALL LETTER RA -->
+ <Key
+ latin:keyLabel="&#x057C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+057F: "տ" ARMENIAN SMALL LETTER TIWN -->
+ <Key
+ latin:keyLabel="&#x057F;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0568: "ը" ARMENIAN SMALL LETTER ET -->
+ <Key
+ latin:keyLabel="&#x0568;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0582: "ւ" ARMENIAN SMALL LETTER YIWN -->
+ <Key
+ latin:keyLabel="&#x0582;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+056B: "ի" ARMENIAN SMALL LETTER INI -->
+ <Key
+ latin:keyLabel="&#x056B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0585: "օ" ARMENIAN SMALL LETTER OH -->
+ <Key
+ latin:keyLabel="&#x0585;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+057A: "պ" ARMENIAN SMALL LETTER PEH -->
+ <Key
+ latin:keyLabel="&#x057A;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-sw768dp/rowkeys_thai_digits.xml b/java/res/xml/rowkeys_armenian_phonetic3.xml
index 55196ebc3..3116811b3 100644
--- a/java/res/xml-sw768dp/rowkeys_thai_digits.xml
+++ b/java/res/xml/rowkeys_armenian_phonetic3.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -21,44 +21,40 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0E51: "๑" THAI DIGIT ONE -->
+ <!-- U+0561: "ա" ARMENIAN SMALL LETTER AYB -->
<Key
- latin:keyLabel="&#x0E51;"
+ latin:keyLabel="&#x0561;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E52: "๒" THAI DIGIT TWO -->
+ <!-- U+057D: "ս" ARMENIAN SMALL LETTER SEH -->
<Key
- latin:keyLabel="&#x0E52;"
+ latin:keyLabel="&#x057D;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E53: "๓" THAI DIGIT THREE -->
+ <!-- U+0564: "դ" ARMENIAN SMALL LETTER DA -->
<Key
- latin:keyLabel="&#x0E53;"
+ latin:keyLabel="&#x0564;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E54: "๔" THAI DIGIT FOUR -->
+ <!-- U+0586: "ֆ" ARMENIAN SMALL LETTER FEH -->
<Key
- latin:keyLabel="&#x0E54;"
+ latin:keyLabel="&#x0586;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E55: "๕" THAI DIGIT FIVE -->
+ <!-- U+0563: "գ" ARMENIAN SMALL LETTER GIM -->
<Key
- latin:keyLabel="&#x0E55;"
+ latin:keyLabel="&#x0563;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E56: "๖" THAI DIGIT SIX -->
+ <!-- U+0570: "հ" ARMENIAN SMALL LETTER HO -->
<Key
- latin:keyLabel="&#x0E56;"
+ latin:keyLabel="&#x0570;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E57: "๗" THAI DIGIT SEVEN -->
+ <!-- U+0575: "յ" ARMENIAN SMALL LETTER YI -->
<Key
- latin:keyLabel="&#x0E57;"
+ latin:keyLabel="&#x0575;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E58: "๘" THAI DIGIT EIGHT -->
+ <!-- U+056F: "կ" ARMENIAN SMALL LETTER KEN -->
<Key
- latin:keyLabel="&#x0E58;"
+ latin:keyLabel="&#x056F;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0E59: "๙" THAI DIGIT NINE -->
+ <!-- U+056C: "լ" ARMENIAN SMALL LETTER LIWN -->
<Key
- latin:keyLabel="&#x0E59;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0E50: "๐" THAI DIGIT ZERO -->
- <Key
- latin:keyLabel="&#x0E50;"
+ latin:keyLabel="&#x056C;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_armenian_phonetic4.xml b/java/res/xml/rowkeys_armenian_phonetic4.xml
new file mode 100644
index 000000000..922481add
--- /dev/null
+++ b/java/res/xml/rowkeys_armenian_phonetic4.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0566: "զ" ARMENIAN SMALL LETTER ZA -->
+ <Key
+ latin:keyLabel="&#x0566;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0572: "ղ" ARMENIAN SMALL LETTER GHAD -->
+ <Key
+ latin:keyLabel="&#x0572;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0581: "ց" ARMENIAN SMALL LETTER CO -->
+ <Key
+ latin:keyLabel="&#x0581;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+057E: "վ" ARMENIAN SMALL LETTER VEW -->
+ <Key
+ latin:keyLabel="&#x057E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0562: "բ" ARMENIAN SMALL LETTER BEN -->
+ <Key
+ latin:keyLabel="&#x0562;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0576: "ն" ARMENIAN SMALL LETTER NOW -->
+ <Key
+ latin:keyLabel="&#x0576;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0574: "մ" ARMENIAN SMALL LETTER MEN -->
+ <Key
+ latin:keyLabel="&#x0574;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/rowkeys_hindi1.xml b/java/res/xml/rowkeys_hindi1.xml
index 745747643..c0b3cb913 100644
--- a/java/res/xml/rowkeys_hindi1.xml
+++ b/java/res/xml/rowkeys_hindi1.xml
@@ -62,10 +62,12 @@
latin:keyLabel="&#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 Hindi, different set of
- Key definitions are needed based on the API version. -->
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
<include
- latin:keyboardLayout="@xml/key_hindi1_shift" />
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_visarga" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVisarga" />
<!-- U+0918: "घ" DEVANAGARI LETTER GHA -->
<Key
latin:keyLabel="&#x0918;"
@@ -88,11 +90,57 @@
</case>
<default>
<!-- Because the font rendering system prior to API version 16 can't automatically
- render dotted circle for incomplete combining letter of Hindi, different set of
- Key definitions are needed based on the API version. -->
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAu"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="&#x0967;,1" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAi"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="&#x0968;,2" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+0969: "३" DEVANAGARI DIGIT THREE -->
<include
- latin:keyboardLayout="@xml/keys_hindi1_left5" />
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_aa" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAa"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="&#x0969;,3" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ii" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignIi"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="&#x096A;,4" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_uu" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignUu"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="&#x096B;,5" />
<!-- U+092C: "ब" DEVANAGARI LETTER BA
+ U+096C: "६" DEVANAGARI DIGIT SIX
U+092C/U+0952: "ब॒" DEVANAGARI LETTER BA/DEVANAGARI STRESS SIGN ANUDATTA -->
<Key
latin:keyLabel="&#x092C;"
diff --git a/java/res/xml/rowkeys_hindi2.xml b/java/res/xml/rowkeys_hindi2.xml
index 9545b840f..70ac66ee4 100644
--- a/java/res/xml/rowkeys_hindi2.xml
+++ b/java/res/xml/rowkeys_hindi2.xml
@@ -97,10 +97,40 @@
</case>
<default>
<!-- Because the font rendering system prior to API version 16 can't automatically
- render dotted circle for incomplete combining letter of Hindi, different set of
- Key definitions are needed based on the API version. -->
+ 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/keys_hindi2_left5" />
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_o" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignO" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignE" />
+ <!-- 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" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVirama" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_i" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignI" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_u" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignU" />
<!-- U+092A: "प" DEVANAGARI LETTER PA -->
<Key
latin:keyLabel="&#x092A;"
diff --git a/java/res/xml/rowkeys_hindi3.xml b/java/res/xml/rowkeys_hindi3.xml
index 3014907ed..136bc5f22 100644
--- a/java/res/xml/rowkeys_hindi3.xml
+++ b/java/res/xml/rowkeys_hindi3.xml
@@ -30,10 +30,10 @@
latin:keyLabel="&#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 Hindi, different set of
- Key definitions are needed based on the API version. -->
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
<include
- latin:keyboardLayout="@xml/key_hindi3_shift_left" />
+ latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
<!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
latin:keyLabel="&#x0923;"
@@ -56,10 +56,10 @@
latin:keyLabel="&#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 Hindi, different set of
- Key definitions are needed based on the API version. -->
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
<include
- latin:keyboardLayout="@xml/key_hindi3_shift_right" />
+ latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" />
<!-- U+091E: "ञ" DEVANAGARI LETTER NYA -->
<Key
latin:keyLabel="&#x091E;"
@@ -67,10 +67,12 @@
</case>
<default>
<!-- Because the font rendering system prior to API version 16 can't automatically
- render dotted circle for incomplete combining letter of Hindi, different set of
- Key definitions are needed based on the API version. -->
+ 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/keys_hindi3_left2" />
+ latin:keyboardLayout="@xml/key_devanagari_vowel_sign_candra_o" />
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
<!-- U+092E: "म" DEVANAGARI LETTER MA
U+0950: "ॐ" DEVANAGARI OM -->
<Key
@@ -107,10 +109,10 @@
latin:moreKeys="&#x095F;"
latin:keyLabelFlags="fontNormal" />
<!-- Because the font rendering system prior to API version 16 can't automatically
- render dotted circle for incomplete combining letter of Hindi, different set of
- Key definitions are needed based on the API version. -->
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
<include
- latin:keyboardLayout="@xml/key_hindi3_right" />
+ latin:keyboardLayout="@xml/key_devanagari_sign_nukta" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/rowkeys_khmer1.xml b/java/res/xml/rowkeys_khmer1.xml
new file mode 100644
index 000000000..25da66400
--- /dev/null
+++ b/java/res/xml/rowkeys_khmer1.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+200D: ZERO WIDTH JOINER -->
+ <Key
+ latin:keyLabel="!"
+ latin:moreKeys="!icon/zwj_key|&#x200D;" />
+ <!-- U+17D7: "ៗ" KHMER SIGN LEK TOO
+ U+200C: ZERO WIDTH NON-JOINER -->
+ <Key
+ latin:keyLabel="&#x17D7;"
+ latin:moreKeys="!icon/zwnj_key|&#x200C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17D1: "៑" KHMER SIGN VIRIAM -->
+ <Key
+ latin:keyLabel="&quot;"
+ latin:keyHintLabel="&#x17D1;"
+ latin:moreKeys="&#x17D1;" />
+ <!-- U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
+ U+20AC: "€" EURO SIGN -->
+ <Key
+ latin:keyLabel="&#x17DB;"
+ latin:keyHintLabel="$"
+ latin:moreKeys="$,&#x20AC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17D6: "៖" KHMER SIGN CAMNUC PII KUUH -->
+ <Key
+ latin:keyLabel="%"
+ latin:keyHintLabel="&#x17D6;"
+ latin:moreKeys="&#x17D6;" />
+ <!-- U+17CD: "៍" KHMER SIGN TOANDAKHIAT
+ U+17D9: "៙" KHMER SIGN PHNAEK MUAN -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="&#x17DA;"
+ latin:moreKeys="&#x17DA;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17CF: "៏" KHMER SIGN AHSDA -->
+ <Key
+ latin:keyLabel="&#x17CF;"
+ latin:keyHintLabel="*"
+ latin:moreKeys="*"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="("
+ latin:keyHintLabel="{"
+ latin:moreKeys="{,&#x00AB;" />
+ <!-- U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel=")"
+ latin:keyHintLabel="}"
+ latin:moreKeys="},&#x00BB;" />
+ <!-- U+17CC: "៌" KHMER SIGN ROBAT
+ U+00D7: "×" MULTIPLICATION SIGN -->
+ <Key
+ latin:keyLabel="&#x17CC;"
+ latin:keyHintLabel="&#x00D7;"
+ latin:moreKeys="&#x00D7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17CE: "៎" KHMER SIGN KAKABAT -->
+ <Key
+ latin:keyLabel="&#x17CE;"
+ latin:keyLabelFlags="fontNormal" />
+ </case>
+ <default>
+ <!-- U+17E1: "១" KHMER DIGIT ONE
+ U+17F1: "៱" KHMER SYMBOL LEK ATTAK MUOY -->
+ <Key
+ latin:keyLabel="&#x17E1;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1"
+ latin:moreKeys="&#x17F1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E2: "២" KHMER DIGIT TWO
+ U+17F2: "៲" KHMER SYMBOL LEK ATTAK PII -->
+ <Key
+ latin:keyLabel="&#x17E2;"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2"
+ latin:moreKeys="&#x17F2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E3: "៣" KHMER DIGIT THREE
+ U+17F3: "៳" KHMER SYMBOL LEK ATTAK BEI -->
+ <Key
+ latin:keyLabel="&#x17E3;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:moreKeys="&#x17F3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E4: "៤" KHMER DIGIT FOUR
+ U+17F4: "៴" KHMER SYMBOL LEK ATTAK BUON -->
+ <Key
+ latin:keyLabel="&#x17E4;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4"
+ latin:moreKeys="&#x17F4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E5: "៥" KHMER DIGIT FIVE
+ U+17F5: "៵" KHMER SYMBOL LEK ATTAK PRAM -->
+ <Key
+ latin:keyLabel="&#x17E5;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:moreKeys="&#x17F5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E6: "៦" KHMER DIGIT SIX
+ U+17F6: "៶" KHMER SYMBOL LEK ATTAK PRAM-MUOY -->
+ <Key
+ latin:keyLabel="&#x17E6;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:moreKeys="&#x17F6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E7: "៧" KHMER DIGIT SEVEN
+ U+17F7: "៷" KHMER SYMBOL LEK ATTAK PRAM-PII -->
+ <Key
+ latin:keyLabel="&#x17E7;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:moreKeys="&#x17F7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E8: "៨" KHMER DIGIT EIGHT
+ U+17F8: "៸" KHMER SYMBOL LEK ATTAK PRAM-BEI -->
+ <Key
+ latin:keyLabel="&#x17E8;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:moreKeys="&#x17F8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E9: "៩" KHMER DIGIT NINE
+ U+17F9: "៹" KHMER SYMBOL LEK ATTAK PRAM-BUON -->
+ <Key
+ latin:keyLabel="&#x17E9;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9"
+ latin:moreKeys="&#x17F9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17E0: "០" KHMER DIGIT ZERO
+ U+17F0: "៰" KHMER SYMBOL LEK ATTAK SON -->
+ <Key
+ latin:keyLabel="&#x17E0;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0"
+ latin:moreKeys="&#x17F0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17A5: "ឥ" KHMER INDEPENDENT VOWEL QI
+ U+17A6: "ឦ" KHMER INDEPENDENT VOWEL QII -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="&#x17B1;"
+ latin:moreKeys="&#x17B1;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_khmer2.xml b/java/res/xml/rowkeys_khmer2.xml
new file mode 100644
index 000000000..cba2d3b90
--- /dev/null
+++ b/java/res/xml/rowkeys_khmer2.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+1788: "ឈ" KHMER LETTER CHO
+ U+17DC: "ៜ" KHMER SIGN AVAKRAHASANYA -->
+ <Key
+ latin:keyLabel="&#x1788;"
+ latin:keyHintLabel="&#x17DC;"
+ latin:moreKeys="&#x17DC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BA: "ឺ" KHMER VOWEL SIGN YY
+ U+17DD: "៝" KHMER SIGN ATTHACAN -->
+ <Key
+ latin:keyLabel="&#x17BA;"
+ latin:keyHintLabel="&#x17DD;"
+ latin:moreKeys="&#x17DD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C2: "ែ" KHMER VOWEL SIGN AE -->
+ <Key
+ latin:keyLabel="&#x17C2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17AC: "ឬ" KHMER INDEPENDENT VOWEL RYY
+ U+17AB: "ឫ" KHMER INDEPENDENT VOWEL RY -->
+ <Key
+ latin:keyLabel="&#x17AC;"
+ latin:keyHintLabel="&#x17AB;"
+ latin:moreKeys="&#x17AB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1791: "ទ" KHMER LETTER TO -->
+ <Key
+ latin:keyLabel="&#x1791;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BD: "ួ" KHMER VOWEL SIGN UA -->
+ <Key
+ latin:keyLabel="&#x17BD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BC: "ូ" KHMER VOWEL SIGN UU -->
+ <Key
+ latin:keyLabel="&#x17BC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17B8: "ី" KHMER VOWEL SIGN II -->
+ <Key
+ latin:keyLabel="&#x17B8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C5: "ៅ" KHMER VOWEL SIGN AU -->
+ <Key
+ latin:keyLabel="&#x17C5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1797: "ភ" KHMER LETTER PHO -->
+ <Key
+ latin:keyLabel="&#x1797;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BF: "ឿ" KHMER VOWEL SIGN YA -->
+ <Key
+ latin:keyLabel="&#x17BF;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17B0: "ឰ" KHMER INDEPENDENT VOWEL QAI -->
+ <Key
+ latin:keyLabel="&#x17B0;"
+ latin:keyLabelFlags="fontNormal" />
+ </case>
+ <default>
+ <!-- U+1786: "ឆ" KHMER LETTER CHA -->
+ <Key
+ latin:keyLabel="&#x1786;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17B9: "ឹ" KHMER VOWEL SIGN Y -->
+ <Key
+ latin:keyLabel="&#x17B9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C1: "េ" KHMER VOWEL SIGN E -->
+ <Key
+ latin:keyLabel="&#x17C1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+179A: "រ" KHMER LETTER RO -->
+ <Key
+ latin:keyLabel="&#x179A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+178F: "ត" KHMER LETTER TA -->
+ <Key
+ latin:keyLabel="&#x178F;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1799: "យ" KHMER LETTER YO -->
+ <Key
+ latin:keyLabel="&#x1799;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BB: "ុ" KHMER VOWEL SIGN U -->
+ <Key
+ latin:keyLabel="&#x17BB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17B7: "ិ" KHMER VOWEL SIGN I -->
+ <Key
+ latin:keyLabel="&#x17B7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C4: "ោ" KHMER VOWEL SIGN OO -->
+ <Key
+ latin:keyLabel="&#x17C4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1795: "ផ" KHMER LETTER PHA -->
+ <Key
+ latin:keyLabel="&#x1795;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C0: "ៀ" KHMER VOWEL SIGN IE -->
+ <Key
+ latin:keyLabel="&#x17C0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17AA: "ឪ" KHMER INDEPENDENT VOWEL QUUV
+ U+17A7: "ឧ" KHMER INDEPENDENT VOWEL QU
+ U+17B1: "ឱ" KHMER INDEPENDENT VOWEL QOO TYPE ONE
+ U+17B3: "ឳ" KHMER INDEPENDENT VOWEL QAU
+ U+17A9: "ឩ" KHMER INDEPENDENT VOWEL QUU
+ U+17A8: "ឨ" KHMER INDEPENDENT VOWEL QUK -->
+ <Key
+ latin:keyLabel="&#x17AA;"
+ latin:keyHintLabel="&#x17A7;"
+ latin:moreKeys="&#x17A7;,&#x17B1;,&#x17B3;,&#x17A9;,&#x17A8;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_khmer3.xml b/java/res/xml/rowkeys_khmer3.xml
new file mode 100644
index 000000000..ff6c9ca51
--- /dev/null
+++ b/java/res/xml/rowkeys_khmer3.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+17B6/U+17C6: "ាំ" KHMER VOWEL SIGN AA/KHMER SIGN NIKAHIT -->
+ <Key
+ latin:keyLabel="&#x17B6;&#x17C6;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+17C3: "ៃ" KHMER VOWEL SIGN AI -->
+ <Key
+ latin:keyLabel="&#x17C3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+178C: "ឌ" KHMER LETTER DO -->
+ <Key
+ latin:keyLabel="&#x178C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1792: "ធ" KHMER LETTER THO -->
+ <Key
+ latin:keyLabel="&#x1792;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17A2: "អ" KHMER LETTER QA -->
+ <Key
+ latin:keyLabel="&#x17A2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C7: "ះ" KHMER SIGN REAHMUK
+ U+17C8: "ៈ" KHMER SIGN YUUKALEAPINTU;-->
+ <Key
+ latin:keyLabel="&#x17C7;"
+ latin:keyHintLabel="&#x17C8;"
+ latin:moreKeys="&#x17C8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1789: "ញ" KHMER LETTER NYO -->
+ <Key
+ latin:keyLabel="&#x1789;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1782: "គ" KHMER LETTER KO
+ U+179D: "ឝ" KHMER LETTER SHA -->
+ <Key
+ latin:keyLabel="&#x1782;"
+ latin:keyHintLabel="&#x179D;"
+ latin:moreKeys="&#x179D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17A1: "ឡ" KHMER LETTER LA -->
+ <Key
+ latin:keyLabel="&#x17A1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C4/U+17C7: "ោះ" KHMER VOWEL SIGN OO/KHMER SIGN REAHMUK -->
+ <Key
+ latin:keyLabel="&#x17C4;&#x17C7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C9: "៉" KHMER SIGN MUUSIKATOAN -->
+ <Key
+ latin:keyLabel="&#x17C9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17AF: "ឯ" KHMER INDEPENDENT VOWEL QE -->
+ <Key
+ latin:keyLabel="&#x17AF;"
+ latin:keyLabelFlags="fontNormal" />
+ </case>
+ <default>
+ <!-- U+17B6: "ា" KHMER VOWEL SIGN AA -->
+ <Key
+ latin:keyLabel="&#x17B6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+179F: "ស" KHMER LETTER SA -->
+ <Key
+ latin:keyLabel="&#x179F;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+178A: "ដ" KHMER LETTER DA -->
+ <Key
+ latin:keyLabel="&#x178A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1790: "ថ" KHMER LETTER THA -->
+ <Key
+ latin:keyLabel="&#x1790;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1784: "ង" KHMER LETTER NGO -->
+ <Key
+ latin:keyLabel="&#x1784;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17A0: "ហ" KHMER LETTER HA -->
+ <Key
+ latin:keyLabel="&#x17A0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17D2: "្" KHMER SIGN COENG -->
+ <Key
+ latin:keyLabel="&#x17D2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1780: "ក" KHMER LETTER KA -->
+ <Key
+ latin:keyLabel="&#x1780;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+179B: "ល" KHMER LETTER LO -->
+ <Key
+ latin:keyLabel="&#x179B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BE: "ើ" KHMER VOWEL SIGN OE -->
+ <Key
+ latin:keyLabel="&#x17BE;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17CB: "់" KHMER SIGN BANTOC -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="&#x17AD;"
+ latin:moreKeys="&#x17AD;,&#x17B0;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_khmer4.xml b/java/res/xml/rowkeys_khmer4.xml
new file mode 100644
index 000000000..fe6c59125
--- /dev/null
+++ b/java/res/xml/rowkeys_khmer4.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+178D: "ឍ" KHMER LETTER TTHO -->
+ <Key
+ latin:keyLabel="&#x178D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1783: "ឃ" KHMER LETTER KHO -->
+ <Key
+ latin:keyLabel="&#x1783;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1787: "ជ" KHMER LETTER CO -->
+ <Key
+ latin:keyLabel="&#x1787;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C1/U+17C7: "េះ" KHMER VOWEL SIGN E/KHMER SIGN REAHMUK -->
+ <Key
+ latin:keyLabel="&#x17C1;&#x17C7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1796: "ព" KHMER LETTER PO
+ U+179E: "ឞ" KHMER LETTER SSO -->
+ <Key
+ latin:keyLabel="&#x1796;"
+ latin:keyHintLabel="&#x179E;"
+ latin:moreKeys="&#x179E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+178E: "ណ" KHMER LETTER NNO -->
+ <Key
+ latin:keyLabel="&#x178E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17C6: "ំ" KHMER SIGN NIKAHIT -->
+ <Key
+ latin:keyLabel="&#x17C6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BB/U+17C7: "ុះ" KHMER VOWEL SIGN U/KHMER SIGN REAHMUK -->
+ <Key
+ latin:keyLabel="&#x17BB;&#x17C7;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+17D5: "៕" KHMER SIGN BARIYOOSAN -->
+ <Key
+ latin:keyLabel="&#x17D5;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="\?" />
+ </case>
+ <default>
+ <!-- U+178B: "ឋ" KHMER LETTER TTHA -->
+ <Key
+ latin:keyLabel="&#x178B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1781: "ខ" KHMER LETTER KHA -->
+ <Key
+ latin:keyLabel="&#x1781;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1785: "ច" KHMER LETTER CA -->
+ <Key
+ latin:keyLabel="&#x1785;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+179C: "វ" KHMER LETTER VO -->
+ <Key
+ latin:keyLabel="&#x179C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1794: "ប" KHMER LETTER BA -->
+ <Key
+ latin:keyLabel="&#x1794;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1793: "ន" KHMER LETTER NO -->
+ <Key
+ latin:keyLabel="&#x1793;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+1798: "ម" KHMER LETTER MO -->
+ <Key
+ latin:keyLabel="&#x1798;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17BB/U+17C6: "ុំ" KHMER VOWEL SIGN U/KHMER SIGN NIKAHIT -->
+ <Key
+ latin:keyLabel="&#x17BB;&#x17C6;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+17D4: "។" KHMER SIGN KHAN -->
+ <Key
+ latin:keyLabel="&#x17D4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+17CA: "៊" KHMER SIGN TRIISAP -->
+ <Key
+ latin:keyLabel="&#x17CA;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao1.xml b/java/res/xml/rowkeys_lao1.xml
new file mode 100644
index 000000000..fa1ad97d8
--- /dev/null
+++ b/java/res/xml/rowkeys_lao1.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0ED1: "໑" LAO DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x0ED1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED2: "໒" LAO DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x0ED2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED3: "໓" LAO DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x0ED3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED4: "໔" LAO DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x0ED4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECC: "໌" LAO CANCELLATION MARK -->
+ <Key
+ latin:keyLabel="&#x0ECC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EBC: "ຼ" LAO SEMIVOWEL SIGN LO -->
+ <Key
+ latin:keyLabel="&#x0EBC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED5: "໕" LAO DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x0ED5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED6: "໖" LAO DIGIT SIX -->
+ <Key
+ latin:keyLabel="&#x0ED6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED7: "໗" LAO DIGIT SEVEN -->
+ <Key
+ latin:keyLabel="&#x0ED7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED8: "໘" LAO DIGIT EIGHT -->
+ <Key
+ latin:keyLabel="&#x0ED8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED9: "໙" LAO DIGIT NINE -->
+ <Key
+ latin:keyLabel="&#x0ED9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECD/U+0EC8: "ໍ່" LAO NIGGAHITA/LAO TONE MAI EK -->
+ <Key
+ latin:keyLabel="&#x0ECD;&#x0EC8;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ </case>
+ <default>
+ <!-- U+0EA2: "ຢ" LAO LETTER YO
+ U+0ED1: "໑" LAO DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x0EA2;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1"
+ latin:moreKeys="&#x0ED1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9F: "ຟ" LAO LETTER FO SUNG
+ U+0ED2: "໒" LAO DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x0E9F;"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2"
+ latin:moreKeys="&#x0ED2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC2: "ໂ" LAO VOWEL SIGN O
+ U+0ED3: "໓" LAO DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x0EC2;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:moreKeys="&#x0ED3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E96: "ຖ" LAO LETTER THO SUNG
+ U+0ED4: "໔" LAO DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x0E96;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4"
+ latin:moreKeys="&#x0ED4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB8: "ຸ" LAO VOWEL SIGN U -->
+ <Key
+ latin:keyLabel="&#x0EB8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB9: "ູ" LAO VOWEL SIGN UU -->
+ <Key
+ latin:keyLabel="&#x0EB9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E84: "ຄ" LAO LETTER KHO TAM
+ U+0ED5: "໕" LAO DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x0E84;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:moreKeys="&#x0ED5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E95: "ຕ" LAO LETTER TO
+ U+0ED6: "໖" LAO DIGIT SIX -->
+ <Key
+ latin:keyLabel="&#x0E95;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:moreKeys="&#x0ED6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E88: "ຈ" LAO LETTER CO
+ U+0ED7: "໗" LAO DIGIT SEVEN -->
+ <Key
+ latin:keyLabel="&#x0E88;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:moreKeys="&#x0ED7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E82: "ຂ" LAO LETTER KHO SUNG
+ U+0ED8: "໘" LAO DIGIT EIGHT -->
+ <Key
+ latin:keyLabel="&#x0E82;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:moreKeys="&#x0ED8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E8A: "ຊ" LAO LETTER SO TAM
+ U+0ED9: "໙" LAO DIGIT NINE -->
+ <Key
+ latin:keyLabel="&#x0E8A;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9"
+ latin:moreKeys="&#x0ED9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECD: "ໍ" LAO NIGGAHITA -->
+ <Key
+ latin:keyLabel="&#x0ECD;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao2.xml b/java/res/xml/rowkeys_lao2.xml
new file mode 100644
index 000000000..fca58ac0e
--- /dev/null
+++ b/java/res/xml/rowkeys_lao2.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0EBB/U+0EC9: "" LAO VOWEL SIGN MAI KON/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EBB;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0ED0: "໐" LAO DIGIT ZERO -->
+ <Key
+ latin:keyLabel="&#x0ED0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB3/U+0EC9: "ຳ້" LAO VOWEL SIGN AM/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB3;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <Key
+ latin:keyLabel="_" />
+ <Key
+ latin:keyLabel="+" />
+ <!-- U+0EB4/U+0EC9: "ິ້" LAO VOWEL SIGN I/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB4;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EB5/U+0EC9: "ີ້" LAO VOWEL SIGN II/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB5;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EA3: "ຣ" LAO LETTER LO LING -->
+ <Key
+ latin:keyLabel="&#x0EA3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EDC: "ໜ" LAO HO NO -->
+ <Key
+ latin:keyLabel="&#x0EDC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EBD: "ຽ" LAO SEMIVOWEL SIGN NYO -->
+ <Key
+ latin:keyLabel="&#x0EBD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAB/U+0EBC: "" LAO LETTER HO SUNG/LAO SEMIVOWEL SIGN LO -->
+ <Key
+ latin:keyLabel="&#x0EAB;&#x0EBC;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+201D: "”" RIGHT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201D;" />
+ </case>
+ <default>
+ <!-- U+0EBB: "ົ" LAO VOWEL SIGN MAI KON -->
+ <Key
+ latin:keyLabel="&#x0EBB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC4: "ໄ" LAO VOWEL SIGN AI
+ U+0ED0: "໐" LAO DIGIT ZERO -->
+ <Key
+ latin:keyLabel="&#x0EC4;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0"
+ latin:moreKeys="&#x0ED0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB3: "ຳ" LAO VOWEL SIGN AM -->
+ <Key
+ latin:keyLabel="&#x0EB3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9E: "ພ" LAO LETTER PHO TAM -->
+ <Key
+ latin:keyLabel="&#x0E9E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB0: "ະ" LAO VOWEL SIGN A -->
+ <Key
+ latin:keyLabel="&#x0EB0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB4: "ິ" LAO VOWEL SIGN I -->
+ <Key
+ latin:keyLabel="&#x0EB4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB5: "ີ" LAO VOWEL SIGN II -->
+ <Key
+ latin:keyLabel="&#x0EB5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAE: "ຮ" LAO LETTER HO TAM -->
+ <Key
+ latin:keyLabel="&#x0EAE;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E99: "ນ" LAO LETTER NO -->
+ <Key
+ latin:keyLabel="&#x0E99;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E8D: "ຍ" LAO LETTER NYO -->
+ <Key
+ latin:keyLabel="&#x0E8D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9A: "ບ" LAO LETTER BO -->
+ <Key
+ latin:keyLabel="&#x0E9A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA5: "ລ" LAO LETTER LO LOOT -->
+ <Key
+ latin:keyLabel="&#x0EA5;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao3.xml b/java/res/xml/rowkeys_lao3.xml
new file mode 100644
index 000000000..2a6c2d1dd
--- /dev/null
+++ b/java/res/xml/rowkeys_lao3.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0EB1/U+0EC9: "ັ້" LAO VOWEL SIGN MAI KAN/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB1;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <Key
+ latin:keyLabel=";" />
+ <Key
+ latin:keyLabel="." />
+ <Key
+ latin:keyLabel="," />
+ <Key
+ latin:keyLabel=":" />
+ <!-- U+0ECA: "໊" LAO TONE MAI TI -->
+ <Key
+ latin:keyLabel="&#x0ECA;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECB: "໋" LAO TONE MAI CATAWA -->
+ <Key
+ latin:keyLabel="&#x0ECB;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="!" />
+ <Key
+ latin:keyLabel="\?" />
+ <Key
+ latin:keyLabel="%" />
+ <Key
+ latin:keyLabel="=" />
+ <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201C;" />
+ </case>
+ <default>
+ <!-- U+0EB1: "ັ" LAO VOWEL SIGN MAI KAN -->
+ <Key
+ latin:keyLabel="&#x0EB1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAB: "ຫ" LAO LETTER HO SUNG -->
+ <Key
+ latin:keyLabel="&#x0EAB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E81: "ກ" LAO LETTER KO -->
+ <Key
+ latin:keyLabel="&#x0E81;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E94: "ດ" LAO LETTER DO -->
+ <Key
+ latin:keyLabel="&#x0E94;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC0: "ເ" LAO VOWEL SIGN E -->
+ <Key
+ latin:keyLabel="&#x0EC0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC9: "້" LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EC9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC8: "່" LAO TONE MAI EK -->
+ <Key
+ latin:keyLabel="&#x0EC8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB2: "າ" LAO VOWEL SIGN AA -->
+ <Key
+ latin:keyLabel="&#x0EB2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAA: "ສ" LAO LETTER SO SUNG -->
+ <Key
+ latin:keyLabel="&#x0EAA;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA7: "ວ" LAO LETTER WO -->
+ <Key
+ latin:keyLabel="&#x0EA7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E87: "ງ" LAO LETTER NGO -->
+ <Key
+ latin:keyLabel="&#x0E87;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201C;" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao4.xml b/java/res/xml/rowkeys_lao4.xml
new file mode 100644
index 000000000..fae9cc923
--- /dev/null
+++ b/java/res/xml/rowkeys_lao4.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+20AD: "₭" KIP SIGN -->
+ <Key
+ latin:keyLabel="&#x20AD;" />
+ <Key
+ latin:keyLabel="(" />
+ <!-- U+0EAF: "ຯ" LAO ELLIPSIS -->
+ <Key
+ latin:keyLabel="&#x0EAF;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="\@" />
+ <!-- U+0EB6/U+0EC9: "ຶ້" LAO VOWEL SIGN Y/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB6;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EB7/U+0EC9: "ື້" LAO VOWEL SIGN YY/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB7;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EC6: "ໆ" LAO KO LA -->
+ <Key
+ latin:keyLabel="&#x0EC6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EDD: "ໝ" LAO HO MO -->
+ <Key
+ latin:keyLabel="&#x0EDD;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="$" />
+ <Key
+ latin:keyLabel=")" />
+ </case>
+ <default>
+ <!-- U+0E9C: "ຜ" LAO LETTER PHO SUNG -->
+ <Key
+ latin:keyLabel="&#x0E9C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9B: "ປ" LAO LETTER PO -->
+ <Key
+ latin:keyLabel="&#x0E9B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC1: "ແ" LAO VOWEL SIGN EI -->
+ <Key
+ latin:keyLabel="&#x0EC1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAD: "ອ" LAO LETTER O -->
+ <Key
+ latin:keyLabel="&#x0EAD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB6: "ຶ" LAO VOWEL SIGN Y -->
+ <Key
+ latin:keyLabel="&#x0EB6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB7: "ື" LAO VOWEL SIGN YY -->
+ <Key
+ latin:keyLabel="&#x0EB7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E97: "ທ" LAO LETTER THO TAM -->
+ <Key
+ latin:keyLabel="&#x0E97;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA1: "ມ" LAO LETTER MO -->
+ <Key
+ latin:keyLabel="&#x0EA1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC3: "ໃ" LAO VOWEL SIGN AY -->
+ <Key
+ latin:keyLabel="&#x0EC3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9D: "ຝ" LAO LETTER FO TAM -->
+ <Key
+ latin:keyLabel="&#x0E9D;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_romanized1.xml b/java/res/xml/rowkeys_nepali_romanized1.xml
new file mode 100644
index 000000000..408a96648
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_romanized1.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0920: "ठ" DEVANAGARI LETTER TTHA -->
+ <Key
+ latin:keyLabel="&#x0920;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0914: "औ" DEVANAGARI LETTER AU -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAi" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" />
+ <!-- U+0925: "थ" DEVANAGARI LETTER THA -->
+ <Key
+ latin:keyLabel="&#x0925;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091E: "ञ" DEVANAGARI LETTER NYA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_uu" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignUu" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ii" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignIi" />
+ <!-- U+0913: "ओ" DEVANAGARI LETTER O -->
+ <Key
+ latin:keyLabel="&#x0913;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092B: "फ" DEVANAGARI LETTER PHA -->
+ <Key
+ latin:keyLabel="&#x092B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0908: "ई" DEVANAGARI LETTER II -->
+ <Key
+ latin:keyLabel="&#x0908;"
+ latin:keyLabelFlags="fontNormal" />
+ </case>
+ <default>
+ <!-- U+091F: "ट" DEVANAGARI LETTER TTA
+ U+0967: "१" DEVANAGARI DIGIT ONE
+ U+093C: "़" DEVANAGARI SIGN NUKTA -->
+ <Key
+ latin:keyLabel="&#x091F;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="&#x0967;,1"
+ latin:moreKeys="&#x093C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAu"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="&#x0968;,2" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignE"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="&#x0969;,3" />
+ <!-- U+0930: "र" DEVANAGARI LETTER RA
+ U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="5"
+ latin:additionalMoreKeys="&#x096B;,5"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092F: "य" DEVANAGARI LETTER YA
+ U+096C: "६" DEVANAGARI DIGIT SIX -->
+ <Key
+ latin:keyLabel="&#x092F;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="&#x096C;,6"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_u" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignU"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="&#x096D;,7" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_i" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignI"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="&#x096E;,8" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+096F: "९" DEVANAGARI DIGIT NINE -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_o" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignO"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="&#x096F;,9" />
+ <!-- U+092A: "प" DEVANAGARI LETTER PA
+ U+0966: "०" DEVANAGARI DIGIT ZERO -->
+ <Key
+ latin:keyLabel="&#x092A;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="&#x0966;,0"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0907: "इ" DEVANAGARI LETTER I -->
+ <Key
+ latin:keyLabel="&#x0907;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_romanized2.xml b/java/res/xml/rowkeys_nepali_romanized2.xml
new file mode 100644
index 000000000..66359ffb5
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_romanized2.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0906: "आ" DEVANAGARI LETTER AA -->
+ <Key
+ latin:keyLabel="&#x0906;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0936: "श" DEVANAGARI LETTER SHA -->
+ <Key
+ latin:keyLabel="&#x0936;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0927: "ध" DEVANAGARI LETTER DHA -->
+ <Key
+ latin:keyLabel="&#x0927;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+090A: "ऊ" DEVANAGARI LETTER UU -->
+ <Key
+ latin:keyLabel="&#x090A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0918: "घ" DEVANAGARI LETTER GHA -->
+ <Key
+ latin:keyLabel="&#x0918;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0905: "अ" DEVANAGARI LETTER A -->
+ <Key
+ latin:keyLabel="&#x0905;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091D: "झ" DEVANAGARI LETTER JHA -->
+ <Key
+ latin:keyLabel="&#x091D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
+ <Key
+ latin:keyLabel="&#x0916;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0965: "॥" DEVANAGARI DOUBLE DANDA -->
+ <Key
+ latin:keyLabel="&#x0965;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0910: "ऐ" DEVANAGARI LETTER AI -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_visarga" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVisarga" />
+ </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_vowel_sign_aa" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAa" />
+ <!-- U+0938: "स" DEVANAGARI LETTER SA -->
+ <Key
+ latin:keyLabel="&#x0938;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0926: "द" DEVANAGARI LETTER DA -->
+ <Key
+ latin:keyLabel="&#x0926;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0909: "उ" DEVANAGARI LETTER U -->
+ <Key
+ latin:keyLabel="&#x0909;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0917: "ग" DEVANAGARI LETTER GA -->
+ <Key
+ latin:keyLabel="&#x0917;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0939: "ह" DEVANAGARI LETTER HA -->
+ <Key
+ latin:keyLabel="&#x0939;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091C: "ज" DEVANAGARI LETTER JA -->
+ <Key
+ latin:keyLabel="&#x091C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0915: "क" DEVANAGARI LETTER KA -->
+ <Key
+ latin:keyLabel="&#x0915;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0932: "ल" DEVANAGARI LETTER LA -->
+ <Key
+ latin:keyLabel="&#x0932;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+090F: "ए" DEVANAGARI LETTER E -->
+ <Key
+ latin:keyLabel="&#x090F;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0950: "ॐ" DEVANAGARI OM -->
+ <Key
+ latin:keyLabel="&#x0950;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_romanized3.xml b/java/res/xml/rowkeys_nepali_romanized3.xml
new file mode 100644
index 000000000..166d028a3
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_romanized3.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
+ <Key
+ latin:keyLabel="&#x090B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0922: "ढ" DEVANAGARI LETTER DDHA -->
+ <Key
+ latin:keyLabel="&#x0922;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091B: "छ" DEVANAGARI LETTER CHA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
+ <!-- U+092D: "भ" DEVANAGARI LETTER BHA -->
+ <Key
+ latin:keyLabel="&#x092D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
+ <!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVirama" />
+ </case>
+ <default>
+ <!-- U+0937: "ष" DEVANAGARI LETTER SSA -->
+ <Key
+ latin:keyLabel="&#x0937;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0921: "ड" DEVANAGARI LETTER DDA -->
+ <Key
+ latin:keyLabel="&#x0921;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091A: "च" DEVANAGARI LETTER CA -->
+ <Key
+ latin:keyLabel="&#x091A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0935: "व" DEVANAGARI LETTER VA -->
+ <Key
+ latin:keyLabel="&#x0935;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092C: "ब" DEVANAGARI LETTER BHA -->
+ <Key
+ latin:keyLabel="&#x092C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0928: "न" DEVANAGARI LETTER NA -->
+ <Key
+ latin:keyLabel="&#x0928;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092E: "म" DEVANAGARI LETTER MA -->
+ <Key
+ latin:keyLabel="&#x092E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0964: "।" DEVANAGARI DANDA
+ U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <Key
+ latin:keyLabel="&#x0964;"
+ latin:moreKeys="&#x093D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVirama" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional1.xml b/java/res/xml/rowkeys_nepali_traditional1.xml
new file mode 100644
index 000000000..c7883c733
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_traditional1.xml
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0924/U+094D/U+0924: "त्त" DEVANAGARI LETTER TA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER TA
+ U+091E: "ञ" DEVANAGARI LETTER NYA
+ U+091C/U+094D/U+091E: "ज्ञ" DEVANAGARI LETTER JA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER NYA
+ U+0965: "॥" DEVANAGARI DOUBLE DANDA -->
+ <Key
+ latin:keyLabel="&#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:moreKeys="&#x0908;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0910: "ऐ" DEVANAGARI LETTER AI
+ U+0918: "घ" DEVANAGARI LETTER GHA -->
+ <Key
+ latin:keyLabel="&#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: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: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:moreKeys="&#x091F;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+090A: "ऊ" DEVANAGARI LETTER UU
+ U+0920: "ठ" DEVANAGARI LETTER TTHA -->
+ <Key
+ latin:keyLabel="&#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:moreKeys="&#x0921;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0907: "इ" DEVANAGARI LETTER I
+ U+0922: "ढ" DEVANAGARI LETTER DDHA -->
+ <Key
+ latin:keyLabel="&#x0907;"
+ latin:moreKeys="&#x0922;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+090F: "ए" DEVANAGARI LETTER E
+ U+0923: "ण" DEVANAGARI LETTER NNA -->
+ <Key
+ latin:keyLabel="&#x090F;"
+ latin:moreKeys="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_vowel_sign_vocalic_r" />
+ </case>
+ <default>
+ <!-- U+091F: "ट" DEVANAGARI LETTER TTA
+ U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="2"
+ latin:additionalMoreKeys="&#x0968;,2"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092D: "भ" DEVANAGARI LETTER BHA
+ U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="4"
+ latin:additionalMoreKeys="&#x096A;,4"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0924: "त" DEVANAGARI LETTER TA
+ U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="6"
+ latin:additionalMoreKeys="&#x096C;,6"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0917: "ग" DEVANAGARI LETTER G
+ U+096D: "७" DEVANAGARI DIGIT SEVEN -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="8"
+ latin:additionalMoreKeys="&#x096E;,8"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092F: "य" DEVANAGARI LETTER YA
+ U+096F: "९" DEVANAGARI DIGIT NINE -->
+ <Key
+ latin:keyLabel="&#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:keyHintLabel="0"
+ latin:additionalMoreKeys="&#x0966;,0"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0907: "इ" DEVANAGARI LETTER I
+ U+0914: "औ" DEVANAGARI LETTER AU -->
+ <Key
+ latin:keyLabel="&#x0907;"
+ latin:moreKeys="&#x0914;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional2.xml b/java/res/xml/rowkeys_nepali_traditional2.xml
new file mode 100644
index 000000000..45620a9d7
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_traditional2.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0906: "आ" DEVANAGARI LETTER AA -->
+ <Key
+ latin:keyLabel="&#x0906;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0919/U+094D: "ङ्" DEVANAGARI LETTER NGA/DEVANAGARI SIGN VIRAMA -->
+ <Key
+ latin:keyLabel="&#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:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_candrabindu" />
+ <!-- U+0926/U+094D/U+0926: "द्द" DEVANAGARI LETTER DA/DEVANAGARI SIGN VIRAMA/DEVANAGARI LETTER DA -->
+ <Key
+ latin:keyLabel="&#x0926;&#x094D;&#x0926;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+091D: "झ" DEVANAGARI LETTER JHA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_o" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignO" />
+ <!-- U+092B: "फ" DEVANAGARI LETTER PHA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ii" />
+ <Key
+ 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:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_uu" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignUu" />
+ </case>
+ <default>
+ <!-- U+092C: "ब" DEVANAGARI LETTER BA -->
+ <Key
+ latin:keyLabel="&#x092C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0915: "क" DEVANAGARI LETTER KA -->
+ <Key
+ latin:keyLabel="&#x0915;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092E: "म" DEVANAGARI LETTER MA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_aa" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAa" />
+ <!-- U+0928: "न" DEVANAGARI LETTER NA -->
+ <Key
+ latin:keyLabel="&#x0928;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+091C: "ज" DEVANAGARI LETTER JA -->
+ <Key
+ latin:keyLabel="&#x091C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0935: "व" DEVANAGARI LETTER VA -->
+ <Key
+ latin:keyLabel="&#x0935;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+092A: "प" DEVANAGARI LETTER PA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_i" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignI" />
+ <!-- U+0938: "स" DEVANAGARI LETTER SA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_u" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignU" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_left6.xml b/java/res/xml/rowkeys_nepali_traditional3_left6.xml
new file mode 100644
index 000000000..1cacced83
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_traditional3_left6.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0915/U+094D: "क्" DEVANAGARI LETTER KA/DEVANAGARI SIGN VIRAMA -->
+ <Key
+ latin:keyLabel="&#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:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+090B: "ऋ" DEVANAGARI LETTER VOCALIC R -->
+ <Key
+ latin:keyLabel="&#x090B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0950: "ॐ" DEVANAGARI OM -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_au" />
+ <Key
+ 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:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ </case>
+ <default>
+ <!-- U+0936: "श" DEVANAGARI LETTER SHA -->
+ <Key
+ latin:keyLabel="&#x0936;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0939: "ह" DEVANAGARI LETTER HA -->
+ <Key
+ latin:keyLabel="&#x0939;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0905: "अ" DEVANAGARI LETTER A -->
+ <Key
+ latin:keyLabel="&#x0905;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0916: "ख" DEVANAGARI LETTER KHA -->
+ <Key
+ latin:keyLabel="&#x0916;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0926: "द" DEVANAGARI LETTER DA -->
+ <Key
+ latin:keyLabel="&#x0926;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0932: "ल" DEVANAGARI LETTER LA -->
+ <Key
+ latin:keyLabel="&#x0932;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_right3.xml b/java/res/xml/rowkeys_nepali_traditional3_right3.xml
new file mode 100644
index 000000000..b2e01e481
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_traditional3_right3.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
+ <!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAi" />
+ </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_vowel_sign_e" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignE" />
+ <!-- U+0964: "।" DEVANAGARI DANDA -->
+ <Key
+ latin:keyLabel="&#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:moreKeys="&#x0930;&#x0941;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_traditional3_right5.xml b/java/res/xml/rowkeys_nepali_traditional3_right5.xml
new file mode 100644
index 000000000..87f061610
--- /dev/null
+++ b/java/res/xml/rowkeys_nepali_traditional3_right5.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/key_devanagari_sign_anusvara" />
+ <!-- U+0919: "ङ" DEVANAGARI LETTER NGA -->
+ <Key
+ latin:keyLabel="&#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
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_ai" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignAi" />
+ <!-- U+0930/U+0941: "रु" DEVANAGARI LETTER RA/DEVANAGARI VOWEL SIGN U -->
+ <Key
+ latin:keyLabel="&#x0930;&#x0941;"
+ latin:moreKeys="!"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <Key
+ latin:keyLabel="\?" />
+ </case>
+ <default>
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <!-- U+093D: "ऽ" DEVANAGARI SIGN AVAGRAHA -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_visarga" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVisarga"
+ latin:moreKeys="&#x093D;" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_vowel_sign_e" />
+ <!-- Override more keys with empty definition -->
+ <key-style
+ latin:styleName="moreKeysDevanagariVowelSignE" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariVowelSignE" />
+ <!-- U+0964: "।" DEVANAGARI DANDA -->
+ <Key
+ latin:keyLabel="&#x0964;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0930: "र" DEVANAGARI LETTER RA -->
+ <Key
+ latin:keyLabel="&#x0930;"
+ latin:moreKeys="!"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- Because the font rendering system prior to API version 16 can't automatically
+ render dotted circle for incomplete combining letter of some scripts, different
+ set of Key definitions are needed based on the API version. -->
+ <include
+ latin:keyboardLayout="@xml/keystyle_devanagari_sign_virama" />
+ <Key
+ latin:keyStyle="baseKeyDevanagariSignVirama"
+ latin:moreKeys="\?" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty1.xml b/java/res/xml/rowkeys_pcqwerty1.xml
index b2d1d374b..de548d0ba 100644
--- a/java/res/xml/rowkeys_pcqwerty1.xml
+++ b/java/res/xml/rowkeys_pcqwerty1.xml
@@ -21,67 +21,61 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
- >
- <!-- U+00AC: "¬" NOT SIGN -->
- <Key
- latin:keyLabel="`"
- latin:moreKeys="~"
- latin:additionalMoreKeys="&#x00AC;" />
- <!-- U+00A1: "¡" NVERTED EXCLAMATION MARK -->
- <Key
- latin:keyLabel="1"
- latin:additionalMoreKeys="!"
- latin:moreKeys="&#x00A1;,!text/more_keys_for_symbols_1" />
- <Key
- latin:keyLabel="2"
- latin:additionalMoreKeys="\@"
- latin:moreKeys="!text/more_keys_for_symbols_2" />
- <Key
- latin:keyLabel="3"
- latin:additionalMoreKeys="\#"
- latin:moreKeys="!text/more_keys_for_symbols_3" />
- <Key
- latin:keyLabel="4"
- latin:additionalMoreKeys="$"
- latin:moreKeys="!text/more_keys_for_symbols_4" />
- <Key
- latin:keyLabel="5"
- latin:additionalMoreKeys="\\%"
- latin:moreKeys="!text/more_keys_for_symbols_5" />
- <Key
- latin:keyLabel="6"
- latin:additionalMoreKeys="^"
- latin:moreKeys="!text/more_keys_for_symbols_6" />
- <Key
- latin:keyLabel="7"
- latin:additionalMoreKeys="&amp;"
- latin:moreKeys="!text/more_keys_for_symbols_7" />
- <Key
- latin:keyLabel="8"
- latin:additionalMoreKeys="*,%"
- latin:moreKeys="!text/more_keys_for_symbols_8" />
- <Key
- latin:keyLabel="9"
- latin:additionalMoreKeys="("
- latin:moreKeys="!text/more_keys_for_symbols_9" />
- <Key
- latin:keyLabel="0"
- latin:additionalMoreKeys=")"
- latin:moreKeys="!text/more_keys_for_symbols_0" />
- <Key
- latin:keyLabel="-"
- latin:moreKeys="_" />
- <Key
- latin:keyLabel="="
- latin:moreKeys="+" />
- </case>
- <!-- keyboardLayoutSetElement="alphabet*Shifted|symbols*" -->
- <default>
- <include
- latin:keyboardLayout="@xml/keys_pcqwerty_symbols1" />
- </default>
- </switch>
+ <Key
+ latin:keyLabel="`"
+ latin:additionalMoreKeys="~" />
+ <Key
+ latin:keyLabel="1"
+ latin:additionalMoreKeys="!,!text/more_keys_for_symbols_exclamation"
+ latin:moreKeys="!text/more_keys_for_symbols_1" />
+ <Key
+ latin:keyLabel="2"
+ latin:additionalMoreKeys="\@"
+ latin:moreKeys="!text/more_keys_for_symbols_2" />
+ <Key
+ latin:keyLabel="3"
+ latin:additionalMoreKeys="\#"
+ latin:moreKeys="!text/more_keys_for_symbols_3" />
+ <Key
+ latin:keyLabel="4"
+ latin:additionalMoreKeys="$"
+ latin:moreKeys="!text/more_keys_for_symbols_4" />
+ <Key
+ latin:keyLabel="5"
+ latin:additionalMoreKeys="\\%"
+ latin:moreKeys="!text/more_keys_for_symbols_5" />
+ <Key
+ latin:keyLabel="6"
+ latin:additionalMoreKeys="^"
+ latin:moreKeys="!text/more_keys_for_symbols_6" />
+ <Key
+ latin:keyLabel="7"
+ latin:additionalMoreKeys="&amp;"
+ latin:moreKeys="!text/more_keys_for_symbols_7" />
+ <Key
+ latin:keyLabel="8"
+ latin:additionalMoreKeys="*"
+ latin:moreKeys="!text/more_keys_for_symbols_8" />
+ <Key
+ latin:keyLabel="9"
+ latin:additionalMoreKeys="("
+ latin:moreKeys="!text/more_keys_for_symbols_9" />
+ <Key
+ latin:keyLabel="0"
+ latin:additionalMoreKeys=")"
+ latin:moreKeys="!text/more_keys_for_symbols_0" />
+ <!-- U+2013: "–" EN DASH
+ U+2014: "—" EM DASH
+ U+00B7: "·" MIDDLE DOT -->
+ <Key
+ latin:keyLabel="-"
+ latin:additionalMoreKeys="_"
+ latin:moreKeys="&#x2013;,&#x2014;,&#x00B7;" />
+ <!-- U+221E: "∞" INFINITY
+ U+2260: "≠" NOT EQUAL TO
+ U+2248: "≈" ALMOST EQUAL TO -->
+ <Key
+ latin:keyLabel="="
+ latin:additionalMoreKeys="+"
+ latin:moreKeys="!fixedColumnOrder!4,&#x221E;,&#x2260;,&#x2248;,%" />
</merge>
diff --git a/java/res/xml/keys_pcqwerty_symbols1.xml b/java/res/xml/rowkeys_pcqwerty1_shift.xml
index 2364e1087..bc39f944e 100644
--- a/java/res/xml/keys_pcqwerty_symbols1.xml
+++ b/java/res/xml/rowkeys_pcqwerty1_shift.xml
@@ -21,37 +21,40 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+00AC: "¬" NOT SIGN -->
<Key
- latin:keyLabel="~"
- latin:moreKeys="&#x00AC;" />
- <!-- U+00A1: "¡" NVERTED EXCLAMATION MARK -->
+ latin:keyLabel="~" />
<Key
latin:keyLabel="!"
- latin:moreKeys="&#x00A1;" />
+ latin:additionalMoreKeys="!text/more_keys_for_symbols_exclamation" />
<Key
latin:keyLabel="\@" />
<Key
latin:keyLabel="\#" />
<Key
- latin:keyLabel="$" />
- <!-- U+2030: "‰" PER MILLE SIGN -->
+ latin:keyLabel="$"
+ latin:additionalMoreKeys="!text/more_keys_for_currency_dollar" />
<Key
latin:keyLabel="%"
- latin:moreKeys="&#x2030;" />
+ latin:additionalMoreKeys="!text/more_keys_for_symbols_percent" />
<Key
latin:keyLabel="^" />
<Key
latin:keyLabel="&amp;" />
<Key
latin:keyLabel="*"
- latin:moreKeys="!text/more_keys_for_star" />
+ latin:additionalMoreKeys="!text/more_keys_for_star" />
<Key
latin:keyLabel="(" />
<Key
latin:keyLabel=")" />
<Key
latin:keyLabel="_" />
- <Key
- latin:keyLabel="+" />
+ <!-- U+00B1: "±" PLUS-MINUS SIGN
+ U+00D7: "×" MULTIPLICATION SIGN
+ U+00F7: "÷" DIVISION SIGN
+ U+221A: "√" SQUARE ROOT -->
+ <Key
+ latin:keyLabel="+"
+ latin:additionalMoreKeys="!text/more_keys_for_plus"
+ latin:moreKeys="&#x00B1;,&#x00D7;,&#x00F7;,&#x221A;" />
</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty2.xml b/java/res/xml/rowkeys_pcqwerty2.xml
index cedf47559..8db704d71 100644
--- a/java/res/xml/rowkeys_pcqwerty2.xml
+++ b/java/res/xml/rowkeys_pcqwerty2.xml
@@ -21,21 +21,11 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <include
- latin:keyboardLayout="@xml/keys_pcqwerty_symbols2" />
- </case>
- <default>
- <!-- The keys on this PC layout row2 consist of the letters of QWERTY layout row1 and
- some symbols keys. -->
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty1"
- latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
- </default>
- </switch>
+ <!-- The keys on this PC layout row2 consist of the letters of QWERTY layout row1 and
+ some symbols keys. -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1"
+ latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
<include
latin:keyboardLayout="@xml/keys_pcqwerty2_right3" />
</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty3.xml b/java/res/xml/rowkeys_pcqwerty3.xml
index 5044e5feb..ad122d30c 100644
--- a/java/res/xml/rowkeys_pcqwerty3.xml
+++ b/java/res/xml/rowkeys_pcqwerty3.xml
@@ -21,20 +21,10 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <include
- latin:keyboardLayout="@xml/keys_pcqwerty_symbols3" />
- </case>
- <default>
- <!-- The keys on this PC layout row3 consist of the letters of QWERTY layout row2 and
- some symbols keys. -->
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty2" />
- </default>
- </switch>
+ <!-- The keys on this PC layout row3 consist of the letters of QWERTY layout row2 and
+ some symbols keys. -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2" />
<include
latin:keyboardLayout="@xml/keys_pcqwerty3_right2" />
</merge>
diff --git a/java/res/xml/rowkeys_pcqwerty4.xml b/java/res/xml/rowkeys_pcqwerty4.xml
index 4071e8c09..b558f4142 100644
--- a/java/res/xml/rowkeys_pcqwerty4.xml
+++ b/java/res/xml/rowkeys_pcqwerty4.xml
@@ -21,20 +21,10 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <switch>
- <case
- latin:keyboardLayoutSetElement="symbols|symbolsShifted"
- >
- <include
- latin:keyboardLayout="@xml/keys_pcqwerty_symbols4" />
- </case>
- <default>
- <!-- The keys on this PC layout row4 consist of the letters of QWERTY layout row3 and
- some symbols keys. -->
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty3" />
- </default>
- </switch>
+ <!-- The keys on this PC layout row4 consist of the letters of QWERTY layout row3 and
+ some symbols keys. -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3" />
<include
latin:keyboardLayout="@xml/keys_pcqwerty4_right3" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols2.xml b/java/res/xml/rowkeys_symbols2.xml
index 3e27f1579..76cbf6259 100644
--- a/java/res/xml/rowkeys_symbols2.xml
+++ b/java/res/xml/rowkeys_symbols2.xml
@@ -50,9 +50,6 @@
latin:moreKeys="!text/more_keys_for_symbols_percent" />
<Key
latin:keyLabel="&amp;" />
- <Key
- latin:keyLabel="*"
- latin:moreKeys="!text/more_keys_for_star" />
<!-- U+2013: "–" EN DASH
U+2014: "—" EM DASH
U+00B7: "·" MIDDLE DOT -->
diff --git a/java/res/xml/rowkeys_symbols3.xml b/java/res/xml/rowkeys_symbols3.xml
index 7722ca9ae..9f5e620e6 100644
--- a/java/res/xml/rowkeys_symbols3.xml
+++ b/java/res/xml/rowkeys_symbols3.xml
@@ -22,8 +22,8 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyLabel="!"
- latin:moreKeys="!text/more_keys_for_symbols_exclamation" />
+ latin:keyLabel="*"
+ latin:moreKeys="!text/more_keys_for_star" />
<switch>
<case
latin:languageCode="fa"
@@ -54,8 +54,9 @@
latin:keyLabel="!text/keylabel_for_symbols_semicolon"
latin:moreKeys="!text/more_keys_for_symbols_semicolon" />
<Key
- latin:keyLabel="/" />
- <Key
latin:keyLabel="!text/keylabel_for_symbols_question"
latin:moreKeys="!text/more_keys_for_symbols_question" />
+ <Key
+ latin:keyLabel="!"
+ latin:moreKeys="!text/more_keys_for_symbols_exclamation" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols_shift1.xml b/java/res/xml/rowkeys_symbols_shift1.xml
index fea8ae337..6013493e5 100644
--- a/java/res/xml/rowkeys_symbols_shift1.xml
+++ b/java/res/xml/rowkeys_symbols_shift1.xml
@@ -34,17 +34,23 @@
<!-- U+221A: "√" SQUARE ROOT -->
<Key
latin:keyLabel="&#x221A;" />
- <!-- U+03C0: "π" GREEK SMALL LETTER PI
- U+03A0: "Π" GREEK CAPITAL LETTER PI -->
+ <!-- U+03A0: "Π" GREEK CAPITAL LETTER PI
+ U+03C0: "π" GREEK SMALL LETTER PI -->
<Key
- latin:keyLabel="&#x03C0;"
- latin:moreKeys="&#x03A0;" />
+ latin:keyLabel="&#x03A0;"
+ latin:moreKeys="&#x03C0;" />
<!-- U+00F7: "÷" DIVISION SIGN -->
<Key
latin:keyLabel="&#x00F7;" />
<!-- U+00D7: "×" MULTIPLICATION SIGN -->
<Key
latin:keyLabel="&#x00D7;" />
- <include
- latin:keyboardLayout="@xml/keys_curly_brackets" />
+ <!-- U+00B6: "¶" PILCROW SIGN
+ U+00A7: "§" SECTION SIGN -->
+ <Key
+ latin:keyLabel="&#x00B6;"
+ latin:moreKeys="&#x00A7;" />
+ <!-- U+2206: "∆" INCREMENT -->
+ <Key
+ latin:keyLabel="&#x2206;" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols_shift2.xml b/java/res/xml/rowkeys_symbols_shift2.xml
index 3fd8aacb6..36f92143f 100644
--- a/java/res/xml/rowkeys_symbols_shift2.xml
+++ b/java/res/xml/rowkeys_symbols_shift2.xml
@@ -22,19 +22,13 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:keyStyle="nonSpecialBackgroundTabKeyStyle" />
- <Key
latin:keyStyle="moreCurrency1KeyStyle" />
<Key
latin:keyStyle="moreCurrency2KeyStyle" />
<Key
latin:keyStyle="moreCurrency3KeyStyle" />
- <!-- U+00B0: "°" DEGREE SIGN
- U+2032: "′" PRIME
- U+2033: "″" DOUBLE PRIME -->
<Key
- latin:keyLabel="&#x00B0;"
- latin:moreKeys="&#x2032;,&#x2033;" />
+ latin:keyStyle="moreCurrency4KeyStyle" />
<!-- U+2191: "↑" UPWARDS ARROW
U+2193: "↓" DOWNWARDS ARROW
U+2190: "←" LEFTWARDS ARROW
@@ -42,8 +36,12 @@
<Key
latin:keyLabel="^"
latin:moreKeys="&#x2191;,&#x2193;,&#x2190;,&#x2192;" />
+ <!-- U+00B0: "°" DEGREE SIGN
+ U+2032: "′" PRIME
+ U+2033: "″" DOUBLE PRIME -->
<Key
- latin:keyLabel="_" />
+ latin:keyLabel="&#x00B0;"
+ latin:moreKeys="&#x2032;,&#x2033;" />
<!-- U+2260: "≠" NOT EQUAL TO
U+2248: "≈" ALMOST EQUAL TO
U+221E: "∞" INFINITY -->
@@ -51,5 +49,5 @@
latin:keyLabel="="
latin:moreKeys="&#x2260;,&#x2248;,&#x221E;" />
<include
- latin:keyboardLayout="@xml/keys_square_brackets" />
+ latin:keyboardLayout="@xml/keys_curly_brackets" />
</merge>
diff --git a/java/res/xml/rowkeys_symbols_shift3.xml b/java/res/xml/rowkeys_symbols_shift3.xml
index a35af218f..5fe1c7450 100644
--- a/java/res/xml/rowkeys_symbols_shift3.xml
+++ b/java/res/xml/rowkeys_symbols_shift3.xml
@@ -21,22 +21,20 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+2122: "™" TRADE MARK SIGN -->
- <Key
- latin:keyLabel="&#x2122;" />
- <!-- U+00AE: "®" REGISTERED SIGN -->
<Key
- latin:keyLabel="&#x00AE;" />
+ latin:keyLabel="\\" />
<!-- U+00A9: "©" COPYRIGHT SIGN -->
<Key
latin:keyLabel="&#x00A9;" />
- <!-- U+00B6: "¶" PILCROW SIGN
- U+00A7: "§" SECTION SIGN -->
+ <!-- U+00AE: "®" REGISTERED SIGN -->
+ <Key
+ latin:keyLabel="&#x00AE;" />
+ <!-- U+2122: "™" TRADE MARK SIGN -->
<Key
- latin:keyLabel="&#x00B6;"
- latin:moreKeys="&#x00A7;" />
+ latin:keyLabel="&#x2122;" />
+ <!-- U+2105: "℅" CARE OF -->
<Key
- latin:keyLabel="\\" />
+ latin:keyLabel="&#x2105;" />
<include
- latin:keyboardLayout="@xml/keys_less_greater" />
+ latin:keyboardLayout="@xml/keys_square_brackets" />
</merge>
diff --git a/java/res/xml-sw600dp/rows_pcqwerty_symbols.xml b/java/res/xml/rows_armenian_phonetic.xml
index 5e1aa6382..ea8870e1a 100644
--- a/java/res/xml-sw600dp/rows_pcqwerty_symbols.xml
+++ b/java/res/xml/rows_armenian_phonetic.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -26,42 +26,39 @@
<include
latin:keyboardLayout="@xml/key_styles_currency" />
<Row
- latin:keyWidth="7.0%p"
+ latin:keyWidth="10.0%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic1" />
</Row>
<Row
- latin:keyWidth="7.0%p"
+ latin:keyWidth="10.0%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyWidth="9.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty2" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic2" />
</Row>
<Row
- latin:keyWidth="7.0%p"
+ latin:keyWidth="10.0%p"
>
- <Key
- latin:keyStyle="toAlphaKeyStyle"
- latin:keyWidth="12.0%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty3" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic3" />
+ <include
+ latin:keyboardLayout="@xml/key_armenian_xeh" />
</Row>
<Row
- latin:keyWidth="7.0%p"
+ latin:keyWidth="9.8000%p"
>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.8%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_armenian_phonetic4" />
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty4"
- latin:keyXPos="15.0%p" />
+ latin:keyboardLayout="@xml/key_armenian_sha" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
</Row>
<include
- latin:keyboardLayout="@xml/row_pcqwerty5" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml/rows_khmer.xml b/java/res/xml/rows_khmer.xml
new file mode 100644
index 000000000..e3993871b
--- /dev/null
+++ b/java/res/xml/rows_khmer.xml
@@ -0,0 +1,56 @@
+<?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.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_khmer1" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_khmer2" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_khmer3" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_khmer4" />
+ <Key
+ latin:keyStyle="deleteKeyStyle" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/rows_lao.xml b/java/res/xml/rows_lao.xml
new file mode 100644
index 000000000..321f4112a
--- /dev/null
+++ b/java/res/xml/rows_lao.xml
@@ -0,0 +1,56 @@
+<?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.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao1" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao2" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao3" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao4" />
+ <Key
+ latin:keyStyle="deleteKeyStyle" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw768dp/rows_arabic.xml b/java/res/xml/rows_nepali_romanized.xml
index 204f6d590..6df09c830 100644
--- a/java/res/xml-sw768dp/rows_arabic.xml
+++ b/java/res/xml/rows_nepali_romanized.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.
@@ -24,37 +24,28 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="7.375%p"
+ latin:keyWidth="9.091%p"
>
- <Key
- latin:keyStyle="tabKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="7.969%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_arabic1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized1" />
</Row>
<Row
- latin:keyWidth="7.227%p"
+ latin:keyWidth="9.091%p"
>
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_arabic2" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized2" />
</Row>
<Row
- latin:keyWidth="7.227%p"
+ latin:keyWidth="8.711%p"
>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.8%p" />
<include
- latin:keyboardLayout="@xml/rowkeys_arabic3"
- latin:keyXPos="6.602%p" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_romanized3" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml/rows_pcqwerty_symbols.xml b/java/res/xml/rows_nepali_traditional.xml
index 107a4ad1f..7789135ae 100644
--- a/java/res/xml/rows_pcqwerty_symbols.xml
+++ b/java/res/xml/rows_nepali_traditional.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -26,35 +26,31 @@
<include
latin:keyboardLayout="@xml/key_styles_currency" />
<Row
- latin:keyWidth="7.692%p"
+ latin:keyWidth="9.091%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional1" />
</Row>
<Row
- latin:keyWidth="7.692%p"
+ latin:keyWidth="9.091%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty2" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional2" />
</Row>
<Row
- latin:keyWidth="7.692%p"
+ latin:keyWidth="8.711%p"
>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.8%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_left6" />
<include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty3"
- latin:keyXPos="3.846%p" />
+ latin:keyboardLayout="@xml/rowkeys_nepali_traditional3_right3" />
<Key
latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"
- latin:visualInsetsLeft="1%p" />
- </Row>
- <Row
- latin:keyWidth="7.692%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty4"
- latin:keyXPos="11.538%p" />
+ latin:keyWidth="fillRight" />
</Row>
<include
- latin:keyboardLayout="@xml/row_pcqwerty5" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml/rows_pcqwerty.xml b/java/res/xml/rows_pcqwerty.xml
index a5ed74518..884698963 100644
--- a/java/res/xml/rows_pcqwerty.xml
+++ b/java/res/xml/rows_pcqwerty.xml
@@ -26,8 +26,19 @@
<Row
latin:keyWidth="7.692%p"
>
- <include
- latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabet|alphabetAutomaticShifted"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_pcqwerty1" />
+ </case>
+ <!-- keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted" -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_pcqwerty1_shift" />
+ </default>
+ </switch>
</Row>
<Row
latin:keyWidth="7.692%p"
diff --git a/java/res/xml/rows_symbols.xml b/java/res/xml/rows_symbols.xml
index bd1a57e75..3f102e277 100644
--- a/java/res/xml/rows_symbols.xml
+++ b/java/res/xml/rows_symbols.xml
@@ -35,7 +35,8 @@
latin:keyWidth="10%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_symbols2" />
+ latin:keyboardLayout="@xml/rowkeys_symbols2"
+ latin:keyXPos="5%p" />
</Row>
<Row
latin:keyWidth="10%p"
@@ -51,6 +52,13 @@
latin:keyWidth="fillRight"
latin:visualInsetsLeft="1%p" />
</Row>
- <include
- latin:keyboardLayout="@xml/row_symbols4" />
+ <Row
+ latin:keyWidth="10%p"
+ >
+ <Key
+ latin:keyStyle="toAlphaKeyStyle"
+ latin:keyWidth="15%p" />
+ <include
+ latin:keyboardLayout="@xml/row_symbols4" />
+ </Row>
</merge>
diff --git a/java/res/xml/rows_symbols_shift.xml b/java/res/xml/rows_symbols_shift.xml
index 9c03d90b5..45ada2a61 100644
--- a/java/res/xml/rows_symbols_shift.xml
+++ b/java/res/xml/rows_symbols_shift.xml
@@ -35,6 +35,7 @@
latin:keyWidth="10%p"
>
<include
+ latin:keyXPos="5%p"
latin:keyboardLayout="@xml/rowkeys_symbols_shift2" />
</Row>
<Row
@@ -51,6 +52,13 @@
latin:keyWidth="fillRight"
latin:visualInsetsLeft="1%p" />
</Row>
- <include
- latin:keyboardLayout="@xml/row_symbols_shift4" />
+ <Row
+ latin:keyWidth="10%p"
+ >
+ <Key
+ latin:keyStyle="toAlphaKeyStyle"
+ latin:keyWidth="15%p" />
+ <include
+ latin:keyboardLayout="@xml/row_symbols_shift4" />
+ </Row>
</merge>
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index 8ce126330..7639432aa 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -157,7 +157,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
// Add the virtual children of the root View.
final Keyboard keyboard = mKeyboardView.getKeyboard();
- final Key[] keys = keyboard.mKeys;
+ final Key[] keys = keyboard.getKeys();
for (Key key : keys) {
final int childVirtualViewId = generateVirtualViewIdForKey(key);
rootInfo.addChild(mKeyboardView, childVirtualViewId);
@@ -300,7 +300,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
}
mVirtualViewIdToKey.clear();
- final Key[] keys = keyboard.mKeys;
+ final Key[] keys = keyboard.getKeys();
for (Key key : keys) {
final int virtualViewId = generateVirtualViewIdForKey(key);
mVirtualViewIdToKey.put(virtualViewId, key);
diff --git a/java/src/com/android/inputmethod/compat/ActivityManagerCompatUtils.java b/java/src/com/android/inputmethod/compat/ActivityManagerCompatUtils.java
new file mode 100644
index 000000000..385e3e025
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ActivityManagerCompatUtils.java
@@ -0,0 +1,46 @@
+/*
+ * 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.compat;
+
+import android.app.ActivityManager;
+import android.content.Context;
+
+import java.lang.reflect.Method;
+
+public class ActivityManagerCompatUtils {
+ private static final Object LOCK = new Object();
+ private static volatile Boolean sBoolean = null;
+ private static final Method METHOD_isLowRamDevice = CompatUtils.getMethod(
+ ActivityManager.class, "isLowRamDevice");
+
+ private ActivityManagerCompatUtils() {
+ // Do not instantiate this class.
+ }
+
+ public static boolean isLowRamDevice(Context context) {
+ if (sBoolean == null) {
+ synchronized(LOCK) {
+ if (sBoolean == null) {
+ final ActivityManager am =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ sBoolean = (Boolean)CompatUtils.invoke(am, false, METHOD_isLowRamDevice);
+ }
+ }
+ }
+ return sBoolean;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java b/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java
new file mode 100644
index 000000000..fed134eb9
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import com.android.inputmethod.latin.R;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class EmojiCategoryPageIndicatorView extends LinearLayout {
+ private static final float BOTTOM_MARGIN_RATIO = 0.66f;
+ private final Paint mPaint = new Paint();
+ private int mCategoryPageSize = 0;
+ private int mCurrentCategoryPageId = 0;
+ private float mOffset = 0.0f;
+
+ public EmojiCategoryPageIndicatorView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public EmojiCategoryPageIndicatorView(Context context, 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) {
+ mCategoryPageSize = size;
+ mCurrentCategoryPageId = id;
+ mOffset = offset;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mCategoryPageSize == 0) {
+ // If the category is not set yet, just clear and return.
+ canvas.drawColor(0);
+ return;
+ }
+ final float height = getHeight();
+ final float width = getWidth();
+ final float unitWidth = width / mCategoryPageSize;
+ final float left = unitWidth * mCurrentCategoryPageId + mOffset * unitWidth;
+ final float top = 0.0f;
+ final float right = left + unitWidth;
+ final float bottom = height * BOTTOM_MARGIN_RATIO;
+ canvas.drawRect(left, top, right, bottom, mPaint);
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
new file mode 100644
index 000000000..61dc56ed1
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
@@ -0,0 +1,768 @@
+/*
+ * 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;
+
+import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.os.Build;
+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.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+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.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * View class to implement Emoji keyboards.
+ * The Emoji keyboard consists of group of views {@link R.layout#emoji_keyboard_view}.
+ * <ol>
+ * <li> Emoji category tabs.
+ * <li> Delete button.
+ * <li> Emoji keyboard pages that can be scrolled by swiping horizontally or by selecting a tab.
+ * <li> Back to main keyboard button and enter button.
+ * </ol>
+ * Because of the above reasons, this class doesn't extend {@link KeyboardView}.
+ */
+public final class EmojiKeyboardView extends LinearLayout implements OnTabChangeListener,
+ ViewPager.OnPageChangeListener, View.OnClickListener,
+ ScrollKeyboardView.OnKeyClickListener {
+ private static final String TAG = EmojiKeyboardView.class.getSimpleName();
+ private final int mKeyBackgroundId;
+ private final int mEmojiFunctionalKeyBackgroundId;
+ private final KeyboardLayoutSet mLayoutSet;
+ private final ColorStateList mTabLabelColor;
+ private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener;
+ private EmojiKeyboardAdapter mEmojiKeyboardAdapter;
+
+ private TabHost mTabHost;
+ private ViewPager mEmojiPager;
+ private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
+
+ private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
+
+ private static final int CATEGORY_ID_UNSPECIFIED = -1;
+ public static final int CATEGORY_ID_RECENTS = 0;
+ public static final int CATEGORY_ID_PEOPLE = 1;
+ public static final int CATEGORY_ID_OBJECTS = 2;
+ public static final int CATEGORY_ID_NATURE = 3;
+ public static final int CATEGORY_ID_PLACES = 4;
+ public static final int CATEGORY_ID_SYMBOLS = 5;
+ public static final int CATEGORY_ID_EMOTICONS = 6;
+
+ private static class CategoryProperties {
+ public int mCategoryId;
+ public int mPageCount;
+ public CategoryProperties(final int categoryId, final int pageCount) {
+ mCategoryId = categoryId;
+ mPageCount = pageCount;
+ }
+ }
+
+ private static class EmojiCategory {
+ private static final String[] sCategoryName = {
+ "recents",
+ "people",
+ "objects",
+ "nature",
+ "places",
+ "symbols",
+ "emoticons" };
+ private static final int[] sCategoryIcon = new int[] {
+ R.drawable.ic_emoji_recent_light,
+ R.drawable.ic_emoji_people_light,
+ R.drawable.ic_emoji_objects_light,
+ R.drawable.ic_emoji_nature_light,
+ R.drawable.ic_emoji_places_light,
+ R.drawable.ic_emoji_symbols_light,
+ 0 };
+ private static final String[] sCategoryLabel =
+ { null, null, null, null, null, null, ":-)" };
+ private static final int[] sCategoryElementId = {
+ KeyboardId.ELEMENT_EMOJI_RECENTS,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY1,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY2,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY3,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY4,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY5,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
+ private final SharedPreferences mPrefs;
+ private final int mMaxPageKeyCount;
+ private final KeyboardLayoutSet mLayoutSet;
+ private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
+ private final ArrayList<CategoryProperties> mShownCategories =
+ CollectionUtils.newArrayList();
+ private final ConcurrentHashMap<Long, DynamicGridKeyboard>
+ mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
+
+ private int mCurrentCategoryId = CATEGORY_ID_UNSPECIFIED;
+ private int mCurrentCategoryPageId = 0;
+
+ public EmojiCategory(final SharedPreferences prefs, final Resources res,
+ final KeyboardLayoutSet layoutSet) {
+ mPrefs = prefs;
+ mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count);
+ mLayoutSet = layoutSet;
+ for (int i = 0; i < sCategoryName.length; ++i) {
+ mCategoryNameToIdMap.put(sCategoryName[i], i);
+ }
+ addShownCategoryId(CATEGORY_ID_RECENTS);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2
+ || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KeyLimePie")
+ || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KitKat")) {
+ addShownCategoryId(CATEGORY_ID_PEOPLE);
+ addShownCategoryId(CATEGORY_ID_OBJECTS);
+ addShownCategoryId(CATEGORY_ID_NATURE);
+ addShownCategoryId(CATEGORY_ID_PLACES);
+ mCurrentCategoryId = CATEGORY_ID_PEOPLE;
+ } else {
+ mCurrentCategoryId = CATEGORY_ID_SYMBOLS;
+ }
+ addShownCategoryId(CATEGORY_ID_SYMBOLS);
+ addShownCategoryId(CATEGORY_ID_EMOTICONS);
+ getKeyboard(CATEGORY_ID_RECENTS, 0 /* cagetoryPageId */)
+ .loadRecentKeys(mCategoryKeyboardMap.values());
+ }
+
+ private void addShownCategoryId(int categoryId) {
+ // Load a keyboard of categoryId
+ getKeyboard(categoryId, 0 /* cagetoryPageId */);
+ final CategoryProperties properties =
+ new CategoryProperties(categoryId, getCategoryPageCount(categoryId));
+ mShownCategories.add(properties);
+ }
+
+ public String getCategoryName(int categoryId, int categoryPageId) {
+ return sCategoryName[categoryId] + "-" + categoryPageId;
+ }
+
+ public int getCategoryId(String name) {
+ final String[] strings = name.split("-");
+ return mCategoryNameToIdMap.get(strings[0]);
+ }
+
+ public int getCategoryIcon(int categoryId) {
+ return sCategoryIcon[categoryId];
+ }
+
+ public String getCategoryLabel(int categoryId) {
+ return sCategoryLabel[categoryId];
+ }
+
+ public ArrayList<CategoryProperties> getShownCategories() {
+ return mShownCategories;
+ }
+
+ public int getCurrentCategoryId() {
+ return mCurrentCategoryId;
+ }
+
+ public int getCurrentCategoryPageSize() {
+ return getCategoryPageSize(mCurrentCategoryId);
+ }
+
+ public int getCategoryPageSize(int categoryId) {
+ for (final CategoryProperties prop : mShownCategories) {
+ if (prop.mCategoryId == categoryId) {
+ return prop.mPageCount;
+ }
+ }
+ Log.w(TAG, "Invalid category id: " + categoryId);
+ // Should not reach here.
+ return 0;
+ }
+
+ public void setCurrentCategoryId(int categoryId) {
+ mCurrentCategoryId = categoryId;
+ }
+
+ public void setCurrentCategoryPageId(int id) {
+ mCurrentCategoryPageId = id;
+ }
+
+ public int getCurrentCategoryPageId() {
+ return mCurrentCategoryPageId;
+ }
+
+ public void saveLastTypedCategoryPage() {
+ Settings.writeEmojiCategoryLastTypedId(
+ mPrefs, mCurrentCategoryId, mCurrentCategoryPageId);
+ }
+
+ public boolean isInRecentTab() {
+ return mCurrentCategoryId == CATEGORY_ID_RECENTS;
+ }
+
+ public int getTabIdFromCategoryId(int categoryId) {
+ for (int i = 0; i < mShownCategories.size(); ++i) {
+ if (mShownCategories.get(i).mCategoryId == categoryId) {
+ return i;
+ }
+ }
+ Log.w(TAG, "categoryId not found: " + categoryId);
+ return 0;
+ }
+
+ // Returns the view pager's page position for the categoryId
+ public int getPageIdFromCategoryId(int categoryId) {
+ final int lastSavedCategoryPageId =
+ Settings.readEmojiCategoryLastTypedId(mPrefs, categoryId);
+ int sum = 0;
+ for (int i = 0; i < mShownCategories.size(); ++i) {
+ final CategoryProperties props = mShownCategories.get(i);
+ if (props.mCategoryId == categoryId) {
+ return sum + lastSavedCategoryPageId;
+ }
+ sum += props.mPageCount;
+ }
+ Log.w(TAG, "categoryId not found: " + categoryId);
+ return 0;
+ }
+
+ public int getRecentTabId() {
+ return getTabIdFromCategoryId(CATEGORY_ID_RECENTS);
+ }
+
+ private int getCategoryPageCount(int categoryId) {
+ final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
+ return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
+ }
+
+ // Returns a pair of the category id and the category page id from the view pager's page
+ // position. The category page id is numbered in each category. And the view page position
+ // is the position of the current shown page in the view pager which contains all pages of
+ // all categories.
+ public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(int position) {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ final int temp = sum;
+ sum += properties.mPageCount;
+ if (sum > position) {
+ return new Pair<Integer, Integer>(properties.mCategoryId, position - temp);
+ }
+ }
+ return null;
+ }
+
+ // Returns a keyboard from the view pager's page position.
+ public DynamicGridKeyboard getKeyboardFromPagePosition(int position) {
+ final Pair<Integer, Integer> categoryAndId =
+ getCategoryIdAndPageIdFromPagePosition(position);
+ if (categoryAndId != null) {
+ return getKeyboard(categoryAndId.first, categoryAndId.second);
+ }
+ 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);
+ }
+ kbd = mCategoryKeyboardMap.get(key);
+ } else {
+ kbd = new DynamicGridKeyboard(mPrefs,
+ mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ mMaxPageKeyCount, categoryId, 0 /* categoryPageId */);
+ mCategoryKeyboardMap.put(key, kbd);
+ }
+ } else {
+ kbd = mCategoryKeyboardMap.get(key);
+ }
+ return kbd;
+ }
+ }
+
+ public int getTotalPageCountOfAllCategories() {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ sum += properties.mPageCount;
+ }
+ 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;
+ }
+ });
+ final int pageCount = (keys.length - 1) / maxPageCount + 1;
+ final Key[][] retval = new Key[pageCount][maxPageCount];
+ for (int i = 0; i < keys.length; ++i) {
+ retval[i / maxPageCount][i % maxPageCount] = keys[i];
+ }
+ return retval;
+ }
+ }
+
+ private final EmojiCategory mEmojiCategory;
+
+ public EmojiKeyboardView(final Context context, final AttributeSet attrs) {
+ this(context, attrs, R.attr.emojiKeyboardViewStyle);
+ }
+
+ public EmojiKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs,
+ R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
+ mKeyBackgroundId = keyboardViewAttr.getResourceId(
+ R.styleable.KeyboardView_keyBackground, 0);
+ mEmojiFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId(
+ R.styleable.KeyboardView_keyBackgroundEmojiFunctional, 0);
+ keyboardViewAttr.recycle();
+ final TypedArray emojiKeyboardViewAttr = context.obtainStyledAttributes(attrs,
+ R.styleable.EmojiKeyboardView, defStyle, R.style.EmojiKeyboardView);
+ mTabLabelColor = emojiKeyboardViewAttr.getColorStateList(
+ R.styleable.EmojiKeyboardView_emojiTabLabelColor);
+ emojiKeyboardViewAttr.recycle();
+ final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
+ context, null /* editorInfo */);
+ final Resources res = context.getResources();
+ final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
+ builder.setSubtype(SubtypeSwitcher.getInstance().getEmojiSubtype());
+ builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res),
+ emojiLp.mEmojiKeyboardHeight);
+ builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
+ mLayoutSet = builder.build();
+ mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context),
+ context.getResources(), builder.build());
+ mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(context);
+ }
+
+ @Override
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ final Resources res = getContext().getResources();
+ // The main keyboard expands to the entire this {@link KeyboardView}.
+ final int width = ResourceUtils.getDefaultKeyboardWidth(res)
+ + getPaddingLeft() + getPaddingRight();
+ final int height = ResourceUtils.getDefaultKeyboardHeight(res)
+ + res.getDimensionPixelSize(R.dimen.suggestions_strip_height)
+ + getPaddingTop() + getPaddingBottom();
+ setMeasuredDimension(width, height);
+ }
+
+ private void addTab(final TabHost host, final int categoryId) {
+ final String tabId = mEmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */);
+ final TabHost.TabSpec tspec = host.newTabSpec(tabId);
+ tspec.setContent(R.id.emoji_keyboard_dummy);
+ if (mEmojiCategory.getCategoryIcon(categoryId) != 0) {
+ final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate(
+ R.layout.emoji_keyboard_tab_icon, null);
+ iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId));
+ tspec.setIndicator(iconView);
+ }
+ if (mEmojiCategory.getCategoryLabel(categoryId) != null) {
+ final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate(
+ R.layout.emoji_keyboard_tab_label, null);
+ textView.setText(mEmojiCategory.getCategoryLabel(categoryId));
+ textView.setTextColor(mTabLabelColor);
+ tspec.setIndicator(textView);
+ }
+ host.addTab(tspec);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost);
+ mTabHost.setup();
+ for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) {
+ addTab(mTabHost, properties.mCategoryId);
+ }
+ mTabHost.setOnTabChangedListener(this);
+ mTabHost.getTabWidget().setStripEnabled(true);
+
+ mEmojiKeyboardAdapter = new EmojiKeyboardAdapter(mEmojiCategory, mLayoutSet, this);
+
+ mEmojiPager = (ViewPager)findViewById(R.id.emoji_keyboard_pager);
+ mEmojiPager.setAdapter(mEmojiKeyboardAdapter);
+ mEmojiPager.setOnPageChangeListener(this);
+ mEmojiPager.setOffscreenPageLimit(0);
+ final Resources res = getResources();
+ final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
+ emojiLp.setPagerProperties(mEmojiPager);
+
+ mEmojiCategoryPageIndicatorView =
+ (EmojiCategoryPageIndicatorView)findViewById(R.id.emoji_category_page_id_view);
+ emojiLp.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView);
+
+ setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */);
+
+ final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar);
+ emojiLp.setActionBarProperties(actionBar);
+
+ 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);
+ final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space);
+ spaceKey.setBackgroundResource(mKeyBackgroundId);
+ spaceKey.setTag(Constants.CODE_SPACE);
+ spaceKey.setOnClickListener(this);
+ emojiLp.setKeyProperties(spaceKey);
+ final ImageView sendKey = (ImageView)findViewById(R.id.emoji_keyboard_send);
+ sendKey.setBackgroundResource(mEmojiFunctionalKeyBackgroundId);
+ sendKey.setTag(Constants.CODE_ENTER);
+ sendKey.setOnClickListener(this);
+ }
+
+ @Override
+ public void onTabChanged(final String tabId) {
+ final int categoryId = mEmojiCategory.getCategoryId(tabId);
+ setCurrentCategoryId(categoryId, false /* force */);
+ updateEmojiCategoryPageIdView();
+ }
+
+
+ @Override
+ public void onPageSelected(final int position) {
+ final Pair<Integer, Integer> newPos =
+ mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
+ setCurrentCategoryId(newPos.first /* categoryId */, false /* force */);
+ mEmojiCategory.setCurrentCategoryPageId(newPos.second /* categoryPageId */);
+ updateEmojiCategoryPageIdView();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(final int state) {
+ // Ignore this message. Only want the actual page selected.
+ }
+
+ @Override
+ public void onPageScrolled(final int position, final float positionOffset,
+ final int positionOffsetPixels) {
+ final Pair<Integer, Integer> newPos =
+ mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
+ final int newCategoryId = newPos.first;
+ final int newCategorySize = mEmojiCategory.getCategoryPageSize(newCategoryId);
+ final int currentCategoryId = mEmojiCategory.getCurrentCategoryId();
+ final int currentCategoryPageId = mEmojiCategory.getCurrentCategoryPageId();
+ final int currentCategorySize = mEmojiCategory.getCurrentCategoryPageSize();
+ if (newCategoryId == currentCategoryId) {
+ mEmojiCategoryPageIndicatorView.setCategoryPageId(
+ newCategorySize, newPos.second, positionOffset);
+ } else if (newCategoryId > currentCategoryId) {
+ mEmojiCategoryPageIndicatorView.setCategoryPageId(
+ currentCategorySize, currentCategoryPageId, positionOffset);
+ } else if (newCategoryId < currentCategoryId) {
+ mEmojiCategoryPageIndicatorView.setCategoryPageId(
+ currentCategorySize, currentCategoryPageId, positionOffset - 1);
+ }
+ }
+
+ @Override
+ public void onClick(final View v) {
+ if (v.getTag() instanceof Integer) {
+ final int code = (Integer)v.getTag();
+ registerCode(code);
+ return;
+ }
+ }
+
+ private void registerCode(final int code) {
+ mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */);
+ mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE);
+ mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
+ }
+
+ @Override
+ public void onKeyClick(final Key key) {
+ mEmojiKeyboardAdapter.addRecentKey(key);
+ mEmojiCategory.saveLastTypedCategoryPage();
+ final int code = key.getCode();
+ if (code == Constants.CODE_OUTPUT_TEXT) {
+ mKeyboardActionListener.onTextInput(key.getOutputText());
+ return;
+ }
+ registerCode(code);
+ }
+
+ public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
+ // TODO:
+ }
+
+ public void setKeyboardActionListener(final KeyboardActionListener listener) {
+ mKeyboardActionListener = listener;
+ mDeleteKeyOnTouchListener.setKeyboardActionListener(mKeyboardActionListener);
+ }
+
+ private void updateEmojiCategoryPageIdView() {
+ if (mEmojiCategoryPageIndicatorView == null) {
+ return;
+ }
+ mEmojiCategoryPageIndicatorView.setCategoryPageId(
+ mEmojiCategory.getCurrentCategoryPageSize(),
+ mEmojiCategory.getCurrentCategoryPageId(), 0.0f /* offset */);
+ }
+
+ private void setCurrentCategoryId(final int categoryId, final boolean force) {
+ if (mEmojiCategory.getCurrentCategoryId() == categoryId && !force) {
+ return;
+ }
+
+ mEmojiCategory.setCurrentCategoryId(categoryId);
+ final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId);
+ final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId);
+ if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(
+ mEmojiPager.getCurrentItem()).first != categoryId) {
+ mEmojiPager.setCurrentItem(newCategoryPageId, false /* smoothScroll */);
+ }
+ if (force || mTabHost.getCurrentTab() != newTabId) {
+ mTabHost.setCurrentTab(newTabId);
+ }
+ }
+
+ private static class EmojiKeyboardAdapter extends PagerAdapter {
+ private final ScrollKeyboardView.OnKeyClickListener mListener;
+ private final DynamicGridKeyboard mRecentsKeyboard;
+ private final SparseArray<ScrollKeyboardView> mActiveKeyboardView =
+ CollectionUtils.newSparseArray();
+ private final EmojiCategory mEmojiCategory;
+ private int mActivePosition = 0;
+
+ public EmojiKeyboardAdapter(final EmojiCategory emojiCategory,
+ final KeyboardLayoutSet layoutSet,
+ final ScrollKeyboardView.OnKeyClickListener listener) {
+ mEmojiCategory = emojiCategory;
+ mListener = listener;
+ mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0);
+ }
+
+ public void addRecentKey(final Key key) {
+ if (mEmojiCategory.isInRecentTab()) {
+ return;
+ }
+ mRecentsKeyboard.addKeyFirst(key);
+ final KeyboardView recentKeyboardView =
+ mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
+ if (recentKeyboardView != null) {
+ recentKeyboardView.invalidateAllKeys();
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mEmojiCategory.getTotalPageCountOfAllCategories();
+ }
+
+ @Override
+ public void setPrimaryItem(final View container, final int position, final Object object) {
+ if (mActivePosition == position) {
+ return;
+ }
+ final ScrollKeyboardView oldKeyboardView = mActiveKeyboardView.get(mActivePosition);
+ if (oldKeyboardView != null) {
+ oldKeyboardView.releaseCurrentKey();
+ oldKeyboardView.deallocateMemory();
+ }
+ mActivePosition = position;
+ }
+
+ @Override
+ public Object instantiateItem(final ViewGroup container, final int position) {
+ final Keyboard keyboard =
+ mEmojiCategory.getKeyboardFromPagePosition(position);
+ final LayoutInflater inflater = LayoutInflater.from(container.getContext());
+ final View view = 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);
+ mActiveKeyboardView.put(position, keyboardView);
+ return view;
+ }
+
+ @Override
+ public boolean isViewFromObject(final View view, final Object object) {
+ return view == object;
+ }
+
+ @Override
+ public void destroyItem(final ViewGroup container, final int position,
+ final Object object) {
+ final ScrollKeyboardView keyboardView = mActiveKeyboardView.get(position);
+ if (keyboardView != null) {
+ keyboardView.deallocateMemory();
+ mActiveKeyboardView.remove(position);
+ }
+ container.removeView(keyboardView);
+ }
+ }
+
+ // 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 final int mDeleteKeyPressedBackgroundColor;
+ private final long mKeyRepeatStartTimeout;
+ private final long mKeyRepeatInterval;
+
+ public DeleteKeyOnTouchListener(Context context) {
+ final Resources res = context.getResources();
+ mDeleteKeyPressedBackgroundColor =
+ 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);
+ }
+
+ private KeyboardActionListener mKeyboardActionListener =
+ KeyboardActionListener.EMPTY_LISTENER;
+ private DummyRepeatKeyRepeatTimer mTimer;
+
+ private synchronized void startRepeat() {
+ if (mTimer != null) {
+ abortRepeat();
+ }
+ mTimer = new DummyRepeatKeyRepeatTimer();
+ mTimer.start();
+ }
+
+ private synchronized void abortRepeat() {
+ mTimer.abort();
+ mTimer = null;
+ }
+
+ // 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 timeCount = 0;
+ while (timeCount < MAX_REPEAT_COUNT_TIME && !mAborted) {
+ if (timeCount > mKeyRepeatStartTimeout) {
+ pressDelete();
+ }
+ timeCount += mKeyRepeatInterval;
+ try {
+ Thread.sleep(mKeyRepeatInterval);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ public void abort() {
+ mAborted = true;
+ }
+ }
+
+ public void pressDelete() {
+ mKeyboardActionListener.onPressKey(
+ Constants.CODE_DELETE, 0 /* repeatCount */, true /* isSinglePointer */);
+ mKeyboardActionListener.onCodeInput(
+ Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
+ mKeyboardActionListener.onReleaseKey(
+ Constants.CODE_DELETE, false /* withSliding */);
+ }
+
+ public void setKeyboardActionListener(KeyboardActionListener listener) {
+ mKeyboardActionListener = listener;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch(event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
+ pressDelete();
+ startRepeat();
+ return true;
+ case MotionEvent.ACTION_UP:
+ v.setBackgroundColor(0);
+ abortRepeat();
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
new file mode 100644
index 000000000..267fad5cd
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+
+import android.content.res.Resources;
+import android.support.v4.view.ViewPager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+public class EmojiLayoutParams {
+ private static final int DEFAULT_KEYBOARD_ROWS = 4;
+
+ public final int mEmojiPagerHeight;
+ private final int mEmojiPagerBottomMargin;
+ public final int mEmojiKeyboardHeight;
+ private final int mEmojiCategoryPageIdViewHeight;
+ public final int mEmojiActionBarHeight;
+ public final int mKeyVerticalGap;
+ private final int mKeyHorizontalGap;
+ private final int mBottomPadding;
+ private final int mTopPadding;
+
+ public EmojiLayoutParams(Resources res) {
+ final int defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
+ final int defaultKeyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
+ mKeyVerticalGap = (int) res.getFraction(R.fraction.key_bottom_gap_ics,
+ (int) defaultKeyboardHeight, (int) defaultKeyboardHeight);
+ mBottomPadding = (int) res.getFraction(R.fraction.keyboard_bottom_padding_ics,
+ (int) defaultKeyboardHeight, (int) defaultKeyboardHeight);
+ mTopPadding = (int) res.getFraction(R.fraction.keyboard_top_padding_ics,
+ (int) defaultKeyboardHeight, (int) defaultKeyboardHeight);
+ mKeyHorizontalGap = (int) (res.getFraction(R.fraction.key_horizontal_gap_ics,
+ defaultKeyboardWidth, defaultKeyboardWidth));
+ mEmojiCategoryPageIdViewHeight =
+ (int) (res.getDimension(R.dimen.emoji_category_page_id_height));
+ final int baseheight = defaultKeyboardHeight - mBottomPadding - mTopPadding
+ + mKeyVerticalGap;
+ mEmojiActionBarHeight = ((int) baseheight) / DEFAULT_KEYBOARD_ROWS
+ - (mKeyVerticalGap - mBottomPadding) / 2;
+ mEmojiPagerHeight = defaultKeyboardHeight - mEmojiActionBarHeight
+ - mEmojiCategoryPageIdViewHeight;
+ mEmojiPagerBottomMargin = mKeyVerticalGap / 2;
+ mEmojiKeyboardHeight = mEmojiPagerHeight - mEmojiPagerBottomMargin - 1;
+ }
+
+ public void setPagerProperties(ViewPager vp) {
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams();
+ lp.height = mEmojiKeyboardHeight;
+ lp.bottomMargin = mEmojiPagerBottomMargin;
+ vp.setLayoutParams(lp);
+ }
+
+ public void setCategoryPageIdViewProperties(LinearLayout ll) {
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
+ lp.height = mEmojiCategoryPageIdViewHeight;
+ ll.setLayoutParams(lp);
+ }
+
+ public void setActionBarProperties(LinearLayout ll) {
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
+ lp.height = mEmojiActionBarHeight;
+ lp.topMargin = 0;
+ lp.bottomMargin = mBottomPadding;
+ ll.setLayoutParams(lp);
+ }
+
+ public void setKeyProperties(ImageView ib) {
+ final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ib.getLayoutParams();
+ lp.leftMargin = mKeyHorizontalGap / 2;
+ lp.rightMargin = mKeyHorizontalGap / 2;
+ ib.setLayoutParams(lp);
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 8098dab37..3ea68806b 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -234,7 +234,7 @@ public class Key implements Comparable<Key> {
public Key(final Resources res, final KeyboardParams params, final KeyboardRow row,
final XmlPullParser parser) throws XmlPullParserException {
final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
- final int rowHeight = row.mRowHeight;
+ final int rowHeight = row.getRowHeight();
mHeight = rowHeight - params.mVerticalGap;
final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
@@ -269,11 +269,11 @@ public class Key implements Comparable<Key> {
final int previewIconId = KeySpecParser.getIconId(style.getString(keyAttr,
R.styleable.Keyboard_Key_keyIconPreview));
- mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
+ mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags)
| row.getDefaultKeyLabelFlags();
final boolean needsToUpperCase = needsToUpperCase(mLabelFlags, params.mId.mElementId);
final Locale locale = params.mId.mLocale;
- int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
+ int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
int moreKeysColumn = style.getInt(keyAttr,
@@ -764,8 +764,9 @@ public class Key implements Comparable<Key> {
}
public final int getDrawX() {
+ final int x = getX();
final OptionalAttributes attrs = mOptionalAttributes;
- return (attrs == null) ? mX : mX + attrs.mVisualInsetsLeft;
+ return (attrs == null) ? x : x + attrs.mVisualInsetsLeft;
}
public final int getDrawWidth() {
@@ -823,9 +824,9 @@ public class Key implements Comparable<Key> {
* @return the square of the distance of the point from the nearest edge of the key
*/
public int squaredDistanceToEdge(final int x, final int y) {
- final int left = mX;
+ final int left = getX();
final int right = left + mWidth;
- final int top = mY;
+ final int top = getY();
final int bottom = top + mHeight;
final int edgeX = x < left ? left : (x > right ? right : x);
final int edgeY = y < top ? top : (y > bottom ? bottom : y);
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index c40ddeabe..bc1383aff 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -51,6 +51,11 @@ public class Keyboard {
/** Total width of the keyboard, including the padding and keys */
public final int mOccupiedWidth;
+ /** Base height of the keyboard, used to calculate rows' height */
+ public final int mBaseHeight;
+ /** Base width of the keyboard, used to calculate keys' width */
+ public final int mBaseWidth;
+
/** The padding above the keyboard */
public final int mTopPadding;
/** Default gap between rows */
@@ -69,7 +74,7 @@ public class Keyboard {
public final int mMaxMoreKeysKeyboardColumn;
/** Array of keys and icons in this keyboard */
- public final Key[] mKeys;
+ private final Key[] mKeys;
public final Key[] mShiftKeys;
public final Key[] mAltCodeKeysWhileTyping;
public final KeyboardIconsSet mIconsSet;
@@ -84,6 +89,8 @@ public class Keyboard {
mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight;
mOccupiedWidth = params.mOccupiedWidth;
+ mBaseHeight = params.mBaseHeight;
+ mBaseWidth = params.mBaseWidth;
mMostCommonKeyHeight = params.mMostCommonKeyHeight;
mMostCommonKeyWidth = params.mMostCommonKeyWidth;
mMoreKeysTemplate = params.mMoreKeysTemplate;
@@ -104,6 +111,30 @@ public class Keyboard {
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
}
+ protected Keyboard(final Keyboard keyboard) {
+ mId = keyboard.mId;
+ mThemeId = keyboard.mThemeId;
+ mOccupiedHeight = keyboard.mOccupiedHeight;
+ mOccupiedWidth = keyboard.mOccupiedWidth;
+ mBaseHeight = keyboard.mBaseHeight;
+ mBaseWidth = keyboard.mBaseWidth;
+ mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight;
+ mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth;
+ mMoreKeysTemplate = keyboard.mMoreKeysTemplate;
+ mMaxMoreKeysKeyboardColumn = keyboard.mMaxMoreKeysKeyboardColumn;
+ mKeyVisualAttributes = keyboard.mKeyVisualAttributes;
+ mTopPadding = keyboard.mTopPadding;
+ mVerticalGap = keyboard.mVerticalGap;
+
+ mKeys = keyboard.mKeys;
+ mShiftKeys = keyboard.mShiftKeys;
+ mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
+ mIconsSet = keyboard.mIconsSet;
+
+ mProximityInfo = keyboard.mProximityInfo;
+ mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled;
+ }
+
public boolean hasProximityCharsCorrection(final int code) {
if (!mProximityCharsCorrectionEnabled) {
return false;
@@ -120,6 +151,19 @@ public class Keyboard {
return mProximityInfo;
}
+ public Key[] getKeys() {
+ return mKeys;
+ }
+
+ public Key getKeyFromOutputText(final String outputText) {
+ for (final Key key : getKeys()) {
+ if (outputText.equals(key.getOutputText())) {
+ return key;
+ }
+ }
+ return null;
+ }
+
public Key getKey(final int code) {
if (code == Constants.CODE_UNSPECIFIED) {
return null;
@@ -130,7 +174,7 @@ public class Keyboard {
return mKeyCache.valueAt(index);
}
- for (final Key key : mKeys) {
+ for (final Key key : getKeys()) {
if (key.getCode() == code) {
mKeyCache.put(code, key);
return key;
@@ -146,7 +190,7 @@ public class Keyboard {
return true;
}
- for (final Key key : mKeys) {
+ for (final Key key : getKeys()) {
if (key == aKey) {
mKeyCache.put(key.getCode(), key);
return true;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 1dc3c6a4c..736f13ed6 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -54,6 +54,13 @@ public final class KeyboardId {
public static final int ELEMENT_PHONE = 7;
public static final int ELEMENT_PHONE_SYMBOLS = 8;
public static final int ELEMENT_NUMBER = 9;
+ public static final int ELEMENT_EMOJI_RECENTS = 10;
+ public static final int ELEMENT_EMOJI_CATEGORY1 = 11;
+ public static final int ELEMENT_EMOJI_CATEGORY2 = 12;
+ public static final int ELEMENT_EMOJI_CATEGORY3 = 13;
+ public static final int ELEMENT_EMOJI_CATEGORY4 = 14;
+ public static final int ELEMENT_EMOJI_CATEGORY5 = 15;
+ public static final int ELEMENT_EMOJI_CATEGORY6 = 16;
public final InputMethodSubtype mSubtype;
public final Locale mLocale;
@@ -217,6 +224,13 @@ public final class KeyboardId {
case ELEMENT_PHONE: return "phone";
case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols";
case ELEMENT_NUMBER: return "number";
+ case ELEMENT_EMOJI_RECENTS: return "emojiRecents";
+ case ELEMENT_EMOJI_CATEGORY1: return "emojiCategory1";
+ case ELEMENT_EMOJI_CATEGORY2: return "emojiCategory2";
+ case ELEMENT_EMOJI_CATEGORY3: return "emojiCategory3";
+ case ELEMENT_EMOJI_CATEGORY4: return "emojiCategory4";
+ case ELEMENT_EMOJI_CATEGORY5: return "emojiCategory5";
+ case ELEMENT_EMOJI_CATEGORY6: return "emojiCategory6";
default: return null;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 711de63b3..1eccdf341 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -106,6 +106,8 @@ public final class KeyboardLayoutSet {
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 mNoSettingsKey;
boolean mLanguageSwitchKeyEnabled;
@@ -259,6 +261,8 @@ 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")
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 1ea0f8b96..cc1ffd183 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -58,19 +58,17 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
private static final KeyboardTheme[] KEYBOARD_THEMES = {
- new KeyboardTheme(0, R.style.KeyboardTheme),
- new KeyboardTheme(1, R.style.KeyboardTheme_HighContrast),
- new KeyboardTheme(6, R.style.KeyboardTheme_Stone),
- new KeyboardTheme(7, R.style.KeyboardTheme_Stone_Bold),
- new KeyboardTheme(8, R.style.KeyboardTheme_Gingerbread),
- new KeyboardTheme(5, R.style.KeyboardTheme_IceCreamSandwich),
+ new KeyboardTheme(0, R.style.KeyboardTheme_ICS),
+ new KeyboardTheme(1, R.style.KeyboardTheme_GB),
};
private SubtypeSwitcher mSubtypeSwitcher;
private SharedPreferences mPrefs;
private InputView mCurrentInputView;
+ private View mMainKeyboardFrame;
private MainKeyboardView mKeyboardView;
+ private EmojiKeyboardView mEmojiKeyboardView;
private LatinIME mLatinIME;
private Resources mResources;
@@ -121,8 +119,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
} catch (NumberFormatException e) {
// Format error, keyboard theme is default to 0.
}
- Log.w(TAG, "Illegal keyboard theme in preference: " + themeIndex + ", default to 0");
- return KEYBOARD_THEMES[0];
+ Log.w(TAG, "Illegal keyboard theme in preference: " + themeIndex + ", default to "
+ + defaultIndex);
+ return KEYBOARD_THEMES[Integer.valueOf(defaultIndex)];
}
private void setContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme) {
@@ -143,7 +142,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
builder.setSubtype(mSubtypeSwitcher.getCurrentSubtype());
builder.setOptions(
settingsValues.isVoiceKeyEnabled(editorInfo),
- settingsValues.isVoiceKeyOnMain(),
+ true /* always show a voice key on the main keyboard */,
settingsValues.isLanguageSwitchKeyEnabled());
mKeyboardLayoutSet = builder.build();
try {
@@ -170,6 +169,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
private void setKeyboard(final Keyboard keyboard) {
+ // Make {@link MainKeyboardView} visible and hide {@link EmojiKeyboardView}.
+ setMainKeyboardFrame();
final MainKeyboardView keyboardView = mKeyboardView;
final Keyboard oldKeyboard = keyboardView.getKeyboard();
keyboardView.setKeyboard(keyboard);
@@ -256,6 +257,18 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS));
}
+ private void setMainKeyboardFrame() {
+ mMainKeyboardFrame.setVisibility(View.VISIBLE);
+ mEmojiKeyboardView.setVisibility(View.GONE);
+ }
+
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setEmojiKeyboard() {
+ mMainKeyboardFrame.setVisibility(View.GONE);
+ mEmojiKeyboardView.setVisibility(View.VISIBLE);
+ }
+
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsShiftedKeyboard() {
@@ -301,6 +314,24 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mState.onCodeInput(code, mLatinIME.getCurrentAutoCapsState());
}
+ public boolean isShowingEmojiKeyboard() {
+ return mEmojiKeyboardView.getVisibility() == View.VISIBLE;
+ }
+
+ public boolean isShowingMoreKeysPanel() {
+ if (isShowingEmojiKeyboard()) {
+ return false;
+ }
+ return mKeyboardView.isShowingMoreKeysPanel();
+ }
+
+ public View getVisibleKeyboardView() {
+ if (isShowingEmojiKeyboard()) {
+ return mEmojiKeyboardView;
+ }
+ return mKeyboardView;
+ }
+
public MainKeyboardView getMainKeyboardView() {
return mKeyboardView;
}
@@ -313,10 +344,16 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
setContextThemeWrapper(mLatinIME, mKeyboardTheme);
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
R.layout.input_view, null);
+ mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
+ mEmojiKeyboardView = (EmojiKeyboardView)mCurrentInputView.findViewById(
+ R.id.emoji_keyboard_view);
mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
mKeyboardView.setKeyboardActionListener(mLatinIME);
+ mEmojiKeyboardView.setHardwareAcceleratedDrawingEnabled(
+ isHardwareAcceleratedDrawingEnabled);
+ mEmojiKeyboardView.setKeyboardActionListener(mLatinIME);
// This always needs to be set since the accessibility state can
// potentially change without the input view being re-created.
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d049a861e..aeb9e67b2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -26,6 +26,7 @@ import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -285,7 +286,7 @@ public class KeyboardView extends View {
// TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
if (drawAllKeys || isHardwareAccelerated) {
// Draw all keys.
- for (final Key key : mKeyboard.mKeys) {
+ for (final Key key : mKeyboard.getKeys()) {
onDrawKey(key, canvas, paint);
}
} else {
@@ -445,6 +446,8 @@ public class KeyboardView extends View {
if (hintLabel != null) {
paint.setTextSize(key.selectHintTextSize(params));
paint.setColor(key.selectHintTextColor(params));
+ // TODO: Should add a way to specify type face for hint letters
+ paint.setTypeface(Typeface.DEFAULT_BOLD);
blendAlpha(paint, params.mAnimAlpha);
final float hintX, hintY;
if (key.hasHintLabel()) {
@@ -465,9 +468,13 @@ public class KeyboardView extends View {
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);
hintX = keyWidth - mKeyHintLetterPadding
- - TypefaceUtils.getCharWidth(KEY_NUMERIC_HINT_LABEL_REFERENCE_CHAR, paint)
- / 2.0f;
+ - Math.max(keyNumericHintLabelReferenceCharWidth, keyHintLabelStringWidth)
+ / 2.0f;
hintY = -paint.ascent();
paint.setTextAlign(Align.CENTER);
}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index e4a8f4cb2..13db47004 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -155,7 +155,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private final SlidingKeyInputPreview mSlidingKeyInputPreview;
// Key preview
- private static final int PREVIEW_ALPHA = 240;
private final int mKeyPreviewLayoutId;
private final int mKeyPreviewOffset;
private final int mKeyPreviewHeight;
@@ -183,6 +182,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper;
private final KeyTimerHandler mKeyTimerHandler;
+ private final int mLanguageOnSpacebarHorizontalMargin;
private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView>
implements TimerProxy {
@@ -512,6 +512,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
altCodeKeyWhileTypingFadeinAnimatorResId, this);
mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
+
+ mLanguageOnSpacebarHorizontalMargin =
+ (int) getResources().getDimension(R.dimen.language_on_spacebar_horizontal_margin);
}
@Override
@@ -812,7 +815,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (background != null) {
final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL;
background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]);
- background.setAlpha(PREVIEW_ALPHA);
}
ViewLayoutUtils.placeViewAt(
previewText, previewX, previewY, previewWidth, previewHeight);
@@ -1188,26 +1190,27 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
}
- private static boolean fitsTextIntoWidth(final int width, final String text,
- final Paint paint) {
+ 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);
if (textWidth < width) {
return true;
}
- final float scaleX = width / textWidth;
+ final float scaleX = maxTextWidth / textWidth;
if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) {
return false;
}
paint.setTextScaleX(scaleX);
- return TypefaceUtils.getLabelWidth(text, paint) < width;
+ return TypefaceUtils.getLabelWidth(text, paint) < maxTextWidth;
}
// Layout language name on spacebar.
- private static String layoutLanguageOnSpacebar(final Paint paint,
+ private String layoutLanguageOnSpacebar(final Paint paint,
final InputMethodSubtype subtype, final int width) {
+
// Choose appropriate language name to fit into the width.
final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype);
if (fitsTextIntoWidth(width, fullText, paint)) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
index a2001cb8f..6b76e2461 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java
@@ -39,7 +39,7 @@ public final class MoreKeysDetector extends KeyDetector {
Key nearestKey = null;
int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
- for (final Key key : getKeyboard().mKeys) {
+ for (final Key key : getKeyboard().getKeys()) {
final int dist = key.squaredDistanceToEdge(touchX, touchY);
if (dist < nearestDist) {
nearestKey = key;
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index d4d0d8718..ee4ac950c 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -346,6 +346,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// true if this pointer is in a sliding key input from a modifier key,
// so that further modifier keys should be ignored.
boolean mIsInSlidingKeyInputFromModifier;
+ // 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;
@@ -937,9 +939,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (!sShouldHandleGesture) {
return;
}
- // A gesture should start only from a non-modifier key.
+ // A gesture should start only from a non-modifier key. Note that the gesture detection is
+ // disabled when the key is repeating.
mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
- && key != null && !key.isModifier() && !key.isRepeatable();
+ && key != null && !key.isModifier();
if (mIsDetectingGesture) {
if (getActivePointerTrackerCount() == 1) {
sGestureFirstDownTime = eventTime;
@@ -1247,6 +1250,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mIsDetectingGesture = false;
final Key currentKey = mCurrentKey;
mCurrentKey = null;
+ final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode;
+ mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
// Release the last pressed key.
setReleasedKeyGraphics(currentKey);
@@ -1272,8 +1277,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (mIsTrackingForActionDisabled) {
return;
}
- if (currentKey != null && currentKey.isRepeatable() && !isInSlidingKeyInput) {
- // Repeatable key has been registered in {@link #onDownEventInternal(int,int,long)}.
+ if (currentKey != null && currentKey.isRepeatable()
+ && (currentKey.getCode() == currentRepeatingKeyCode) && !isInSlidingKeyInput) {
return;
}
detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
@@ -1412,7 +1417,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (!key.isRepeatable()) return;
// Don't start key repeat when we are in sliding input mode.
if (mIsInSlidingKeyInput) return;
- detectAndSendKey(key, key.getX(), key.getY(), SystemClock.uptimeMillis());
final int startRepeatCount = 1;
mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout);
}
@@ -1420,8 +1424,11 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public void onKeyRepeat(final int code, final int repeatCount) {
final Key key = getKey();
if (key == null || key.getCode() != code) {
+ mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
return;
}
+ mCurrentRepeatingKeyCode = code;
+ mIsDetectingGesture = false;
final int nextRepeatCount = repeatCount + 1;
mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval);
callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount);
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index c0c02f10a..a0316696c 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -245,8 +245,8 @@ public class ProximityInfo {
final int threshold = (int) (defaultWidth * SEARCH_DISTANCE);
final int thresholdSquared = threshold * threshold;
// Round-up so we don't have any pixels outside the grid
- final int fullGridWidth = mGridWidth * mCellWidth;
- final int fullGridHeight = mGridHeight * mCellHeight;
+ final int lastPixelXCoordinate = mGridWidth * mCellWidth - 1;
+ final int lastPixelYCoordinate = mGridHeight * mCellHeight - 1;
// For large layouts, 'neighborsFlatBuffer' is about 80k of memory: gridSize is usually 512,
// keycount is about 40 and a pointer to a Key is 4 bytes. This contains, for each cell,
@@ -329,14 +329,14 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
final int yMiddleOfTopCell = topPixelWithinThreshold - yDeltaToGrid + halfCellHeight;
final int yStart = Math.max(halfCellHeight,
yMiddleOfTopCell + (yDeltaToGrid <= halfCellHeight ? 0 : mCellHeight));
- final int yEnd = Math.min(fullGridHeight, keyY + key.getHeight() + threshold);
+ final int yEnd = Math.min(lastPixelYCoordinate, keyY + key.getHeight() + threshold);
final int leftPixelWithinThreshold = keyX - threshold;
final int xDeltaToGrid = leftPixelWithinThreshold % mCellWidth;
final int xMiddleOfLeftCell = leftPixelWithinThreshold - xDeltaToGrid + halfCellWidth;
final int xStart = Math.max(halfCellWidth,
xMiddleOfLeftCell + (xDeltaToGrid <= halfCellWidth ? 0 : mCellWidth));
- final int xEnd = Math.min(fullGridWidth, keyX + key.getWidth() + threshold);
+ final int xEnd = Math.min(lastPixelXCoordinate, keyX + key.getWidth() + threshold);
int baseIndexOfCurrentRow = (yStart / mCellHeight) * mGridWidth + (xStart / mCellWidth);
for (int centerY = yStart; centerY <= yEnd; centerY += mCellHeight) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java
new file mode 100644
index 000000000..c10fdbace
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+/**
+ * The string parser of codesArray specification for <GridRows />. The attribute codesArray is an
+ * array of string.
+ * Each element of the array defines a key label by specifying a code point as a hexadecimal string.
+ * A key label may consist of multiple code points separated by comma.
+ * Each element of the array optionally can have an output text definition after vertical bar
+ * 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]*)?
+ * </pre>
+ */
+// TODO: Write unit tests for this class.
+public final class CodesArrayParser {
+ // Constants for parsing.
+ private static final char COMMA = ',';
+ private static final char VERTICAL_BAR = '|';
+ private static final String COMMA_STRING = ",";
+ private static final int BASE_HEX = 16;
+
+ private CodesArrayParser() {
+ // This utility class is not publicly instantiable.
+ }
+
+ private static String getLabelSpec(final String codesArraySpec) {
+ final int pos = codesArraySpec.indexOf(VERTICAL_BAR);
+ return (pos < 0) ? codesArraySpec : codesArraySpec.substring(0, pos);
+ }
+
+ 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)) {
+ final int codePoint = Integer.parseInt(codeInHex, BASE_HEX);
+ sb.appendCodePoint(codePoint);
+ }
+ return sb.toString();
+ }
+
+ private static String getCodeSpec(final String codesArraySpec) {
+ final int pos = codesArraySpec.indexOf(VERTICAL_BAR);
+ return (pos < 0) ? codesArraySpec : codesArraySpec.substring(pos + 1);
+ }
+
+ public static int parseCode(final String codesArraySpec) {
+ final String codeSpec = getCodeSpec(codesArraySpec);
+ if (codeSpec.indexOf(COMMA) < 0) {
+ return Integer.parseInt(codeSpec, BASE_HEX);
+ }
+ return Constants.CODE_OUTPUT_TEXT;
+ }
+
+ public static String parseOutputText(final String codesArraySpec) {
+ final String codeSpec = getCodeSpec(codesArraySpec);
+ if (codeSpec.indexOf(COMMA) < 0) {
+ return null;
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (final String codeInHex : codeSpec.split(COMMA_STRING)) {
+ final int codePoint = Integer.parseInt(codeInHex, BASE_HEX);
+ sb.appendCodePoint(codePoint);
+ }
+ return sb.toString();
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
new file mode 100644
index 000000000..0dd71e2ec
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.inputmethod.keyboard.EmojiKeyboardView;
+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 java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This is a Keyboard class where you can add keys dynamically shown in a grid layout
+ */
+public class DynamicGridKeyboard extends Keyboard {
+ private static final String TAG = DynamicGridKeyboard.class.getSimpleName();
+ private static final int TEMPLATE_KEY_CODE_0 = 0x30;
+ private static final int TEMPLATE_KEY_CODE_1 = 0x31;
+
+ private final SharedPreferences mPrefs;
+ private final int mLeftPadding;
+ private final int mHorizontalStep;
+ private final int mVerticalStep;
+ private final int mColumnsNum;
+ private final int mMaxKeyCount;
+ private final boolean mIsRecents;
+ private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
+
+ private Key[] mCachedGridKeys;
+
+ public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
+ final int maxKeyCount, final int categoryId, final int categoryPageId) {
+ super(templateKeyboard);
+ final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
+ final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
+ mLeftPadding = key0.getX();
+ mHorizontalStep = Math.abs(key1.getX() - key0.getX());
+ mVerticalStep = key0.getHeight() + mVerticalGap;
+ mColumnsNum = mBaseWidth / mHorizontalStep;
+ mMaxKeyCount = maxKeyCount;
+ mIsRecents = categoryId == EmojiKeyboardView.CATEGORY_ID_RECENTS;
+ mPrefs = prefs;
+ }
+
+ private Key getTemplateKey(final int code) {
+ for (final Key key : super.getKeys()) {
+ if (key.getCode() == code) {
+ return key;
+ }
+ }
+ throw new RuntimeException("Can't find template key: code=" + code);
+ }
+
+ public void addKeyFirst(final Key usedKey) {
+ addKey(usedKey, true);
+ if (mIsRecents) {
+ saveRecentKeys();
+ }
+ }
+
+ public void addKeyLast(final Key usedKey) {
+ addKey(usedKey, false);
+ }
+
+ private void addKey(final Key usedKey, final boolean addFirst) {
+ if (usedKey == null) {
+ return;
+ }
+ synchronized (mGridKeys) {
+ mCachedGridKeys = null;
+ final GridKey key = new GridKey(usedKey);
+ while (mGridKeys.remove(key)) {
+ // Remove duplicate keys.
+ }
+ if (addFirst) {
+ mGridKeys.addFirst(key);
+ } else {
+ mGridKeys.addLast(key);
+ }
+ while (mGridKeys.size() > mMaxKeyCount) {
+ mGridKeys.removeLast();
+ }
+ int index = 0;
+ for (final GridKey gridKey : mGridKeys) {
+ final int keyX = getKeyX(index);
+ final int keyY = getKeyY(index);
+ gridKey.updateCorrdinates(keyX, keyY);
+ index++;
+ }
+ }
+ }
+
+ private void saveRecentKeys() {
+ final ArrayList<Object> keys = CollectionUtils.newArrayList();
+ for (final Key key : mGridKeys) {
+ if (key.getOutputText() != null) {
+ keys.add(key.getOutputText());
+ } else {
+ keys.add(key.getCode());
+ }
+ }
+ final String jsonStr = StringUtils.listToJsonStr(keys);
+ Settings.writeEmojiRecentKeys(mPrefs, jsonStr);
+ }
+
+ private static Key getKey(final Collection<DynamicGridKeyboard> keyboards, final Object o) {
+ for (final DynamicGridKeyboard kbd : keyboards) {
+ if (o instanceof Integer) {
+ final int code = (Integer) o;
+ final Key key = kbd.getKey(code);
+ if (key != null) {
+ 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);
+ }
+ }
+ return null;
+ }
+
+ public void loadRecentKeys(Collection<DynamicGridKeyboard> keyboards) {
+ final String str = Settings.readEmojiRecentKeys(mPrefs);
+ final List<Object> keys = StringUtils.jsonStrToList(str);
+ for (final Object o : keys) {
+ addKeyLast(getKey(keyboards, o));
+ }
+ }
+
+ private int getKeyX(final int index) {
+ final int column = index % mColumnsNum;
+ return column * mHorizontalStep + mLeftPadding;
+ }
+
+ private int getKeyY(final int index) {
+ final int row = index / mColumnsNum;
+ return row * mVerticalStep + mTopPadding;
+ }
+
+ @Override
+ public Key[] getKeys() {
+ synchronized (mGridKeys) {
+ if (mCachedGridKeys != null) {
+ return mCachedGridKeys;
+ }
+ mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
+ return mCachedGridKeys;
+ }
+ }
+
+ @Override
+ public Key[] getNearestKeys(final int x, final int y) {
+ // TODO: Calculate the nearest key index in mGridKeys from x and y.
+ return getKeys();
+ }
+
+ static final class GridKey extends Key {
+ private int mCurrentX;
+ private int mCurrentY;
+
+ public GridKey(final Key originalKey) {
+ super(originalKey);
+ }
+
+ public void updateCorrdinates(final int x, final int y) {
+ mCurrentX = x;
+ mCurrentY = y;
+ getHitBox().set(x, y, x + getWidth(), y + getHeight());
+ }
+
+ @Override
+ public int getX() {
+ return mCurrentX;
+ }
+
+ @Override
+ public int getY() {
+ return mCurrentY;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (!(o instanceof Key)) return false;
+ final Key key = (Key)o;
+ if (getCode() != key.getCode()) return false;
+ if (!TextUtils.equals(getLabel(), key.getLabel())) return false;
+ return TextUtils.equals(getOutputText(), key.getOutputText());
+ }
+
+ @Override
+ public String toString() {
+ return "GridKey: " + super.toString();
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java
index f65056948..e6a674334 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java
@@ -24,7 +24,7 @@ public abstract class KeyStyle {
public abstract String[] getStringArray(TypedArray a, int index);
public abstract String getString(TypedArray a, int index);
public abstract int getInt(TypedArray a, int index, int defaultValue);
- public abstract int getFlag(TypedArray a, int index);
+ public abstract int getFlags(TypedArray a, int index);
protected KeyStyle(final KeyboardTextsSet textsSet) {
mTextsSet = textsSet;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
index 6aab3e7b3..05d855e31 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
@@ -66,7 +66,7 @@ public final class KeyStylesSet {
}
@Override
- public int getFlag(final TypedArray a, final int index) {
+ public int getFlags(final TypedArray a, final int index) {
return a.getInt(index, 0);
}
}
@@ -123,14 +123,12 @@ public final class KeyStylesSet {
}
@Override
- public int getFlag(final TypedArray a, final int index) {
- int flags = a.getInt(index, 0);
- final Object value = mStyleAttributes.get(index);
- if (value != null) {
- flags |= (Integer)value;
- }
- final KeyStyle parentStyle = mStyles.get(mParentStyleName);
- return flags | parentStyle.getFlag(a, index);
+ public int getFlags(final TypedArray a, final int index) {
+ final int parentFlags = mStyles.get(mParentStyleName).getFlags(a, index);
+ final Integer value = (Integer)mStyleAttributes.get(index);
+ final int styleFlags = (value != null) ? value : 0;
+ final int flags = a.getInt(index, 0);
+ return flags | styleFlags | parentFlags;
}
public void readKeyAttributes(final TypedArray keyAttr) {
@@ -142,13 +140,13 @@ public final class KeyStylesSet {
readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
readStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys);
- readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
+ 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);
readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType);
- readFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
+ readFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
}
private void readString(final TypedArray a, final int index) {
@@ -163,10 +161,11 @@ public final class KeyStylesSet {
}
}
- private void readFlag(final TypedArray a, final int index) {
+ private void readFlags(final TypedArray a, final int index) {
if (a.hasValue(index)) {
final Integer value = (Integer)mStyleAttributes.get(index);
- mStyleAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+ final int styleFlags = value != null ? value : 0;
+ mStyleAttributes.put(index, a.getInt(index, 0) | styleFlags);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index 9bc52e567..22f7a83fc 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -29,6 +29,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.RunInLocale;
@@ -113,6 +114,7 @@ import java.util.Locale;
* </pre>
*/
+// TODO: Write unit tests for this class.
public class KeyboardBuilder<KP extends KeyboardParams> {
private static final String BUILDER_TAG = "Keyboard.Builder";
private static final boolean DEBUG = false;
@@ -120,6 +122,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
// Keyboard XML Tags
private static final String TAG_KEYBOARD = "Keyboard";
private static final String TAG_ROW = "Row";
+ private static final String TAG_GRID_ROWS = "GridRows";
private static final String TAG_KEY = "Key";
private static final String TAG_SPACER = "Spacer";
private static final String TAG_INCLUDE = "include";
@@ -312,6 +315,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
startRow(row);
}
parseRowContent(parser, row, skip);
+ } else if (TAG_GRID_ROWS.equals(tag)) {
+ if (DEBUG) startTag("<%s>%s", TAG_GRID_ROWS, skip ? " skipped" : "");
+ parseGridRows(parser, skip);
} else if (TAG_INCLUDE.equals(tag)) {
parseIncludeKeyboardContent(parser, skip);
} else if (TAG_SWITCH.equals(tag)) {
@@ -389,6 +395,73 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
}
}
+ private void parseGridRows(final XmlPullParser parser, final boolean skip)
+ throws XmlPullParserException, IOException {
+ if (skip) {
+ XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser);
+ if (DEBUG) {
+ startEndTag("<%s /> skipped", TAG_GRID_ROWS);
+ }
+ return;
+ }
+ final KeyboardRow gridRows = new KeyboardRow(mResources, mParams, parser, mCurrentY);
+ final TypedArray gridRowAttr = mResources.obtainAttributes(
+ Xml.asAttributeSet(parser), R.styleable.Keyboard_GridRows);
+ final int codesArrayId = gridRowAttr.getResourceId(
+ R.styleable.Keyboard_GridRows_codesArray, 0);
+ final int textsArrayId = gridRowAttr.getResourceId(
+ R.styleable.Keyboard_GridRows_textsArray, 0);
+ gridRowAttr.recycle();
+ if (codesArrayId == 0 && textsArrayId == 0) {
+ throw new XmlParseUtils.ParseException(
+ "Missing codesArray or textsArray attributes", parser);
+ }
+ if (codesArrayId != 0 && textsArrayId != 0) {
+ throw new XmlParseUtils.ParseException(
+ "Both codesArray and textsArray attributes specifed", parser);
+ }
+ final String[] array = mResources.getStringArray(
+ codesArrayId != 0 ? codesArrayId : textsArrayId);
+ final int counts = array.length;
+ final float keyWidth = gridRows.getKeyWidth(null, 0.0f);
+ final int numColumns = (int)(mParams.mOccupiedWidth / keyWidth);
+ for (int index = 0; index < counts; index += numColumns) {
+ final KeyboardRow row = new KeyboardRow(mResources, mParams, parser, mCurrentY);
+ startRow(row);
+ for (int c = 0; c < numColumns; c++) {
+ final int i = index + c;
+ if (i >= counts) {
+ break;
+ }
+ final String label;
+ final int code;
+ final String outputText;
+ if (codesArrayId != 0) {
+ final String codeArraySpec = array[i];
+ label = CodesArrayParser.parseLabel(codeArraySpec);
+ code = CodesArrayParser.parseCode(codeArraySpec);
+ outputText = CodesArrayParser.parseOutputText(codeArraySpec);
+ } else {
+ final String textArraySpec = array[i];
+ // TODO: Utilize KeySpecParser or write more generic TextsArrayParser.
+ label = textArraySpec;
+ code = Constants.CODE_OUTPUT_TEXT;
+ outputText = textArraySpec + (char)Constants.CODE_SPACE;
+ }
+ 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());
+ endKey(key);
+ row.advanceXPos(keyWidth);
+ }
+ endRow(row);
+ }
+
+ XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser);
+ }
+
private void parseKey(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
throws XmlPullParserException, IOException {
if (skip) {
@@ -440,9 +513,6 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
attr, R.styleable.Keyboard_Include);
final TypedArray keyAttr = mResources.obtainAttributes(attr, R.styleable.Keyboard_Key);
int keyboardLayout = 0;
- float savedDefaultKeyWidth = 0;
- int savedDefaultKeyLabelFlags = 0;
- int savedDefaultBackgroundType = Key.BACKGROUND_TYPE_NORMAL;
try {
XmlParseUtils.checkAttributeExists(
keyboardAttr, R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout",
@@ -450,24 +520,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
keyboardLayout = keyboardAttr.getResourceId(
R.styleable.Keyboard_Include_keyboardLayout, 0);
if (row != null) {
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
- // Override current x coordinate.
- row.setXPos(row.getKeyX(keyAttr));
- }
- // TODO: Remove this if-clause and do the same as backgroundType below.
- savedDefaultKeyWidth = row.getDefaultKeyWidth();
- if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) {
- // Override default key width.
- row.setDefaultKeyWidth(row.getKeyWidth(keyAttr));
- }
- savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags();
- // Bitwise-or default keyLabelFlag if exists.
- row.setDefaultKeyLabelFlags(keyAttr.getInt(
- R.styleable.Keyboard_Key_keyLabelFlags, 0) | savedDefaultKeyLabelFlags);
- savedDefaultBackgroundType = row.getDefaultBackgroundType();
- // Override default backgroundType if exists.
- row.setDefaultBackgroundType(keyAttr.getInt(
- R.styleable.Keyboard_Key_backgroundType, savedDefaultBackgroundType));
+ // Override current x coordinate.
+ row.setXPos(row.getKeyX(keyAttr));
+ // Push current Row attributes and update with new attributes.
+ row.pushRowAttributes(keyAttr);
}
} finally {
keyboardAttr.recycle();
@@ -484,10 +540,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
parseMerge(parserForInclude, row, skip);
} finally {
if (row != null) {
- // Restore default keyWidth, keyLabelFlags, and backgroundType.
- row.setDefaultKeyWidth(savedDefaultKeyWidth);
- row.setDefaultKeyLabelFlags(savedDefaultKeyLabelFlags);
- row.setDefaultBackgroundType(savedDefaultBackgroundType);
+ // Restore Row attributes.
+ row.popRowAttributes();
}
parserForInclude.close();
}
@@ -571,6 +625,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final AttributeSet attr = Xml.asAttributeSet(parser);
final TypedArray caseAttr = mResources.obtainAttributes(attr, R.styleable.Keyboard_Case);
try {
+ final boolean keyboardLayoutSetMatched = matchString(caseAttr,
+ R.styleable.Keyboard_Case_keyboardLayoutSet,
+ SubtypeLocaleUtils.getKeyboardLayoutSetName(id.mSubtype));
final boolean keyboardLayoutSetElementMatched = matchTypedValue(caseAttr,
R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId,
KeyboardId.elementIdToName(id.mElementId));
@@ -603,15 +660,18 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
final boolean countryCodeMatched = matchString(caseAttr,
R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
- final boolean selected = keyboardLayoutSetElementMatched && modeMatched
- && navigateNextMatched && navigatePreviousMatched && passwordInputMatched
- && clobberSettingsKeyMatched && shortcutKeyEnabledMatched
- && shortcutKeyOnSymbolsMatched && hasShortcutKeyMatched
- && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched
- && localeCodeMatched && languageCodeMatched && countryCodeMatched;
+ final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched
+ && modeMatched && navigateNextMatched && navigatePreviousMatched
+ && passwordInputMatched && clobberSettingsKeyMatched
+ && shortcutKeyEnabledMatched && shortcutKeyOnSymbolsMatched
+ && 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", TAG_CASE,
+ startTag("<%s%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(
R.styleable.Keyboard_Case_keyboardLayoutSetElement),
"keyboardLayoutSetElement"),
@@ -745,7 +805,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
mRightEdgeKey = null;
}
addEdgeSpace(mParams.mRightPadding, row);
- mCurrentY += row.mRowHeight;
+ mCurrentY += row.getRowHeight();
mCurrentRow = null;
mTopEdge = false;
}
@@ -763,7 +823,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
}
private void endKeyboard() {
- // nothing to do here.
+ // {@link #parseGridRows(XmlPullParser,boolean)} may populate keyboard rows higher than
+ // previously expected.
+ final int actualHeight = mCurrentY - mParams.mVerticalGap + mParams.mBottomPadding;
+ mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight);
}
private void addEdgeSpace(final float width, final KeyboardRow row) {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
index edfcec7e1..0f9497c27 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
@@ -23,10 +23,13 @@ import android.util.Xml;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import org.xmlpull.v1.XmlPullParser;
+import java.util.ArrayDeque;
+
/**
* Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
* Some of the key size defaults can be overridden per row from what the {@link Keyboard}
@@ -38,64 +41,100 @@ public final class KeyboardRow {
private static final int KEYWIDTH_FILL_RIGHT = -1;
private final KeyboardParams mParams;
- /** Default width of a key in this row. */
- private float mDefaultKeyWidth;
- /** Default height of a key in this row. */
- public final int mRowHeight;
- /** Default keyLabelFlags in this row. */
- private int mDefaultKeyLabelFlags;
- /** Default backgroundType for this row */
- private int mDefaultBackgroundType;
+ /** The height of this row. */
+ private final int mRowHeight;
+
+ private final ArrayDeque<RowAttributes> mRowAttributesStack = CollectionUtils.newArrayDeque();
+
+ private static class RowAttributes {
+ /** Default width of a key in this row. */
+ public final float mDefaultKeyWidth;
+ /** Default keyLabelFlags in this row. */
+ public final int mDefaultKeyLabelFlags;
+ /** Default backgroundType for this row */
+ public final int mDefaultBackgroundType;
+
+ /**
+ * Parse and create key attributes. This constructor is used to parse Row tag.
+ *
+ * @param keyAttr an attributes array of Row tag.
+ * @param defaultKeyWidth a default key width.
+ * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute.
+ */
+ public RowAttributes(final TypedArray keyAttr, final float defaultKeyWidth,
+ final int keyboardWidth) {
+ mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth,
+ keyboardWidth, keyboardWidth, defaultKeyWidth);
+ mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0);
+ mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
+ Key.BACKGROUND_TYPE_NORMAL);
+ }
+
+ /**
+ * Parse and update key attributes using default attributes. This constructor is used
+ * to parse include tag.
+ *
+ * @param keyAttr an attributes array of include tag.
+ * @param defaultRowAttr default Row attributes.
+ * @param keyboardWidth the keyboard width that is required to calculate keyWidth attribute.
+ */
+ public RowAttributes(final TypedArray keyAttr, final RowAttributes defaultRowAttr,
+ final int keyboardWidth) {
+ mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth,
+ keyboardWidth, keyboardWidth, defaultRowAttr.mDefaultKeyWidth);
+ mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0)
+ | defaultRowAttr.mDefaultKeyLabelFlags;
+ mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
+ defaultRowAttr.mDefaultBackgroundType);
+ }
+ }
private final int mCurrentY;
// Will be updated by {@link Key}'s constructor.
private float mCurrentX;
- public KeyboardRow(final Resources res, final KeyboardParams params, final XmlPullParser parser,
- final int y) {
+ public KeyboardRow(final Resources res, final KeyboardParams params,
+ final XmlPullParser parser, final int y) {
mParams = params;
final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard);
mRowHeight = (int)ResourceUtils.getDimensionOrFraction(keyboardAttr,
- R.styleable.Keyboard_rowHeight,
- params.mBaseHeight, params.mDefaultRowHeight);
+ R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight);
keyboardAttr.recycle();
final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Key);
- mDefaultKeyWidth = keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth,
- params.mBaseWidth, params.mBaseWidth, params.mDefaultKeyWidth);
- mDefaultBackgroundType = keyAttr.getInt(R.styleable.Keyboard_Key_backgroundType,
- Key.BACKGROUND_TYPE_NORMAL);
+ mRowAttributesStack.push(new RowAttributes(
+ keyAttr, params.mDefaultKeyWidth, params.mBaseWidth));
keyAttr.recycle();
- // TODO: Initialize this with <Row> attribute as backgroundType is done.
- mDefaultKeyLabelFlags = 0;
mCurrentY = y;
mCurrentX = 0.0f;
}
- public float getDefaultKeyWidth() {
- return mDefaultKeyWidth;
+ public int getRowHeight() {
+ return mRowHeight;
}
- public void setDefaultKeyWidth(final float defaultKeyWidth) {
- mDefaultKeyWidth = defaultKeyWidth;
+ public void pushRowAttributes(final TypedArray keyAttr) {
+ final RowAttributes newAttributes = new RowAttributes(
+ keyAttr, mRowAttributesStack.peek(), mParams.mBaseWidth);
+ mRowAttributesStack.push(newAttributes);
}
- public int getDefaultKeyLabelFlags() {
- return mDefaultKeyLabelFlags;
+ public void popRowAttributes() {
+ mRowAttributesStack.pop();
}
- public void setDefaultKeyLabelFlags(final int keyLabelFlags) {
- mDefaultKeyLabelFlags = keyLabelFlags;
+ public float getDefaultKeyWidth() {
+ return mRowAttributesStack.peek().mDefaultKeyWidth;
}
- public int getDefaultBackgroundType() {
- return mDefaultBackgroundType;
+ public int getDefaultKeyLabelFlags() {
+ return mRowAttributesStack.peek().mDefaultKeyLabelFlags;
}
- public void setDefaultBackgroundType(final int backgroundType) {
- mDefaultBackgroundType = backgroundType;
+ public int getDefaultBackgroundType() {
+ return mRowAttributesStack.peek().mDefaultBackgroundType;
}
public void setXPos(final float keyXPos) {
@@ -128,13 +167,9 @@ public final class KeyboardRow {
return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
}
- public float getKeyWidth(final TypedArray keyAttr) {
- return getKeyWidth(keyAttr, mCurrentX);
- }
-
public float getKeyWidth(final TypedArray keyAttr, final float keyXPos) {
if (keyAttr == null) {
- return mDefaultKeyWidth;
+ return getDefaultKeyWidth();
}
final int widthType = ResourceUtils.getEnumValue(keyAttr,
R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
@@ -146,7 +181,7 @@ public final class KeyboardRow {
return keyboardRightEdge - keyXPos;
default: // KEYWIDTH_NOT_ENUM
return keyAttr.getFraction(R.styleable.Keyboard_Key_keyWidth,
- mParams.mBaseWidth, mParams.mBaseWidth, mDefaultKeyWidth);
+ mParams.mBaseWidth, mParams.mBaseWidth, getDefaultKeyWidth());
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 164910dd4..9f9fdaa6f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -45,6 +45,7 @@ public final class KeyboardState {
public void setAlphabetAutomaticShiftedKeyboard();
public void setAlphabetShiftLockedKeyboard();
public void setAlphabetShiftLockShiftedKeyboard();
+ public void setEmojiKeyboard();
public void setSymbolsKeyboard();
public void setSymbolsShiftedKeyboard();
@@ -74,7 +75,10 @@ public final class KeyboardState {
private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 5;
private int mSwitchState = SWITCH_STATE_ALPHA;
+ // TODO: Consolidate these two mode booleans into one integer to distinguish between alphabet,
+ // symbols, and emoji mode.
private boolean mIsAlphabetMode;
+ private boolean mIsEmojiMode;
private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState();
private boolean mIsSymbolShifted;
private boolean mPrevMainKeyboardWasShiftLocked;
@@ -91,6 +95,7 @@ public final class KeyboardState {
public boolean mIsValid;
public boolean mIsAlphabetMode;
public boolean mIsAlphabetShiftLocked;
+ public boolean mIsEmojiMode;
public int mShiftMode;
@Override
@@ -99,6 +104,8 @@ public final class KeyboardState {
if (mIsAlphabetMode) {
if (mIsAlphabetShiftLocked) return "ALPHABET_SHIFT_LOCKED";
return "ALPHABET_" + shiftModeToString(mShiftMode);
+ } else if (mIsEmojiMode) {
+ return "EMOJI";
} else {
return "SYMBOLS_" + shiftModeToString(mShiftMode);
}
@@ -131,6 +138,7 @@ public final class KeyboardState {
public void onSaveKeyboardState() {
final SavedKeyboardState state = mSavedKeyboardState;
state.mIsAlphabetMode = mIsAlphabetMode;
+ state.mIsEmojiMode = mIsEmojiMode;
if (mIsAlphabetMode) {
state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked();
state.mShiftMode = mAlphabetShiftState.isAutomaticShifted() ? AUTOMATIC_SHIFT
@@ -152,6 +160,8 @@ public final class KeyboardState {
}
if (!state.mIsValid || state.mIsAlphabetMode) {
setAlphabetKeyboard();
+ } else if (state.mIsEmojiMode) {
+ setEmojiKeyboard();
} else {
if (state.mShiftMode == MANUAL_SHIFT) {
setSymbolsShiftedKeyboard();
@@ -280,6 +290,7 @@ public final class KeyboardState {
mSwitchActions.setAlphabetKeyboard();
mIsAlphabetMode = true;
+ mIsEmojiMode = false;
mIsSymbolShifted = false;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
mSwitchState = SWITCH_STATE_ALPHA;
@@ -310,6 +321,15 @@ public final class KeyboardState {
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
}
+ private void setEmojiKeyboard() {
+ if (DEBUG_ACTION) {
+ Log.d(TAG, "setEmojiKeyboard");
+ }
+ mIsAlphabetMode = false;
+ mIsEmojiMode = true;
+ mSwitchActions.setEmojiKeyboard();
+ }
+
public void onPressKey(final int code, final boolean isSinglePointer, final int autoCaps) {
if (DEBUG_EVENT) {
Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code)
@@ -460,7 +480,8 @@ public final class KeyboardState {
} else {
if (mAlphabetShiftState.isShiftLocked()) {
// Shift key is pressed while shift locked state, we will treat this state as
- // shift lock shifted state and mark as if shift key pressed while normal state.
+ // shift lock shifted state and mark as if shift key pressed while normal
+ // state.
setShifted(SHIFT_LOCK_SHIFTED);
mShiftKeyState.onPress();
} else if (mAlphabetShiftState.isAutomaticShifted()) {
@@ -564,7 +585,7 @@ public final class KeyboardState {
}
}
- private static boolean isSpaceCharacter(final int c) {
+ private static boolean isSpaceOrEnter(final int c) {
return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER;
}
@@ -587,12 +608,18 @@ public final class KeyboardState {
break;
case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
if (code == Constants.CODE_SHIFT) {
- // Detected only the shift key has been pressed on symbol layout, and then released.
+ // Detected only the shift key has been pressed on symbol layout, and then
+ // released.
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
}
break;
case SWITCH_STATE_SYMBOL_BEGIN:
- if (!isSpaceCharacter(code) && (Constants.isLetterCode(code)
+ if (mIsEmojiMode) {
+ // When in the Emoji keyboard, we don't want to switch back to the main layout even
+ // after the user hits an emoji letter followed by an enter or a space.
+ break;
+ }
+ if (!isSpaceOrEnter(code) && (Constants.isLetterCode(code)
|| code == Constants.CODE_OUTPUT_TEXT)) {
mSwitchState = SWITCH_STATE_SYMBOL;
}
@@ -600,7 +627,7 @@ public final class KeyboardState {
case SWITCH_STATE_SYMBOL:
// Switch back to alpha keyboard mode if user types one or more non-space/enter
// characters followed by a space/enter.
- if (isSpaceCharacter(code)) {
+ if (isSpaceOrEnter(code)) {
toggleAlphabetAndSymbols();
mPrevSymbolsKeyboardWasShifted = false;
}
@@ -610,6 +637,8 @@ public final class KeyboardState {
// If the code is a letter, update keyboard shift state.
if (Constants.isLetterCode(code)) {
updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
+ } else if (code == Constants.CODE_EMOJI) {
+ setEmojiKeyboard();
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index bb49f4758..67553fb75 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -153,8 +153,8 @@ public final class KeyboardTextsSet {
/* 48 */ "single_angle_quotes",
/* 49 */ "double_angle_quotes",
/* 50 */ "more_keys_for_currency_dollar",
- /* 51 */ "keylabel_for_currency_generic",
- /* 52 */ "more_keys_for_currency_generic",
+ /* 51 */ "keylabel_for_currency",
+ /* 52 */ "more_keys_for_currency",
/* 53 */ "more_keys_for_punctuation",
/* 54 */ "more_keys_for_star",
/* 55 */ "more_keys_for_bullet",
@@ -233,25 +233,24 @@ public final class KeyboardTextsSet {
/* 128 */ "label_to_phone_symbols_key",
/* 129 */ "label_time_am",
/* 130 */ "label_time_pm",
- /* 131 */ "label_to_symbol_key_pcqwerty",
- /* 132 */ "keylabel_for_popular_domain",
- /* 133 */ "more_keys_for_popular_domain",
- /* 134 */ "more_keys_for_smiley",
- /* 135 */ "single_laqm_raqm",
- /* 136 */ "single_laqm_raqm_rtl",
- /* 137 */ "single_raqm_laqm",
- /* 138 */ "double_laqm_raqm",
- /* 139 */ "double_laqm_raqm_rtl",
- /* 140 */ "double_raqm_laqm",
- /* 141 */ "single_lqm_rqm",
- /* 142 */ "single_9qm_lqm",
- /* 143 */ "single_9qm_rqm",
- /* 144 */ "double_lqm_rqm",
- /* 145 */ "double_9qm_lqm",
- /* 146 */ "double_9qm_rqm",
- /* 147 */ "more_keys_for_single_quote",
- /* 148 */ "more_keys_for_double_quote",
- /* 149 */ "more_keys_for_tablet_double_quote",
+ /* 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",
};
private static final String EMPTY = "";
@@ -278,7 +277,7 @@ public final class KeyboardTextsSet {
/* 50 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
/* 51 */ "$",
/* 52 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
- /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
+ /* 53 */ "!fixedColumnOrder!3,!,\\,,?,:,;,@",
// U+2020: "†" DAGGER
// U+2021: "‡" DOUBLE DAGGER
// U+2605: "★" BLACK STAR
@@ -361,10 +360,11 @@ public final class KeyboardTextsSet {
// U+2030: "‰" PER MILLE SIGN
/* 103 */ "\u2030",
/* 104 */ ",",
- /* 105 */ "!",
- /* 106 */ "!",
- /* 107 */ "?",
- /* 108 */ "?",
+ /* 105~ */
+ EMPTY, EMPTY, EMPTY,
+ /* ~107 */
+ // U+2026: "…" HORIZONTAL ELLIPSIS
+ /* 108 */ "\u2026",
/* 109 */ "\'",
/* 110 */ "\"",
/* 111 */ "\"",
@@ -383,7 +383,7 @@ public final class KeyboardTextsSet {
// 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 */ "~ \\ {",
+ /* 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!
@@ -396,12 +396,10 @@ public final class KeyboardTextsSet {
/* 129 */ "AM",
// Key label for "post meridiem"
/* 130 */ "PM",
- // Label for "switch to symbols" key on PC QWERTY layout
- /* 131 */ "Sym",
- /* 132 */ ".com",
+ /* 131 */ ".com",
// popular web domains for the locale - most popular, displayed on the keyboard
- /* 133 */ "!hasLabels!,.net,.org,.gov,.edu",
- /* 134 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+ /* 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
@@ -423,24 +421,24 @@ public final class KeyboardTextsSet {
// 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>.
- /* 135 */ "\u2039,\u203A",
- /* 136 */ "\u2039|\u203A,\u203A|\u2039",
- /* 137 */ "\u203A,\u2039",
- /* 138 */ "\u00AB,\u00BB",
- /* 139 */ "\u00AB|\u00BB,\u00BB|\u00AB",
- /* 140 */ "\u00BB,\u00AB",
+ /* 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>.
- /* 141 */ "\u201A,\u2018,\u2019",
- /* 142 */ "\u2019,\u201A,\u2018",
- /* 143 */ "\u2018,\u201A,\u2019",
- /* 144 */ "\u201E,\u201C,\u201D",
- /* 145 */ "\u201D,\u201E,\u201C",
- /* 146 */ "\u201C,\u201E,\u201D",
- /* 147 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
- /* 148 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
- /* 149 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
+ /* 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",
};
/* Language af: Afrikaans */
@@ -785,7 +783,7 @@ public final class KeyboardTextsSet {
null, null, null, null, null, null, null, null,
/* ~52 */
// U+00B7: "·" MIDDLE DOT
- /* 53 */ "!fixedColumnOrder!9,\u00B7,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
+ /* 53 */ "!fixedColumnOrder!4,\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,
@@ -1257,7 +1255,7 @@ public final class KeyboardTextsSet {
/* ~52 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 53 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)",
+ /* 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,
@@ -1402,9 +1400,10 @@ public final class KeyboardTextsSet {
/* 47 */ null,
/* 48 */ "!text/single_laqm_raqm_rtl",
/* 49 */ "!text/double_laqm_raqm_rtl",
- /* 50~ */
- null, null, null,
- /* ~52 */
+ /* 50 */ null,
+ // U+FDFC: "﷼" RIAL SIGN
+ /* 51 */ "\uFDFC",
+ /* 52 */ null,
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
@@ -1762,6 +1761,37 @@ public final class KeyboardTextsSet {
/* 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
@@ -1899,10 +1929,11 @@ public final class KeyboardTextsSet {
/* 47 */ "\u201C,\u201D,\u201E",
/* 48 */ "!text/single_laqm_raqm_rtl",
/* 49 */ "!text/double_laqm_raqm_rtl",
- /* 50~ */
- null, null, null,
- /* ~52 */
- /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(|),)|(",
+ /* 50 */ null,
+ // U+20AA: "₪" NEW SHEQEL SIGN
+ /* 51 */ "\u20AA",
+ /* 52 */ null,
+ /* 53 */ null,
// U+2605: "★" BLACK STAR
/* 54 */ "\u2605",
/* 55 */ null,
@@ -1921,6 +1952,15 @@ public final class KeyboardTextsSet {
// 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 */
@@ -1987,6 +2027,25 @@ public final class KeyboardTextsSet {
/* 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~ */
@@ -2028,6 +2087,25 @@ public final class KeyboardTextsSet {
/* 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
@@ -2319,6 +2397,63 @@ public final class KeyboardTextsSet {
/* 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
@@ -3297,17 +3432,21 @@ public final class KeyboardTextsSet {
"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 */
diff --git a/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java b/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java
new file mode 100644
index 000000000..b8ee976e8
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/ScrollKeyboardView.java
@@ -0,0 +1,212 @@
+/*
+ * 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.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.latin.R;
+
+/**
+ * This is an extended {@link KeyboardView} class that hosts a scroll keyboard.
+ * Multi-touch unsupported. No {@link PointerTracker}s. No gesture support.
+ */
+// TODO: Implement key popup preview.
+public final class ScrollKeyboardView extends KeyboardView implements
+ ScrollViewWithNotifier.ScrollListener, GestureDetector.OnGestureListener {
+ private static final boolean PAGINATION = false;
+
+ public interface OnKeyClickListener {
+ public void onKeyClick(Key key);
+ }
+
+ private static final OnKeyClickListener EMPTY_LISTENER = new OnKeyClickListener() {
+ @Override
+ public void onKeyClick(final Key key) {}
+ };
+
+ private OnKeyClickListener mListener = EMPTY_LISTENER;
+ private final KeyDetector mKeyDetector = new KeyDetector(0.0f /*keyHysteresisDistance */);
+ private final GestureDetector mGestureDetector;
+
+ private final Scroller mScroller;
+ private ScrollViewWithNotifier mScrollView;
+
+ public ScrollKeyboardView(final Context context, final AttributeSet attrs) {
+ this(context, attrs, R.attr.keyboardViewStyle);
+ }
+
+ public ScrollKeyboardView(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();
+ }
+
+ public void setOnKeyClickListener(final OnKeyClickListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setKeyboard(final Keyboard keyboard) {
+ super.setKeyboard(keyboard);
+ mKeyDetector.setKeyboard(keyboard, 0 /* correctionX */, 0 /* correctionY */);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean onTouchEvent(final MotionEvent e) {
+ if (mGestureDetector.onTouchEvent(e)) {
+ return true;
+ }
+ final Key key = getKey(e);
+ if (key != null && key != mCurrentKey) {
+ releaseCurrentKey();
+ }
+ return true;
+ }
+
+ // {@link GestureDetector#OnGestureListener} methods.
+ private Key mCurrentKey;
+
+ private Key getKey(final MotionEvent e) {
+ final int index = e.getActionIndex();
+ final int x = (int)e.getX(index);
+ final int y = (int)e.getY(index);
+ return mKeyDetector.detectHitKey(x, y);
+ }
+
+ public void releaseCurrentKey() {
+ final Key currentKey = mCurrentKey;
+ if (currentKey == null) {
+ return;
+ }
+ currentKey.onReleased();
+ invalidateKey(currentKey);
+ mCurrentKey = null;
+ }
+
+ @Override
+ public boolean onDown(final MotionEvent e) {
+ final Key key = getKey(e);
+ releaseCurrentKey();
+ mCurrentKey = key;
+ if (key == null) {
+ return false;
+ }
+ // TODO: May call {@link KeyboardActionListener#onPressKey(int,int,boolean)}.
+ key.onPressed();
+ invalidateKey(key);
+ return false;
+ }
+
+ @Override
+ public void onShowPress(final MotionEvent e) {
+ // User feedback is done at {@link #onDown(MotionEvent)}.
+ }
+
+ @Override
+ public boolean onSingleTapUp(final MotionEvent e) {
+ final Key key = getKey(e);
+ releaseCurrentKey();
+ if (key == null) {
+ return false;
+ }
+ // TODO: May call {@link KeyboardActionListener#onReleaseKey(int,boolean)}.
+ key.onReleased();
+ invalidateKey(key);
+ mListener.onKeyClick(key);
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
+ final float distanceY) {
+ releaseCurrentKey();
+ return false;
+ }
+
+ @Override
+ public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX,
+ final float velocityY) {
+ releaseCurrentKey();
+ return false;
+ }
+
+ @Override
+ public void onLongPress(final MotionEvent e) {
+ // Long press detection of {@link #mGestureDetector} is disabled and not used.
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java b/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java
new file mode 100644
index 000000000..d1ccdc7b5
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/ScrollViewWithNotifier.java
@@ -0,0 +1,66 @@
+/*
+ * 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/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
index ebbcedc96..845a9b987 100644
--- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
@@ -19,10 +19,11 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.util.Log;
+import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
// TODO: Quit extending Dictionary after implementing dynamic binary dictionary.
@@ -42,37 +43,28 @@ abstract public class AbstractDictionaryWriter extends Dictionary {
abstract public void addUnigramWord(final String word, final String shortcutTarget,
final int frequency, final boolean isNotAWord);
+ // TODO: Remove lastModifiedTime after making binary dictionary support forgetting curve.
abstract public void addBigramWords(final String word0, final String word1,
- final int frequency, final boolean isValid);
+ final int frequency, final boolean isValid,
+ final long lastModifiedTime);
abstract public void removeBigramWords(final String word0, final String word1);
- abstract protected void writeBinaryDictionary(final FileOutputStream out)
+ abstract protected void writeDictionary(final DictEncoder dictEncoder)
throws IOException, UnsupportedFormatException;
public void write(final String fileName) {
final String tempFileName = fileName + ".temp";
final File file = new File(mContext.getFilesDir(), fileName);
final File tempFile = new File(mContext.getFilesDir(), tempFileName);
- FileOutputStream out = null;
try {
- out = new FileOutputStream(tempFile);
- writeBinaryDictionary(out);
- out.flush();
- out.close();
+ final DictEncoder dictEncoder = new Ver3DictEncoder(tempFile);
+ writeDictionary(dictEncoder);
tempFile.renameTo(file);
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
} catch (UnsupportedFormatException e) {
Log.e(TAG, "Unsupported format", e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index d181bf697..a463651d5 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -19,21 +19,24 @@ package com.android.inputmethod.latin;
import android.text.TextUtils;
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.settings.AdditionalFeaturesSettingUtils;
import com.android.inputmethod.latin.settings.NativeSuggestOptions;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.StringUtils;
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
+import java.util.Map;
/**
* Implements a static, compacted, binary dictionary of standard words.
*/
+// TODO: All methods which should be locked need to have a suffix "Locked".
public final class BinaryDictionary extends Dictionary {
private static final String TAG = BinaryDictionary.class.getSimpleName();
@@ -41,14 +44,20 @@ public final class BinaryDictionary extends Dictionary {
private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH;
// Must be equal to MAX_RESULTS in native/jni/src/defines.h
private static final int MAX_RESULTS = 18;
+ // Required space count for auto commit.
+ // TODO: Remove this heuristic.
+ private static final int SPACE_COUNT_FOR_AUTO_COMMIT = 3;
private long mNativeDict;
private final Locale mLocale;
+ private final long mDictSize;
+ private final String mDictFilePath;
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];
private final int[] mOutputScores = new int[MAX_RESULTS];
private final int[] mOutputTypes = new int[MAX_RESULTS];
+ private final int[] mOutputAutoCommitFirstWordConfidence = new int[MAX_RESULTS];
private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions();
@@ -63,7 +72,7 @@ public final class BinaryDictionary extends Dictionary {
if (traverseSession == null) {
traverseSession = mDicTraverseSessions.get(traverseSessionId);
if (traverseSession == null) {
- traverseSession = new DicTraverseSession(mLocale, mNativeDict);
+ traverseSession = new DicTraverseSession(mLocale, mNativeDict, mDictSize);
mDicTraverseSessions.put(traverseSessionId, traverseSession);
}
}
@@ -86,6 +95,8 @@ public final class BinaryDictionary extends Dictionary {
final boolean isUpdatable) {
super(dictType);
mLocale = locale;
+ mDictSize = length;
+ mDictFilePath = filename;
mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
loadDictionary(filename, offset, length, isUpdatable);
}
@@ -94,22 +105,44 @@ public final class BinaryDictionary extends Dictionary {
JniUtils.loadNativeLibrary();
}
+ private static native boolean createEmptyDictFileNative(String filePath, long dictVersion,
+ String[] attributeKeyStringArray, String[] attributeValueStringArray);
private static native long openNative(String sourceDir, long dictOffset, long dictSize,
boolean isUpdatable);
+ private static native void flushNative(long dict, String filePath);
+ private static native boolean needsToRunGCNative(long dict);
+ private static native void flushWithGCNative(long dict, String filePath);
private static native void closeNative(long dict);
private static native int getProbabilityNative(long dict, int[] word);
- private static native boolean isValidBigramNative(long dict, int[] word0, int[] word1);
+ private static native int getBigramProbabilityNative(long dict, int[] word0, int[] word1);
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,
int[] suggestOptions, int[] prevWordCodePointArray,
- int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes);
+ int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes,
+ int[] outputAutoCommitFirstWordConfidence);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
private static native int editDistanceNative(int[] before, int[] after);
private static native void addUnigramWordNative(long dict, int[] word, int probability);
private static native void addBigramWordsNative(long dict, int[] word0, int[] word1,
int probability);
private static native void removeBigramWordsNative(long dict, int[] word0, int[] word1);
+ private static native int calculateProbabilityNative(long dict, int unigramProbability,
+ int bigramProbability);
+
+ @UsedForTesting
+ public static boolean createEmptyDictFile(final String filePath, final long dictVersion,
+ final Map<String, String> attributeMap) {
+ final String[] keyArray = new String[attributeMap.size()];
+ final String[] valueArray = new String[attributeMap.size()];
+ int index = 0;
+ for (final String key : attributeMap.keySet()) {
+ keyArray[index] = key;
+ valueArray[index] = attributeMap.get(key);
+ index++;
+ }
+ return createEmptyDictFileNative(filePath, dictVersion, keyArray, valueArray);
+ }
// TODO: Move native dict into session
private final void loadDictionary(final String path, final long startOffset,
@@ -120,15 +153,16 @@ public final class BinaryDictionary extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords,
- 0 /* sessionId */);
+ additionalFeaturesOptions, 0 /* sessionId */);
}
@Override
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords, final int sessionId) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
+ final int sessionId) {
if (!isValidDictionary()) return null;
Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE);
@@ -148,15 +182,14 @@ public final class BinaryDictionary extends Dictionary {
final InputPointers ips = composer.getInputPointers();
final int inputSize = isGesture ? ips.getPointerSize() : composerSize;
mNativeSuggestOptions.setIsGesture(isGesture);
- mNativeSuggestOptions.setAdditionalFeaturesOptions(
- AdditionalFeaturesSettingUtils.getAdditionalNativeSuggestOptions());
+ mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions);
// proximityInfo and/or prevWordForBigrams may not be null.
final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
getTraverseSession(sessionId).getSession(), ips.getXCoordinates(),
ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(),
prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices,
- mOutputTypes);
+ mOutputTypes, mOutputAutoCommitFirstWordConfidence);
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
for (int j = 0; j < count; ++j) {
final int start = j * MAX_WORD_LENGTH;
@@ -179,7 +212,9 @@ public final class BinaryDictionary extends Dictionary {
// TODO: check that all users of the `kind' parameter are ready to accept
// flags too and pass mOutputTypes[j] instead of kind
suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len),
- score, kind, mDictType));
+ score, kind, this /* sourceDict */,
+ mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */,
+ mOutputAutoCommitFirstWordConfidence[0]));
}
}
return suggestions;
@@ -205,12 +240,12 @@ public final class BinaryDictionary extends Dictionary {
@Override
public boolean isValidWord(final String word) {
- return getFrequency(word) >= 0;
+ return getFrequency(word) != NOT_A_PROBABILITY;
}
@Override
public int getFrequency(final String word) {
- if (word == null) return -1;
+ if (word == null) return NOT_A_PROBABILITY;
int[] codePoints = StringUtils.toCodePointArray(word);
return getProbabilityNative(mNativeDict, codePoints);
}
@@ -218,10 +253,20 @@ public final class BinaryDictionary extends Dictionary {
// TODO: Add a batch process version (isValidBigramMultiple?) to avoid excessive numbers of jni
// calls when checking for changes in an entire dictionary.
public boolean isValidBigram(final String word0, final String word1) {
- if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) return false;
+ return getBigramProbability(word0, word1) != NOT_A_PROBABILITY;
+ }
+
+ public int getBigramProbability(final String word0, final String word1) {
+ if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) return NOT_A_PROBABILITY;
final int[] codePoints0 = StringUtils.toCodePointArray(word0);
final int[] codePoints1 = StringUtils.toCodePointArray(word1);
- return isValidBigramNative(mNativeDict, codePoints0, codePoints1);
+ return getBigramProbabilityNative(mNativeDict, codePoints0, codePoints1);
+ }
+
+ private void runGCIfRequired() {
+ if (needsToRunGCNative(mNativeDict)) {
+ flushWithGC();
+ }
}
// Add a unigram entry to binary dictionary in native code.
@@ -229,6 +274,7 @@ public final class BinaryDictionary extends Dictionary {
if (TextUtils.isEmpty(word)) {
return;
}
+ runGCIfRequired();
final int[] codePoints = StringUtils.toCodePointArray(word);
addUnigramWordNative(mNativeDict, codePoints, probability);
}
@@ -238,6 +284,7 @@ public final class BinaryDictionary extends Dictionary {
if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) {
return;
}
+ runGCIfRequired();
final int[] codePoints0 = StringUtils.toCodePointArray(word0);
final int[] codePoints1 = StringUtils.toCodePointArray(word1);
addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability);
@@ -248,11 +295,58 @@ public final class BinaryDictionary extends Dictionary {
if (TextUtils.isEmpty(word0) || TextUtils.isEmpty(word1)) {
return;
}
+ runGCIfRequired();
final int[] codePoints0 = StringUtils.toCodePointArray(word0);
final int[] codePoints1 = StringUtils.toCodePointArray(word1);
removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
}
+ private void reopen() {
+ close();
+ final File dictFile = new File(mDictFilePath);
+ mNativeDict = openNative(dictFile.getAbsolutePath(), 0 /* startOffset */,
+ dictFile.length(), true /* isUpdatable */);
+ }
+
+ public void flush() {
+ if (!isValidDictionary()) return;
+ flushNative(mNativeDict, mDictFilePath);
+ reopen();
+ }
+
+ public void flushWithGC() {
+ if (!isValidDictionary()) return;
+ flushWithGCNative(mNativeDict, mDictFilePath);
+ reopen();
+ }
+
+ public boolean needsToRunGC() {
+ if (!isValidDictionary()) return false;
+ return needsToRunGCNative(mNativeDict);
+ }
+
+ @UsedForTesting
+ public int calculateProbability(final int unigramProbability, final int bigramProbability) {
+ if (!isValidDictionary()) return NOT_A_PROBABILITY;
+ return calculateProbabilityNative(mNativeDict, unigramProbability, bigramProbability);
+ }
+
+ @Override
+ public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
+ // TODO: actually use the confidence rather than use this completely broken heuristic
+ final String word = candidate.mWord;
+ final int length = word.length();
+ int remainingSpaces = SPACE_COUNT_FOR_AUTO_COMMIT;
+ for (int i = 0; i < length; ++i) {
+ // This is okay because no low-surrogate and no high-surrogate can ever match the
+ // space character, so we don't need to take care of iterating on code points.
+ if (Constants.CODE_SPACE == word.charAt(i)) {
+ if (0 >= --remainingSpaces) return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void close() {
synchronized (mDicTraverseSessions) {
@@ -263,21 +357,23 @@ public final class BinaryDictionary extends Dictionary {
traverseSession.close();
}
}
+ mDicTraverseSessions.clear();
}
- closeInternal();
+ closeInternalLocked();
}
- private synchronized void closeInternal() {
+ private synchronized void closeInternalLocked() {
if (mNativeDict != 0) {
closeNative(mNativeDict);
mNativeDict = 0;
}
}
+ // TODO: Manage BinaryDictionary instances without using WeakReference or something.
@Override
protected void finalize() throws Throwable {
try {
- closeInternal();
+ closeInternalLocked();
} finally {
super.finalize();
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 7e497e9b9..181ad17ea 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -21,17 +21,17 @@ import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.util.Log;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
+import com.android.inputmethod.latin.makedict.DictDecoder;
import com.android.inputmethod.latin.makedict.FormatSpec;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
import com.android.inputmethod.latin.utils.LocaleUtils;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.nio.BufferUnderflowException;
-import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
@@ -227,23 +227,12 @@ final public class BinaryDictionaryGetter {
// those do not include whitelist entries, the new code with an old version of the dictionary
// would lose whitelist functionality.
private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
- FileInputStream inStream = null;
try {
// Read the version of the file
- inStream = new FileInputStream(f);
- final BinaryDictDecoder.ByteBufferWrapper buffer =
- new BinaryDictDecoder.ByteBufferWrapper(inStream.getChannel().map(
- FileChannel.MapMode.READ_ONLY, 0, f.length()));
- final int magic = buffer.readInt();
- if (magic != FormatSpec.MAGIC_NUMBER) {
- return false;
- }
- final int formatVersion = buffer.readInt();
- final int headerSize = buffer.readInt();
- final HashMap<String, String> options = CollectionUtils.newHashMap();
- BinaryDictDecoder.populateOptions(buffer, headerSize, options);
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(f);
+ final FileHeader header = dictDecoder.readHeader();
- final String version = options.get(VERSION_KEY);
+ final String version = header.mDictionaryOptions.mAttributes.get(VERSION_KEY);
if (null == version) {
// No version in the options : the format is unexpected
return false;
@@ -259,14 +248,8 @@ final public class BinaryDictionaryGetter {
return false;
} catch (BufferUnderflowException e) {
return false;
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ } catch (UnsupportedFormatException e) {
+ return false;
}
}
@@ -303,7 +286,8 @@ final public class BinaryDictionaryGetter {
}
if (!dictPackSettings.isWordListActive(wordListId)) continue;
if (canUse) {
- fileList.add(AssetFileAddress.makeFromFileName(f.getPath()));
+ final AssetFileAddress afa = AssetFileAddress.makeFromFileName(f.getPath());
+ if (null != afa) fileList.add(afa);
} else {
Log.e(TAG, "Found a cached dictionary file but cannot read or use it");
}
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 8aec03f71..c4f96016c 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -76,6 +76,11 @@ public final class Constants {
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.
+ */
+ public static final String EMOJI_CAPABLE = "EmojiCapable";
+ /**
* The subtype extra value used to indicate that the subtype require network connection
* to work.
*/
@@ -133,6 +138,9 @@ public final class Constants {
public static final int SPELL_CHECKER_COORDINATE = -3;
public static final int EXTERNAL_KEYBOARD_COORDINATE = -4;
+ // A hint on how many characters to cache from the TextView. A good value of this is given by
+ // how many characters we need to be able to almost always find the caps mode.
+ public static final int EDITOR_CONTENTS_CACHE_SIZE = 1024;
// Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h
public static final int DICTIONARY_MAX_WORD_LENGTH = 48;
@@ -157,6 +165,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_ARMENIAN_PERIOD = 0x0589;
public static final int CODE_DASH = '-';
public static final int CODE_SINGLE_QUOTE = '\'';
public static final int CODE_DOUBLE_QUOTE = '"';
@@ -164,9 +173,7 @@ public final class Constants {
public static final int CODE_EXCLAMATION_MARK = '!';
public static final int CODE_SLASH = '/';
public static final int CODE_COMMERCIAL_AT = '@';
- // TODO: Check how this should work for right-to-left languages. It seems to stand
- // that for rtl languages, a closing parenthesis is a left parenthesis. Is this
- // managed by the font? Or is it a different char?
+ public static final int CODE_PLUS = '+';
public static final int CODE_CLOSING_PARENTHESIS = ')';
public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
public static final int CODE_CLOSING_CURLY_BRACKET = '}';
@@ -220,7 +227,10 @@ public final class Constants {
}
}
+ public static final int MAX_INT_BIT_COUNT = 32;
+
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 c99d0e2ea..ffeb92784 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.SystemClock;
import android.provider.BaseColumns;
@@ -70,7 +71,8 @@ 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);
+ super(context, getFilenameWithLocale(NAME, locale.toString()), Dictionary.TYPE_CONTACTS,
+ false /* isUpdatable */);
mLocale = locale;
mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale);
registerObserver(context);
@@ -144,8 +146,10 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
cursor.close();
}
}
- } catch (IllegalStateException e) {
- Log.e(TAG, "Contacts DB is having problems");
+ } 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);
}
}
@@ -172,14 +176,18 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
private int getContactCount() {
// TODO: consider switching to a rawQuery("select count(*)...") on the database if
// performance is a bottleneck.
- 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();
+ 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();
+ }
}
+ } catch (final SQLiteException e) {
+ Log.e(TAG, "SQLiteException in the remote Contacts process.", e);
}
return 0;
}
@@ -208,7 +216,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
false /* isNotAWord */);
if (!TextUtils.isEmpty(prevWord)) {
if (mUseFirstLastBigrams) {
- super.setBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM);
+ super.addBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM,
+ 0 /* lastModifiedTime */);
}
}
prevWord = word;
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index 45b281318..8d295adee 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -25,16 +25,16 @@ public final class DicTraverseSession {
JniUtils.loadNativeLibrary();
}
- private static native long setDicTraverseSessionNative(String locale);
+ private static native long setDicTraverseSessionNative(String locale, long dictSize);
private static native void initDicTraverseSessionNative(long nativeDicTraverseSession,
long dictionary, int[] previousWord, int previousWordLength);
private static native void releaseDicTraverseSessionNative(long nativeDicTraverseSession);
private long mNativeDicTraverseSession;
- public DicTraverseSession(Locale locale, long dictionary) {
+ public DicTraverseSession(Locale locale, long dictionary, long dictSize) {
mNativeDicTraverseSession = createNativeDicTraverseSession(
- locale != null ? locale.toString() : "");
+ locale != null ? locale.toString() : "", dictSize);
initSession(dictionary);
}
@@ -51,8 +51,8 @@ public final class DicTraverseSession {
mNativeDicTraverseSession, dictionary, previousWord, previousWordLength);
}
- private final long createNativeDicTraverseSession(String locale) {
- return setDicTraverseSessionNative(locale);
+ private final long createNativeDicTraverseSession(String locale, long dictSize) {
+ return setDicTraverseSessionNative(locale, dictSize);
}
private void closeInternal() {
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 7c3e4a740..fa79f5af7 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -28,9 +28,26 @@ import java.util.ArrayList;
public abstract class Dictionary {
public static final int NOT_A_PROBABILITY = -1;
+ // The following types do not actually come from real dictionary instances, so we create
+ // corresponding instances.
public static final String TYPE_USER_TYPED = "user_typed";
+ public static final Dictionary DICTIONARY_USER_TYPED = new PhonyDictionary(TYPE_USER_TYPED);
+
public static final String TYPE_APPLICATION_DEFINED = "application_defined";
+ public static final Dictionary DICTIONARY_APPLICATION_DEFINED =
+ new PhonyDictionary(TYPE_APPLICATION_DEFINED);
+
public static final String TYPE_HARDCODED = "hardcoded"; // punctuation signs and such
+ public static final Dictionary DICTIONARY_HARDCODED =
+ new PhonyDictionary(TYPE_HARDCODED);
+
+ // Spawned by resuming suggestions. Comes from a span that was in the TextView.
+ public static final String TYPE_RESUMED = "resumed";
+ public static final Dictionary DICTIONARY_RESUMED =
+ new PhonyDictionary(TYPE_RESUMED);
+
+ // The following types of dictionary have actual functional instances. We don't need final
+ // phony dictionary instances for them.
public static final String TYPE_MAIN = "main";
public static final String TYPE_CONTACTS = "contacts";
// User dictionary, the system-managed one.
@@ -42,9 +59,7 @@ public abstract class Dictionary {
// Personalization prediction dictionary internal to LatinIME's Java code.
public static final String TYPE_PERSONALIZATION_PREDICTION_IN_JAVA =
"personalization_prediction_in_java";
- // Spawned by resuming suggestions. Comes from a span that was in the TextView.
- public static final String TYPE_RESUMED = "resumed";
- protected final String mDictType;
+ public final String mDictType;
public Dictionary(final String dictType) {
mDictType = dictType;
@@ -57,20 +72,23 @@ public abstract class Dictionary {
* @param prevWord the previous word, or null if none
* @param proximityInfo the object for key proximity. May be ignored by some implementations.
* @param blockOffensiveWords whether to block potentially offensive words
+ * @param additionalFeaturesOptions options about additional features used for the suggestion.
* @return the list of suggestions (possibly null if none)
*/
// TODO: pass more context than just the previous word, to enable better suggestions (n-gram
// and more)
abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords);
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions);
// The default implementation of this method ignores sessionId.
// Subclasses that want to use sessionId need to override this method.
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords, final int sessionId) {
- return getSuggestions(composer, prevWord, proximityInfo, blockOffensiveWords);
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
+ final int sessionId) {
+ return getSuggestions(composer, prevWord, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions);
}
/**
@@ -114,8 +132,43 @@ public abstract class Dictionary {
/**
* Subclasses may override to indicate that this Dictionary is not yet properly initialized.
*/
-
public boolean isInitialized() {
return true;
}
+
+ /**
+ * Whether we think this suggestion should trigger an auto-commit. prevWord is the word
+ * before the suggestion, so that we can use n-gram frequencies.
+ * @param candidate The candidate suggestion, in whole (not only the first part).
+ * @return whether we should auto-commit or not.
+ */
+ public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
+ // If we don't have support for auto-commit, or if we don't know, we return false to
+ // avoid auto-committing stuff. Implementations of the Dictionary class that know to
+ // determine whether we should auto-commit will override this.
+ return false;
+ }
+
+ /**
+ * Not a true dictionary. A placeholder used to indicate suggestions that don't come from any
+ * real dictionary.
+ */
+ private static class PhonyDictionary extends Dictionary {
+ // This class is not publicly instantiable.
+ private PhonyDictionary(final String type) {
+ super(type);
+ }
+
+ @Override
+ public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
+ final String prevWord, final ProximityInfo proximityInfo,
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
+ return null;
+ }
+
+ @Override
+ public boolean isValidWord(String word) {
+ return false;
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index d05bb1e55..bf075140e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -58,18 +58,18 @@ public final class DictionaryCollection extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
if (dictionaries.isEmpty()) return null;
// To avoid creating unnecessary objects, we get the list out of the first
// dictionary and add the rest to it if not null, hence the get(0)
ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composer,
- prevWord, proximityInfo, blockOffensiveWords);
+ prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions);
if (null == suggestions) suggestions = CollectionUtils.newArrayList();
final int length = dictionaries.size();
for (int i = 1; i < length; ++ i) {
final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(composer,
- prevWord, proximityInfo, blockOffensiveWords);
+ prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions);
if (null != sugg) suggestions.addAll(sugg);
}
return suggestions;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
index 3b300a3fd..5a453dde5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -20,15 +20,14 @@ import android.content.Context;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoder;
+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.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -51,7 +50,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
@Override
public void clear() {
final HashMap<String, String> attributes = CollectionUtils.newHashMap();
- mFusionDictionary = new FusionDictionary(new Node(),
+ mFusionDictionary = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(attributes, false, false));
}
@@ -75,7 +74,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
@Override
public void addBigramWords(final String word0, final String word1, final int frequency,
- final boolean isValid) {
+ final boolean isValid, final long lastModifiedTime) {
mFusionDictionary.setBigram(word0, word1, frequency);
}
@@ -85,15 +84,15 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
}
@Override
- protected void writeBinaryDictionary(final FileOutputStream out)
+ protected void writeDictionary(final DictEncoder dictEncoder)
throws IOException, UnsupportedFormatException {
- BinaryDictEncoder.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS);
+ dictEncoder.writeDictionary(mFusionDictionary, FORMAT_OPTIONS);
}
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- boolean blockOffensiveWords) {
+ boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
// This class doesn't support suggestion.
return null;
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 3f11391ba..99859decf 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -20,14 +20,21 @@ 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.FormatSpec;
+import com.android.inputmethod.latin.personalization.DynamicPersonalizationDictionaryWriter;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.AsyncResultHolder;
import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.PrioritizedSerialExecutor;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Abstract base class for an expandable dictionary that can be created and updated dynamically
@@ -45,19 +52,32 @@ 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 int TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS = 100;
+
/**
* The maximum length of a word in this dictionary.
*/
protected static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH;
+ private static final int DICTIONARY_FORMAT_VERSION = 3;
+
+ private static final String SUPPORTS_DYNAMIC_UPDATE =
+ FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE;
+
/**
- * A static map of locks, each of which controls access to a single binary dictionary file. They
- * ensure that only one instance can update the same dictionary at the same time. The key for
- * this map is the filename and the value is the shared dictionary controller associated with
- * that filename.
+ * A static map of time recorders, each of which records the time of accesses to a single binary
+ * dictionary file. The key for this map is the filename and the value is the shared dictionary
+ * time recorder associated with that filename.
*/
- private static final HashMap<String, DictionaryController> sSharedDictionaryControllers =
- CollectionUtils.newHashMap();
+ private static volatile ConcurrentHashMap<String, DictionaryTimeRecorder>
+ sFilenameDictionaryTimeRecorderMap = CollectionUtils.newConcurrentHashMap();
+
+ private static volatile ConcurrentHashMap<String, PrioritizedSerialExecutor>
+ sFilenameExecutorMap = CollectionUtils.newConcurrentHashMap();
/** The application context. */
protected final Context mContext;
@@ -68,21 +88,34 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private BinaryDictionary mBinaryDictionary;
+ // TODO: Remove and handle dictionaries in native code.
/** The in-memory dictionary used to generate the binary dictionary. */
- private AbstractDictionaryWriter mDictionaryWriter;
+ 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
- * DictionaryController.
+ * DictionaryTimeRecorder.
*/
private final String mFilename;
- /** Controls access to the shared binary dictionary file across multiple instances. */
- private final DictionaryController mSharedDictionaryController;
+ /** Whether to support dynamically updating the dictionary */
+ private final boolean mIsUpdatable;
+
+ // TODO: remove, once dynamic operations is serialized
+ /** Records access to the shared binary dictionary file across multiple instances. */
+ private final DictionaryTimeRecorder mFilenameDictionaryTimeRecorder;
+
+ // TODO: remove, once dynamic operations is serialized
+ /** Records access to the local binary dictionary for this instance. */
+ private final DictionaryTimeRecorder mPerInstanceDictionaryTimeRecorder =
+ new DictionaryTimeRecorder();
+
+ /* A extension for a binary dictionary file. */
+ public static final String DICT_FILE_EXTENSION = ".dict";
- /** Controls access to the local binary dictionary for this instance. */
- private final DictionaryController mLocalDictionaryController = new DictionaryController();
+ private final AtomicReference<Runnable> mUnfinishedFlushingTask =
+ new AtomicReference<Runnable>();
/**
* Abstract method for loading the unigrams and bigrams of a given dictionary in a background
@@ -98,16 +131,45 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
protected abstract boolean hasContentChanged();
/**
- * Gets the shared dictionary controller for the given filename.
+ * Gets the dictionary time recorder for the given filename.
*/
- private static synchronized DictionaryController getSharedDictionaryController(
+ private static DictionaryTimeRecorder getDictionaryTimeRecorder(
String filename) {
- DictionaryController controller = sSharedDictionaryControllers.get(filename);
- if (controller == null) {
- controller = new DictionaryController();
- sSharedDictionaryControllers.put(filename, controller);
+ DictionaryTimeRecorder recorder = sFilenameDictionaryTimeRecorderMap.get(filename);
+ if (recorder == null) {
+ synchronized(sFilenameDictionaryTimeRecorderMap) {
+ recorder = new DictionaryTimeRecorder();
+ sFilenameDictionaryTimeRecorderMap.put(filename, recorder);
+ }
+ }
+ return recorder;
+ }
+
+ /**
+ * Gets the executor for the given filename.
+ */
+ private static PrioritizedSerialExecutor getExecutor(final String filename) {
+ PrioritizedSerialExecutor executor = sFilenameExecutorMap.get(filename);
+ if (executor == null) {
+ synchronized(sFilenameExecutorMap) {
+ executor = new PrioritizedSerialExecutor();
+ sFilenameExecutorMap.put(filename, executor);
+ }
+ }
+ return executor;
+ }
+
+ private static AbstractDictionaryWriter getDictionaryWriter(final Context context,
+ final String dictType, final boolean isDynamicPersonalizationDictionary) {
+ if (isDynamicPersonalizationDictionary) {
+ if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ return null;
+ } else {
+ return new DynamicPersonalizationDictionaryWriter(context, dictType);
+ }
+ } else {
+ return new DictionaryWriter(context, dictType);
}
- return controller;
}
/**
@@ -117,19 +179,23 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* @param filename The filename for this binary dictionary. Multiple dictionaries with the same
* filename is supported.
* @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.
*/
- public ExpandableBinaryDictionary(
- final Context context, final String filename, final String dictType) {
+ public ExpandableBinaryDictionary(final Context context, final String filename,
+ final String dictType, final boolean isUpdatable) {
super(dictType);
mFilename = filename;
mContext = context;
+ mIsUpdatable = isUpdatable;
mBinaryDictionary = null;
- mSharedDictionaryController = getSharedDictionaryController(filename);
- mDictionaryWriter = new DictionaryWriter(context, dictType);
+ mFilenameDictionaryTimeRecorder = getDictionaryTimeRecorder(filename);
+ // Currently, only dynamic personalization dictionary is updatable.
+ mDictionaryWriter = getDictionaryWriter(context, dictType, isUpdatable);
}
protected static String getFilenameWithLocale(final String name, final String localeStr) {
- return name + "." + localeStr + ".dict";
+ return name + "." + localeStr + DICT_FILE_EXTENSION;
}
/**
@@ -137,17 +203,54 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
@Override
public void close() {
+ getExecutor(mFilename).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.
- mLocalDictionaryController.writeLock().lock();
- try {
- if (mBinaryDictionary != null) {
- mBinaryDictionary.close();
- mBinaryDictionary = null;
+ getExecutor(mFilename).execute(new Runnable() {
+ @Override
+ public void run() {
+ if (mBinaryDictionary != null) {
+ mBinaryDictionary.close();
+ mBinaryDictionary = null;
+ }
}
- mDictionaryWriter.close();
- } finally {
- mLocalDictionaryController.writeLock().unlock();
- }
+ });
+ }
+
+ protected Map<String, String> getHeaderAttributeMap() {
+ HashMap<String, String> attributeMap = new HashMap<String, String>();
+ attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE,
+ SUPPORTS_DYNAMIC_UPDATE);
+ return attributeMap;
+ }
+
+ protected void clear() {
+ getExecutor(mFilename).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());
+ } else {
+ mDictionaryWriter.clear();
+ }
+ }
+ });
}
/**
@@ -159,86 +262,159 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
/**
- * Sets a word bigram in the dictionary. Used for loading a dictionary.
+ * Adds a word bigram in the dictionary. Used for loading a dictionary.
*/
- protected void setBigram(final String prevWord, final String word, final int frequency) {
- mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
+ protected void addBigram(final String prevWord, final String word, final int frequency,
+ final long lastModifiedTime) {
+ mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */,
+ lastModifiedTime);
}
/**
- * Dynamically adds a word unigram to the 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 boolean isNotAWord) {
- mLocalDictionaryController.writeLock().lock();
- try {
- mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
- } finally {
- mLocalDictionaryController.writeLock().unlock();
+ if (!mIsUpdatable) {
+ Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename);
+ return;
}
+
+ getExecutor(mFilename).execute(new Runnable() {
+ @Override
+ public void run() {
+ if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ mBinaryDictionary.addUnigramWord(word, frequency);
+ } else {
+ // TODO: Remove.
+ mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
+ }
+ }
+ });
+ }
+
+ /**
+ * Dynamically adds a word bigram in the dictionary. May overwrite an existing entry.
+ */
+ protected void addBigramDynamically(final String word0, final String word1,
+ final int frequency, final boolean isValid) {
+ if (!mIsUpdatable) {
+ Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: "
+ + mFilename);
+ return;
+ }
+
+ getExecutor(mFilename).execute(new Runnable() {
+ @Override
+ public void run() {
+ if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ mBinaryDictionary.addBigramWords(word0, word1, frequency);
+ } else {
+ // TODO: Remove.
+ mDictionaryWriter.addBigramWords(word0, word1, frequency, isValid,
+ 0 /* lastTouchedTime */);
+ }
+ }
+ });
}
/**
- * Dynamically sets a word bigram in the dictionary.
+ * Dynamically remove a word bigram in the dictionary.
*/
- protected void setBigramDynamically(final String prevWord, final String word,
- final int frequency) {
- mLocalDictionaryController.writeLock().lock();
- try {
- mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
- } finally {
- mLocalDictionaryController.writeLock().unlock();
+ protected void removeBigramDynamically(final String word0, final String word1) {
+ if (!mIsUpdatable) {
+ Log.w(TAG, "removeBigramDynamically is called for non-updatable dictionary: "
+ + mFilename);
+ return;
}
+
+ getExecutor(mFilename).execute(new Runnable() {
+ @Override
+ public void run() {
+ if (ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ mBinaryDictionary.removeBigramWords(word0, word1);
+ } else {
+ // TODO: Remove.
+ mDictionaryWriter.removeBigramWords(word0, word1);
+ }
+ }
+ });
}
@Override
- public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
+ public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
- asyncReloadDictionaryIfRequired();
- // Write lock because getSuggestions in native updates session status.
- if (mLocalDictionaryController.writeLock().tryLock()) {
- try {
- final ArrayList<SuggestedWordInfo> inMemDictSuggestion =
- mDictionaryWriter.getSuggestions(composer, prevWord, proximityInfo,
- blockOffensiveWords);
- if (mBinaryDictionary != null) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
+ final int sessionId) {
+ reloadDictionaryIfRequired();
+ final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
+ final AsyncResultHolder<ArrayList<SuggestedWordInfo>> holder =
+ new AsyncResultHolder<ArrayList<SuggestedWordInfo>>();
+ getExecutor(mFilename).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.getSuggestions(composer, prevWord, proximityInfo,
- blockOffensiveWords);
- if (inMemDictSuggestion == null) {
- return binarySuggestion;
- } else if (binarySuggestion == null) {
- return inMemDictSuggestion;
+ 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 {
- binarySuggestion.addAll(binarySuggestion);
- return binarySuggestion;
+ holder.set(inMemDictSuggestion);
}
- } else {
- return inMemDictSuggestion;
}
- } finally {
- mLocalDictionaryController.writeLock().unlock();
}
- }
- return null;
+ });
+ return holder.get(null, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
+ }
+
+ @Override
+ public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
+ final String prevWord, final ProximityInfo proximityInfo,
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
+ return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions, 0 /* sessionId */);
}
@Override
public boolean isValidWord(final String word) {
- asyncReloadDictionaryIfRequired();
+ reloadDictionaryIfRequired();
return isValidWordInner(word);
}
protected boolean isValidWordInner(final String word) {
- if (mLocalDictionaryController.readLock().tryLock()) {
- try {
- return isValidWordLocked(word);
- } finally {
- mLocalDictionaryController.readLock().unlock();
+ final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>();
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ holder.set(isValidWordLocked(word));
}
- }
- return false;
+ });
+ return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
}
protected boolean isValidWordLocked(final String word) {
@@ -256,8 +432,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* dictionary exists, this method will generate one.
*/
protected void loadDictionary() {
- mLocalDictionaryController.mLastUpdateRequestTime = SystemClock.uptimeMillis();
- asyncReloadDictionaryIfRequired();
+ mPerInstanceDictionaryTimeRecorder.mLastUpdateRequestTime = SystemClock.uptimeMillis();
+ reloadDictionaryIfRequired();
}
/**
@@ -267,8 +443,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private void loadBinaryDictionary() {
if (DEBUG) {
Log.d(TAG, "Loading binary dictionary: " + mFilename + " request="
- + mSharedDictionaryController.mLastUpdateRequestTime + " update="
- + mSharedDictionaryController.mLastUpdateTime);
+ + mFilenameDictionaryTimeRecorder.mLastUpdateRequestTime + " update="
+ + mFilenameDictionaryTimeRecorder.mLastUpdateTime);
}
final File file = new File(mContext.getFilesDir(), mFilename);
@@ -277,22 +453,21 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// Build the new binary dictionary
final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length,
- true /* useFullEditDistance */, null, mDictType, false /* isUpdatable */);
-
- if (mBinaryDictionary != null) {
- // Ensure all threads accessing the current dictionary have finished before swapping in
- // the new one.
- final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
- mLocalDictionaryController.writeLock().lock();
- try {
+ true /* useFullEditDistance */, null, mDictType, mIsUpdatable);
+
+ // Ensure all threads accessing the current dictionary have finished before
+ // swapping in the new one.
+ // TODO: Ensure multi-thread assignment of mBinaryDictionary.
+ final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
mBinaryDictionary = newBinaryDictionary;
- } finally {
- mLocalDictionaryController.writeLock().unlock();
+ if (oldBinaryDictionary != null) {
+ oldBinaryDictionary.close();
+ }
}
- oldBinaryDictionary.close();
- } else {
- mBinaryDictionary = newBinaryDictionary;
- }
+ });
}
/**
@@ -302,19 +477,35 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
abstract protected boolean needsToReloadBeforeWriting();
/**
- * Generates and writes a new binary dictionary based on the contents of the fusion dictionary.
+ * Writes a new binary dictionary based on the contents of the fusion dictionary.
*/
- private void generateBinaryDictionary() {
+ private void writeBinaryDictionary() {
if (DEBUG) {
Log.d(TAG, "Generating binary dictionary: " + mFilename + " request="
- + mSharedDictionaryController.mLastUpdateRequestTime + " update="
- + mSharedDictionaryController.mLastUpdateTime);
+ + mFilenameDictionaryTimeRecorder.mLastUpdateRequestTime + " update="
+ + mFilenameDictionaryTimeRecorder.mLastUpdateTime);
}
if (needsToReloadBeforeWriting()) {
mDictionaryWriter.clear();
loadDictionaryAsync();
+ mDictionaryWriter.write(mFilename);
+ } 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()) {
+ mBinaryDictionary.flushWithGC();
+ } else {
+ mBinaryDictionary.flush();
+ }
+ }
+ } else {
+ mDictionaryWriter.write(mFilename);
+ }
}
- mDictionaryWriter.write(mFilename);
}
/**
@@ -326,83 +517,74 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
protected void setRequiresReload(final boolean requiresRebuild) {
final long time = SystemClock.uptimeMillis();
- mLocalDictionaryController.mLastUpdateRequestTime = time;
- mSharedDictionaryController.mLastUpdateRequestTime = time;
+ mPerInstanceDictionaryTimeRecorder.mLastUpdateRequestTime = time;
+ mFilenameDictionaryTimeRecorder.mLastUpdateRequestTime = time;
if (DEBUG) {
Log.d(TAG, "Reload request: " + mFilename + ": request=" + time + " update="
- + mSharedDictionaryController.mLastUpdateTime);
- }
- }
-
- /**
- * Reloads the dictionary if required. Reload will occur asynchronously in a separate thread.
- */
- void asyncReloadDictionaryIfRequired() {
- if (!isReloadRequired()) return;
- if (DEBUG) {
- Log.d(TAG, "Starting AsyncReloadDictionaryTask: " + mFilename);
+ + mFilenameDictionaryTimeRecorder.mLastUpdateTime);
}
- new AsyncReloadDictionaryTask().start();
}
/**
* Reloads the dictionary if required.
*/
- protected final void syncReloadDictionaryIfRequired() {
+ public final void reloadDictionaryIfRequired() {
if (!isReloadRequired()) return;
- syncReloadDictionaryInternal();
+ reloadDictionary();
}
/**
* Returns whether a dictionary reload is required.
*/
private boolean isReloadRequired() {
- return mBinaryDictionary == null || mLocalDictionaryController.isOutOfDate();
+ return mBinaryDictionary == null || mPerInstanceDictionaryTimeRecorder.isOutOfDate();
}
/**
* Reloads the dictionary. Access is controlled on a per dictionary file basis and supports
* concurrent calls from multiple instances that share the same dictionary file.
*/
- private final void syncReloadDictionaryInternal() {
+ private final void reloadDictionary() {
// Ensure that only one thread attempts to read or write to the shared binary dictionary
// file at the same time.
- mSharedDictionaryController.writeLock().lock();
- try {
- final long time = SystemClock.uptimeMillis();
- final boolean dictionaryFileExists = dictionaryFileExists();
- if (mSharedDictionaryController.isOutOfDate() || !dictionaryFileExists) {
- // If the shared dictionary file does not exist or is out of date, the first
- // instance that acquires the lock will generate a new one.
- if (hasContentChanged() || !dictionaryFileExists) {
- // If the source content has changed or the dictionary does not exist, rebuild
- // the binary dictionary. Empty dictionaries are supported (in the case where
- // loadDictionaryAsync() adds nothing) in order to provide a uniform framework.
- mSharedDictionaryController.mLastUpdateTime = time;
- generateBinaryDictionary();
+ getExecutor(mFilename).execute(new Runnable() {
+ @Override
+ public void run() {
+ final long time = SystemClock.uptimeMillis();
+ final boolean dictionaryFileExists = dictionaryFileExists();
+ if (mFilenameDictionaryTimeRecorder.isOutOfDate() || !dictionaryFileExists) {
+ // If the shared dictionary file does not exist or is out of date, the first
+ // instance that acquires the lock will generate a new one.
+ if (hasContentChanged() || !dictionaryFileExists) {
+ // If the source content has changed or the dictionary does not exist,
+ // rebuild the binary dictionary. Empty dictionaries are supported (in the
+ // case where loadDictionaryAsync() adds nothing) in order to provide a
+ // uniform framework.
+ mFilenameDictionaryTimeRecorder.mLastUpdateTime = time;
+ writeBinaryDictionary();
+ loadBinaryDictionary();
+ } else {
+ // If not, the reload request was unnecessary so revert
+ // LastUpdateRequestTime to LastUpdateTime.
+ mFilenameDictionaryTimeRecorder.mLastUpdateRequestTime =
+ mFilenameDictionaryTimeRecorder.mLastUpdateTime;
+ }
+ } else if (mBinaryDictionary == null ||
+ mPerInstanceDictionaryTimeRecorder.mLastUpdateTime
+ < mFilenameDictionaryTimeRecorder.mLastUpdateTime) {
+ // Otherwise, if the local dictionary is older than the shared dictionary, load
+ // the shared dictionary.
loadBinaryDictionary();
- } else {
- // If not, the reload request was unnecessary so revert LastUpdateRequestTime
- // to LastUpdateTime.
- mSharedDictionaryController.mLastUpdateRequestTime =
- mSharedDictionaryController.mLastUpdateTime;
}
- } else if (mBinaryDictionary == null || mLocalDictionaryController.mLastUpdateTime
- < mSharedDictionaryController.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.
- mSharedDictionaryController.mLastUpdateTime = time;
- generateBinaryDictionary();
- loadBinaryDictionary();
+ if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) {
+ // Binary dictionary is not valid. Regenerate the dictionary file.
+ mFilenameDictionaryTimeRecorder.mLastUpdateTime = time;
+ writeBinaryDictionary();
+ loadBinaryDictionary();
+ }
+ mPerInstanceDictionaryTimeRecorder.mLastUpdateTime = time;
}
- mLocalDictionaryController.mLastUpdateTime = time;
- } finally {
- mSharedDictionaryController.writeLock().unlock();
- }
+ });
}
// TODO: cache the file's existence so that we avoid doing a disk access each time.
@@ -412,21 +594,38 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
/**
- * Thread class for asynchronously reloading and rewriting the binary dictionary.
+ * Load the dictionary to memory.
*/
- private class AsyncReloadDictionaryTask extends Thread {
- @Override
- public void run() {
- syncReloadDictionaryInternal();
- }
+ protected void asyncLoadDictionaryToMemory() {
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ if (!ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ loadDictionaryAsync();
+ }
+ }
+ });
+ }
+
+ /**
+ * Generate binary dictionary using DictionaryWriter.
+ */
+ protected void asyncFlashAllBinaryDictionary() {
+ final Runnable newTask = new Runnable() {
+ @Override
+ public void run() {
+ writeBinaryDictionary();
+ }
+ };
+ final Runnable oldTask = mUnfinishedFlushingTask.getAndSet(newTask);
+ getExecutor(mFilename).replaceAndExecute(oldTask, newTask);
}
/**
- * Lock for controlling access to a given binary dictionary and for tracking whether the
- * dictionary is out of date. Can be shared across multiple dictionary instances that access the
- * same filename.
+ * Time recorder for tracking whether the dictionary is out of date.
+ * Can be shared across multiple dictionary instances that access the same filename.
*/
- private static class DictionaryController extends ReentrantReadWriteLock {
+ private static class DictionaryTimeRecorder {
private volatile long mLastUpdateTime = 0;
private volatile long mLastUpdateRequestTime = 0;
@@ -434,4 +633,75 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return (mLastUpdateRequestTime > mLastUpdateTime);
}
}
+
+ /**
+ * Dynamically adds a word unigram to the dictionary for testing with blocking-lock.
+ */
+ @UsedForTesting
+ protected void addWordDynamicallyForTests(final String word, final String shortcutTarget,
+ final int frequency, final boolean isNotAWord) {
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ addWordDynamically(word, shortcutTarget, frequency, isNotAWord);
+ }
+ });
+ }
+
+ /**
+ * Dynamically adds a word bigram in the dictionary for testing with blocking-lock.
+ */
+ @UsedForTesting
+ protected void addBigramDynamicallyForTests(final String word0, final String word1,
+ final int frequency, final boolean isValid) {
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ addBigramDynamically(word0, word1, frequency, isValid);
+ }
+ });
+ }
+
+ /**
+ * Dynamically remove a word bigram in the dictionary for testing with blocking-lock.
+ */
+ @UsedForTesting
+ protected void removeBigramDynamicallyForTests(final String word0, final String word1) {
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ removeBigramDynamically(word0, word1);
+ }
+ });
+ }
+
+ // TODO: Implement native binary methods once the dynamic dictionary implementation is done.
+ @UsedForTesting
+ public boolean isInDictionaryForTests(final String word) {
+ final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>();
+ getExecutor(mFilename).executePrioritized(new Runnable() {
+ @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)
+ .isInDictionaryForTests(word));
+ }
+ }
+ }
+ });
+ return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
+ }
+
+ @UsedForTesting
+ public void shutdownExecutorForTests() {
+ getExecutor(mFilename).shutdown();
+ }
+
+ @UsedForTesting
+ public boolean isTerminatedForTests() {
+ return getExecutor(mFilename).isTerminated();
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index bd2d70365..d491f988a 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -16,10 +16,10 @@
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.utils.CollectionUtils;
@@ -29,9 +29,10 @@ import java.util.ArrayList;
import java.util.LinkedList;
/**
- * Base class for an in-memory dictionary that can grow dynamically and can
+ * 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();
/**
@@ -39,23 +40,11 @@ public class ExpandableDictionary extends Dictionary {
*/
private static final int FULL_WORD_SCORE_MULTIPLIER = 2;
- // Bigram frequency is a fixed point number with 1 meaning 1.2 and 255 meaning 1.8.
- protected static final int BIGRAM_MAX_FREQUENCY = 255;
-
- private Context mContext;
private char[] mWordBuilder = new char[Constants.DICTIONARY_MAX_WORD_LENGTH];
private int mMaxDepth;
private int mInputLength;
- private boolean mRequiresReload;
-
- private boolean mUpdatingDictionary;
-
- // Use this lock before touching mUpdatingDictionary & mRequiresDownload
- private Object mUpdatingLock = new Object();
-
private static final class Node {
- Node() {}
char mCode;
int mFrequency;
boolean mTerminal;
@@ -157,46 +146,12 @@ public class ExpandableDictionary extends Dictionary {
private int[][] mCodes;
- public ExpandableDictionary(final Context context, final String dictType) {
+ public ExpandableDictionary(final String dictType) {
super(dictType);
- mContext = context;
clearDictionary();
mCodes = new int[Constants.DICTIONARY_MAX_WORD_LENGTH][];
}
- public void loadDictionary() {
- synchronized (mUpdatingLock) {
- startDictionaryLoadingTaskLocked();
- }
- }
-
- public void startDictionaryLoadingTaskLocked() {
- if (!mUpdatingDictionary) {
- mUpdatingDictionary = true;
- mRequiresReload = false;
- new LoadDictionaryTask().start();
- }
- }
-
- public void setRequiresReload(final boolean reload) {
- synchronized (mUpdatingLock) {
- mRequiresReload = reload;
- }
- }
-
- public boolean getRequiresReload() {
- return mRequiresReload;
- }
-
- /** Override to load your dictionary here, on a background thread. */
- public void loadDictionaryAsync() {
- // empty base implementation
- }
-
- public Context getContext() {
- return mContext;
- }
-
public int getMaxWordLength() {
return Constants.DICTIONARY_MAX_WORD_LENGTH;
}
@@ -231,7 +186,7 @@ public class ExpandableDictionary extends Dictionary {
childNode.mShortcutOnly = isShortcutOnly;
children.add(childNode);
}
- if (wordLength == depth + 1 && shortcutTarget != null) {
+ if (wordLength == depth + 1) {
// Terminate this word
childNode.mTerminal = true;
if (isShortcutOnly) {
@@ -255,8 +210,7 @@ public class ExpandableDictionary extends Dictionary {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
- if (reloadDictionaryIfRequired()) return null;
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
if (composer.size() > 1) {
if (composer.size() >= Constants.DICTIONARY_MAX_WORD_LENGTH) {
return null;
@@ -272,17 +226,7 @@ public class ExpandableDictionary extends Dictionary {
}
}
- // This reloads the dictionary if required, and returns whether it's currently updating its
- // contents or not.
- private boolean reloadDictionaryIfRequired() {
- synchronized (mUpdatingLock) {
- // If we need to update, start off a background task
- if (mRequiresReload) startDictionaryLoadingTaskLocked();
- return mUpdatingDictionary;
- }
- }
-
- protected ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes,
+ private ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer codes,
final String prevWordForBigrams, final ProximityInfo proximityInfo) {
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
mInputLength = codes.size();
@@ -312,11 +256,6 @@ public class ExpandableDictionary extends Dictionary {
@Override
public synchronized boolean isValidWord(final String word) {
- synchronized (mUpdatingLock) {
- // If we need to update, start off a background task
- if (mRequiresReload) startDictionaryLoadingTaskLocked();
- if (mUpdatingDictionary) return false;
- }
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,
@@ -326,10 +265,10 @@ public class ExpandableDictionary extends Dictionary {
return (node == null) ? false : !node.mShortcutOnly;
}
- protected boolean removeBigram(final String word1, final String word2) {
+ public boolean removeBigram(final String word0, final String word1) {
// Refer to addOrSetBigram() about word1.toLowerCase()
- final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
- final Node secondWord = searchWord(mRoots, word2, 0, null);
+ 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) {
@@ -351,16 +290,17 @@ public class ExpandableDictionary extends Dictionary {
/**
* Returns the word's frequency or -1 if not found
*/
- protected int getWordFrequency(final String word) {
+ @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;
}
- protected NextWord getBigramWord(final String word1, final String word2) {
- // Refer to addOrSetBigram() about word1.toLowerCase()
- final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null);
- final Node secondWord = searchWord(mRoots, word2, 0, null);
+ 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;
@@ -403,7 +343,9 @@ public class ExpandableDictionary extends Dictionary {
// 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, mDictType));
+ 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) {
@@ -411,7 +353,9 @@ public class ExpandableDictionary extends Dictionary {
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, mDictType));
+ finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false;
}
}
@@ -438,7 +382,7 @@ public class ExpandableDictionary extends Dictionary {
* @param suggestions the list in which to add suggestions
*/
// TODO: Share this routine with the native code for BinaryDictionary
- protected void getWordsRec(final NodeArray roots, final WordComposer codes, final char[] word,
+ 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;
@@ -531,37 +475,41 @@ public class ExpandableDictionary extends Dictionary {
}
}
- public int setBigramAndGetFrequency(final String word1, final String word2,
+ public int setBigramAndGetFrequency(final String word0, final String word1,
final int frequency) {
- return setBigramAndGetFrequency(word1, word2, frequency, null /* unused */);
+ return setBigramAndGetFrequency(word0, word1, frequency, null /* unused */);
}
- public int setBigramAndGetFrequency(final String word1, final String word2,
+ public int setBigramAndGetFrequency(final String word0, final String word1,
final ForgettingCurveParams fcp) {
- return setBigramAndGetFrequency(word1, word2, 0 /* unused */, 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 word1 the first word of this bigram
- * @param word2 the second word of this bigram
+ * @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 word1, final String word2,
+ 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 word1Lower = word1.toLowerCase();
- if (TextUtils.isEmpty(word1Lower) || TextUtils.isEmpty(word2)) {
- Log.e(TAG, "Invalid bigram pair: " + word1 + ", " + word1Lower + ", " + word2);
+ 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, word1Lower, 0, null);
- final Node secondWord = searchWord(mRoots, word2, 0, null);
+ 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();
@@ -657,7 +605,9 @@ public class ExpandableDictionary extends Dictionary {
if (freq >= 0 && node == null) {
suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index,
Constants.DICTIONARY_MAX_WORD_LENGTH - index),
- freq, SuggestedWordInfo.KIND_CORRECTION, mDictType));
+ freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
}
}
@@ -695,21 +645,10 @@ public class ExpandableDictionary extends Dictionary {
return null;
}
- protected void clearDictionary() {
+ public void clearDictionary() {
mRoots = new NodeArray();
}
- private final class LoadDictionaryTask extends Thread {
- LoadDictionaryTask() {}
- @Override
- public void run() {
- loadDictionaryAsync();
- synchronized (mUpdatingLock) {
- mUpdatingDictionary = false;
- }
- }
- }
-
private static char toLowerCase(final char c) {
char baseChar = c;
if (c < BASE_CHARS.length) {
diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java
index e96a46e12..2e638aaf3 100644
--- a/java/src/com/android/inputmethod/latin/InputPointers.java
+++ b/java/src/com/android/inputmethod/latin/InputPointers.java
@@ -105,6 +105,17 @@ public final class InputPointers {
mTimes.append(times, startPos, length);
}
+ /**
+ * Shift to the left by elementCount, discarding elementCount pointers at the start.
+ * @param elementCount how many elements to shift.
+ */
+ public void shift(final int elementCount) {
+ mXCoordinates.shift(elementCount);
+ mYCoordinates.shift(elementCount);
+ mPointerIds.shift(elementCount);
+ mTimes.shift(elementCount);
+ }
+
public void reset() {
final int defaultCapacity = mDefaultCapacity;
mXCoordinates.reset(defaultCapacity);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ffe317161..270dc4c06 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -31,6 +31,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.net.ConnectivityManager;
@@ -45,11 +46,13 @@ 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;
@@ -71,10 +74,12 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
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.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister;
+import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.settings.Settings;
@@ -82,6 +87,7 @@ 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.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;
@@ -90,11 +96,11 @@ import com.android.inputmethod.latin.utils.InputTypeUtils;
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.PositionalInfoForUserDictPendingAddition;
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
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.research.ResearchLogger;
import java.io.FileDescriptor;
@@ -124,6 +130,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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.
@@ -151,8 +160,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final Settings mSettings;
- private View mInputView;
- private int mInputViewMinHeight;
+ private View mExtractArea;
+ private View mKeyPreviewBackingView;
private SuggestionStripView mSuggestionStripView;
// Never null
private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@@ -172,11 +181,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private UserBinaryDictionary mUserDictionary;
private UserHistoryPredictionDictionary mUserHistoryPredictionDictionary;
private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary;
+ private PersonalizationDictionary mPersonalizationDictionary;
private boolean mIsUserDictionaryAvailable;
private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
- private PositionalInfoForUserDictPendingAddition
- mPositionalInfoForUserDictPendingAddition = null;
private final WordComposer mWordComposer = new WordComposer();
private final RichInputConnection mConnection = new RichInputConnection(this);
private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus();
@@ -191,7 +199,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mExpectingUpdateSelection;
private int mDeleteCount;
private long mLastKeyTime;
- private TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet();
+ 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;
@@ -212,6 +223,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final boolean mIsHardwareAcceleratedDrawingEnabled;
public final UIHandler mHandler = new UIHandler(this);
+ private InputUpdater mInputUpdater;
public static final class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
private static final int MSG_UPDATE_SHIFT_STATE = 0;
@@ -220,8 +232,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3;
private static final int MSG_RESUME_SUGGESTIONS = 4;
private static final int MSG_REOPEN_DICTIONARIES = 5;
+ private static final int MSG_ON_END_BATCH_INPUT = 6;
+ private static final int MSG_RESET_CACHES = 7;
+ 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 int mDelayUpdateSuggestions;
private int mDelayUpdateShiftState;
@@ -254,8 +272,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
switcher.updateShiftState();
break;
case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords)msg.obj,
- msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT);
+ 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);
+ }
+ } else {
+ latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords) msg.obj,
+ msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT);
+ }
break;
case MSG_RESUME_SUGGESTIONS:
latinIme.restartSuggestionsOnWordTouchedByCursor();
@@ -267,6 +295,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// get any suggestions. Wait one frame.
postUpdateSuggestionStrip();
break;
+ case MSG_ON_END_BATCH_INPUT:
+ latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj);
+ break;
+ case MSG_RESET_CACHES:
+ latinIme.retryResetCaches(msg.arg1 == 1 /* tryResumeSuggestions */,
+ msg.arg2 /* remainingTries */);
+ break;
}
}
@@ -283,6 +318,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
}
+ public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) {
+ removeMessages(MSG_RESET_CACHES);
+ sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0,
+ remainingTries, null));
+ }
+
public void cancelUpdateSuggestionStrip() {
removeMessages(MSG_UPDATE_SUGGESTION_STRIP);
}
@@ -308,9 +349,29 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final boolean dismissGestureFloatingPreviewText) {
removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
final int arg1 = dismissGestureFloatingPreviewText
- ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT : 0;
- obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, 0, suggestedWords)
- .sendToTarget();
+ ? 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();
+ }
+
+ 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();
+ }
+
+ public void onEndBatchInput(final SuggestedWords suggestedWords) {
+ obtainMessage(MSG_ON_END_BATCH_INPUT, suggestedWords).sendToTarget();
}
public void startDoubleSpacePeriodTimer() {
@@ -505,6 +566,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final IntentFilter newDictFilter = new IntentFilter();
newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
+
+ mInputUpdater = new InputUpdater(this);
}
// Has to be package-visible for unit tests
@@ -560,10 +623,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- mUserHistoryPredictionDictionary = PersonalizationDictionaryHelper
+ mUserHistoryPredictionDictionary = PersonalizationHelper
.getUserHistoryPredictionDictionary(this, localeStr, prefs);
newSuggest.setUserHistoryPredictionDictionary(mUserHistoryPredictionDictionary);
- mPersonalizationPredictionDictionary = PersonalizationDictionaryHelper
+ mPersonalizationDictionary = PersonalizationHelper
+ .getPersonalizationDictionary(this, localeStr, prefs);
+ newSuggest.setPersonalizationDictionary(mPersonalizationDictionary);
+ mPersonalizationPredictionDictionary = PersonalizationHelper
.getPersonalizationPredictionDictionary(this, localeStr, prefs);
newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary);
@@ -635,8 +701,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
ResearchLogger.getInstance().onDestroy();
}
unregisterReceiver(mDictionaryPackInstallReceiver);
+ PersonalizationDictionarySessionRegister.onDestroy(this);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
+ if (mInputUpdater != null) {
+ mInputUpdater.onDestroy();
+ mInputUpdater = null;
+ }
super.onDestroy();
}
@@ -663,25 +734,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled);
}
- private void setInputViewMinHeight(final int minHeight) {
- if (mInputView != null && mInputViewMinHeight != minHeight) {
- mInputView.setMinimumHeight(minHeight);
- mInputViewMinHeight = minHeight;
- }
- }
-
@Override
- public void setInputView(final View inputView) {
- super.setInputView(inputView);
- mInputView = inputView;
- setInputViewMinHeight(0);
- mSuggestionStripView = (SuggestionStripView)inputView.findViewById(
- R.id.suggestion_strip_view);
- if (mSuggestionStripView != null) {
- mSuggestionStripView.setListener(this, inputView);
- }
+ public void setInputView(final View view) {
+ super.setInputView(view);
+ mExtractArea = getWindow().getWindow().getDecorView()
+ .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)
+ mSuggestionStripView.setListener(this, view);
if (LatinImeLogger.sVISUALDEBUG) {
- inputView.setBackgroundColor(0x10FF0000);
+ mKeyPreviewBackingView.setBackgroundColor(0x10FF0000);
}
}
@@ -800,7 +863,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// span, so we should reset our state unconditionally, even if restarting is true.
mEnteredText = null;
resetComposingState(true /* alsoResetLastComposedWord */);
- if (isDifferentTextField) mHandler.postResumeSuggestions();
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
mRecapitalizeStatus.deactivate();
@@ -819,8 +881,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mSuggestedWords = SuggestedWords.EMPTY;
- mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart,
- 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.
+ if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(editorInfo.initialSelStart,
+ false /* shouldFinishComposition */)) {
+ // We try resetting the caches up to 5 times before giving up.
+ mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
+ } else {
+ if (isDifferentTextField) mHandler.postResumeSuggestions();
+ }
if (isDifferentTextField) {
mainKeyboardView.closing();
@@ -847,6 +917,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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();
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -861,22 +934,64 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
currentSettingsValues.mGestureTrailEnabled,
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
- // If we have a user dictionary addition in progress, we should check now if we should
- // replace the previously committed string with the word that has actually been added
- // to the user dictionary.
- if (null != mPositionalInfoForUserDictPendingAddition
- && mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, editorInfo, mLastSelectionEnd, currentLocale)) {
- mPositionalInfoForUserDictPendingAddition = null;
- }
- // If tryReplaceWithActualWord returns false, we don't know what word was
- // added to the user dictionary yet, so we keep the data and defer processing. The word will
- // be replaced when the user dictionary reports back with the actual word, which ends
- // up calling #onWordAddedToUserDictionary() in this class.
+ 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)) {
+ mLastSelectionStart = textLength;
+ // We can't figure out the value of mLastSelectionEnd :(
+ // But at least if it's smaller than mLastSelectionStart something is wrong
+ if (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) {
@@ -1007,7 +1122,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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.resetCachesUponCursorMove(newSelStart,
+ mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart,
false /* shouldFinishComposition */);
}
@@ -1133,11 +1248,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggestionStripView.setVisibility(
shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
}
- if (shouldShowSuggestions && mainKeyboardView != null) {
- final int remainingHeight = getWindow().getWindow().getDecorView().getHeight()
- - mainKeyboardView.getHeight() - mSuggestionStripView.getHeight();
- mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
- }
}
}
@@ -1145,37 +1255,69 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
}
+ private int getAdjustedBackingViewHeight() {
+ final int currentHeight = mKeyPreviewBackingView.getHeight();
+ if (currentHeight > 0) {
+ return currentHeight;
+ }
+
+ final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+ if (visibleKeyboardView == null) {
+ return 0;
+ }
+ // TODO: !!!!!!!!!!!!!!!!!!!! Handle different backing view heights between the main !!!
+ // keyboard and the emoji keyboard. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ final int keyboardHeight = visibleKeyboardView.getHeight();
+ final int suggestionsHeight = mSuggestionStripView.getHeight();
+ final int displayHeight = getResources().getDisplayMetrics().heightPixels;
+ final Rect rect = new Rect();
+ mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect);
+ final int notificationBarHeight = rect.top;
+ final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight
+ - keyboardHeight;
+
+ final LayoutParams params = mKeyPreviewBackingView.getLayoutParams();
+ params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
+ mKeyPreviewBackingView.setLayoutParams(params);
+ return params.height;
+ }
+
@Override
public void onComputeInsets(final InputMethodService.Insets outInsets) {
super.onComputeInsets(outInsets);
- final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- if (mainKeyboardView == null || mSuggestionStripView == null) {
+ final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+ if (visibleKeyboardView == null || mSuggestionStripView == null) {
return;
}
- // This method is never called when in fullscreen mode.
- // The contentTop is the top coordinate of the keyboard. The application behind will be
- // resized/panned above this coordibnate to be able to show an input field.
- final int contentTop = mInputView.getHeight() - mainKeyboardView.getHeight();
- final int suggestionsHeight = (mSuggestionStripView.getVisibility() == View.VISIBLE)
- ? mSuggestionStripView.getHeight() : 0;
- // The visibleTop is the top coordinates of the visible part of this IME. The application
- // behind will never be resized, but may be panned or scrolled.
- final int visibleTop = mainKeyboardView.isShowingMoreKeysPanel() ? 0
- : contentTop - suggestionsHeight;
- outInsets.contentTopInsets = contentTop;
- outInsets.visibleTopInsets = visibleTop;
+ final int adjustedBackingHeight = getAdjustedBackingViewHeight();
+ final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE);
+ final int backingHeight = backingGone ? 0 : adjustedBackingHeight;
+ // In fullscreen mode, the height of the extract area managed by InputMethodService should
+ // be considered.
+ // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}.
+ final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0;
+ final int suggestionsHeight = (mSuggestionStripView.getVisibility() == View.GONE) ? 0
+ : mSuggestionStripView.getHeight();
+ final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
+ int visibleTopY = extraHeight;
// Need to set touchable region only if input view is being shown
- if (mainKeyboardView.isShown()) {
- final int touchLeft = 0;
- final int touchTop = visibleTop;
- final int touchRight = touchLeft + mainKeyboardView.getWidth();
- final int touchBottom = contentTop + mainKeyboardView.getHeight()
+ if (visibleKeyboardView.isShown()) {
+ // Note that the height of Emoji layout is the same as the height of the main keyboard
+ // and the suggestion strip
+ if (mKeyboardSwitcher.isShowingEmojiKeyboard()
+ || mSuggestionStripView.getVisibility() == View.VISIBLE) {
+ visibleTopY -= suggestionsHeight;
+ }
+ final int touchY = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
+ final int touchWidth = visibleKeyboardView.getWidth();
+ final int touchHeight = visibleKeyboardView.getHeight() + extraHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
- // The touch event on touchableRegion will be delivered to this IME.
- outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
+ outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight);
}
+ outInsets.contentTopInsets = visibleTopY;
+ outInsets.visibleTopInsets = visibleTopY;
}
@Override
@@ -1198,11 +1340,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void updateFullscreenMode() {
super.updateFullscreenMode();
- if (!isFullscreenMode()) {
- // Expand the input view to cover entire display to be able to show key previews and
- // more suggestions view that may be displayed above the keyboard.
- setInputViewMinHeight(getResources().getDisplayMetrics().heightPixels);
- }
+
+ if (mKeyPreviewBackingView == null) return;
+ // In fullscreen mode, no need to have extra space to show the key preview.
+ // If not, we should have extra space above the keyboard to show the key preview.
+ mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE);
}
// This will reset the whole input state to the starting state. It will clear
@@ -1216,7 +1358,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
setSuggestedWords(settingsValues.mSuggestPuncList, false);
}
- mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition);
+ mConnection.resetCachesUponCursorMoveAndReturnSuccess(newCursorPosition,
+ shouldFinishComposition);
}
private void resetComposingState(final boolean alsoResetLastComposedWord) {
@@ -1320,7 +1463,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|| 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_CLOSING_ANGLE_BRACKET
+ || codePoint == Constants.CODE_PLUS;
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1329,7 +1473,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void addWordToUserDictionary(final String word) {
if (TextUtils.isEmpty(word)) {
// Probably never supposed to happen, but just in case.
- mPositionalInfoForUserDictPendingAddition = null;
return;
}
final String wordToEdit;
@@ -1341,22 +1484,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mUserDictionary.addWordToUserDictionary(wordToEdit);
}
- public void onWordAddedToUserDictionary(final String newSpelling) {
- // If word was added but not by us, bail out
- if (null == mPositionalInfoForUserDictPendingAddition) return;
- if (mWordComposer.isComposingWord()) {
- // We are late... give up and return
- mPositionalInfoForUserDictPendingAddition = null;
- return;
- }
- mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling);
- if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd,
- mSubtypeSwitcher.getCurrentSubtypeLocale())) {
- mPositionalInfoForUserDictPendingAddition = null;
- }
- }
-
private void onSettingsKeyPressed() {
if (isShowingOptionDialog()) return;
showSubtypeSelectorAndSettings();
@@ -1496,7 +1623,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
handleLanguageSwitchKey();
break;
case Constants.CODE_EMOJI:
- // TODO: Implement emoji keyboard switch.
+ // Note: Switching emoji keyboard is being handled in
+ // {@link KeyboardState#onCodeInput(int,int)}.
break;
case Constants.CODE_ENTER:
final EditorInfo editorInfo = getCurrentInputEditorInfo();
@@ -1612,7 +1740,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onStartBatchInput() {
- BatchInputUpdater.getInstance().onStartBatchInput(this);
+ mInputUpdater.onStartBatchInput();
mHandler.cancelUpdateSuggestionStrip();
mConnection.beginBatchEdit();
final SettingsValues settingsValues = mSettings.getCurrent();
@@ -1652,46 +1780,41 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
}
- private static final class BatchInputUpdater implements Handler.Callback {
+ private static final class InputUpdater implements Handler.Callback {
private final Handler mHandler;
- private LatinIME mLatinIme;
+ private final LatinIME mLatinIme;
private final Object mLock = new Object();
private boolean mInBatchInput; // synchronized using {@link #mLock}.
- private BatchInputUpdater() {
+ private InputUpdater(final LatinIME latinIme) {
final HandlerThread handlerThread = new HandlerThread(
- BatchInputUpdater.class.getSimpleName());
+ InputUpdater.class.getSimpleName());
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper(), this);
- }
-
- // Initialization-on-demand holder
- private static final class OnDemandInitializationHolder {
- public static final BatchInputUpdater sInstance = new BatchInputUpdater();
- }
-
- public static BatchInputUpdater getInstance() {
- return OnDemandInitializationHolder.sInstance;
+ 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) {
switch (msg.what) {
- case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- updateBatchInput((InputPointers)msg.obj);
- break;
+ case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
+ updateBatchInput((InputPointers)msg.obj);
+ break;
+ case MSG_GET_SUGGESTED_WORDS:
+ mLatinIme.getSuggestedWords(msg.arg1, (OnGetSuggestedWordsCallback) msg.obj);
+ break;
}
return true;
}
// Run in the UI thread.
- public void onStartBatchInput(final LatinIME latinIme) {
+ public void onStartBatchInput() {
synchronized (mLock) {
mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
mInBatchInput = true;
- mLatinIme = latinIme;
mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */);
}
@@ -1704,9 +1827,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Batch input has ended or canceled while the message was being delivered.
return;
}
- final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers);
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, false /* dismissGestureFloatingPreviewText */);
+
+ getSuggestedWordsGestureLocked(batchPointers, new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
+ mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ suggestedWords, false /* dismissGestureFloatingPreviewText */);
+ }
+ });
}
}
@@ -1729,35 +1857,57 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// Run in the UI thread.
- public SuggestedWords onEndBatchInput(final InputPointers batchPointers) {
- synchronized (mLock) {
- mInBatchInput = false;
- final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers);
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, true /* dismissGestureFloatingPreviewText */);
- return suggestedWords;
+ public void onEndBatchInput(final InputPointers batchPointers) {
+ synchronized(mLock) {
+ getSuggestedWordsGestureLocked(batchPointers, 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 SuggestedWords getSuggestedWordsGestureLocked(final InputPointers batchPointers) {
+ private void getSuggestedWordsGestureLocked(final InputPointers batchPointers,
+ final OnGetSuggestedWordsCallback callback) {
mLatinIme.mWordComposer.setBatchInputPointers(batchPointers);
- final SuggestedWords suggestedWords =
- mLatinIme.getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_GESTURE);
- final int suggestionCount = suggestedWords.size();
- if (suggestionCount <= 1) {
- final String mostProbableSuggestion = (suggestionCount == 0) ? null
- : suggestedWords.getWord(0);
- return mLatinIme.getOlderSuggestions(mostProbableSuggestion);
- }
- return suggestedWords;
+ mLatinIme.getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_GESTURE,
+ 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);
+ }
+ });
+ }
+
+ public void getSuggestedWords(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
+ mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, 0, callback).sendToTarget();
+ }
+
+ private void onDestroy() {
+ mHandler.removeMessages(MSG_GET_SUGGESTED_WORDS);
+ mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
+ mHandler.getLooper().quit();
}
}
+ // This method must run in UI Thread.
private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords,
final boolean dismissGestureFloatingPreviewText) {
- showSuggestionStrip(suggestedWords, null);
+ showSuggestionStrip(suggestedWords);
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
mainKeyboardView.showGestureFloatingPreviewText(suggestedWords);
if (dismissGestureFloatingPreviewText) {
@@ -1767,24 +1917,48 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onUpdateBatchInput(final InputPointers batchPointers) {
- BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers);
+ if (mSettings.getCurrent().mPhraseGestureEnabled) {
+ final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate();
+ if (null != candidate) {
+ 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());
+ }
+ }
+ }
+ mInputUpdater.onUpdateBatchInput(batchPointers);
}
- @Override
- public void onEndBatchInput(final InputPointers batchPointers) {
- final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput(
- batchPointers);
+ // 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;
}
- mWordComposer.setBatchInputWord(batchInputText);
mConnection.beginBatchEdit();
if (SPACE_STATE_PHANTOM == mSpaceState) {
promotePhantomSpace();
}
- mConnection.setComposingText(batchInputText, 1);
+ 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) {
@@ -1795,6 +1969,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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))) {
@@ -1830,7 +2009,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onCancelBatchInput() {
- BatchInputUpdater.getInstance().onCancelBatchInput();
+ mInputUpdater.onCancelBatchInput();
}
private void handleBackspace(final int spaceState) {
@@ -1948,7 +2127,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
}
- if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (currentSettings.isSuggestionsRequested(mDisplayOrientation)
+ && currentSettings.mCurrentLanguageHasSpaces) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
// We just removed a character. We need to update the auto-caps state.
@@ -1977,6 +2157,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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.
@@ -1996,17 +2179,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
resetEntireInputState(mLastSelectionStart);
isComposingWord = false;
}
- // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several
- // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
- // thread here.
- if (!isComposingWord && currentSettings.isWordCodePoint(primaryCode)
+ // 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) &&
- !mConnection.isCursorTouchingWord(currentSettings)) {
+ // 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. The idea here is, single quote is not a
- // separator and it should be treated as a normal character, except in the first
- // position where it should not start composing a word.
- isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode);
+ // 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
@@ -2085,20 +2277,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mKeyboardSwitcher.updateShiftState();
}
- // Returns true if we did an autocorrection, false otherwise.
+ // 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);
}
- final SettingsValues currentSettings = mSettings.getCurrent();
- if (mWordComposer.isComposingWord()) {
+ if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing
if (currentSettings.mCorrectionEnabled) {
- // TODO: maybe cache Strings in an <String> sparse array or something
- commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
+ final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
+ : new String(new int[] { primaryCode }, 0, 1);
+ commitCurrentAutoCorrection(separator);
didAutoCorrect = true;
} else {
commitTyped(new String(new int[]{primaryCode}, 0, 1));
@@ -2115,7 +2311,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
}
- sendKeyCodePoint(primaryCode);
+
+ if (!shouldAvoidSendingCode) {
+ sendKeyCodePoint(primaryCode);
+ }
if (Constants.CODE_SPACE == primaryCode) {
if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
@@ -2245,34 +2444,60 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final SuggestedWords suggestedWords =
- getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_TYPING);
- final String typedWord = mWordComposer.getTypedWord();
- showSuggestionStrip(suggestedWords, typedWord);
+ final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>();
+ getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING,
+ 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);
+ }
}
- private SuggestedWords getSuggestedWords(final int sessionId) {
+ private void getSuggestedWords(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final Suggest suggest = mSuggest;
if (keyboard == null || suggest == null) {
- return SuggestedWords.EMPTY;
+ callback.onGetSuggestedWords(SuggestedWords.EMPTY);
+ return;
}
// Get the word on which we should search the bigrams. If we are composing a word, it's
// whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we
// should just skip whitespace if any, so 1.
- // TODO: this is slow (2-way IPC) - we should probably cache this instead.
final SettingsValues currentSettings = mSettings.getCurrent();
- final String prevWord =
- mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
- mWordComposer.isComposingWord() ? 2 : 1);
- return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
- currentSettings.mBlockPotentiallyOffensive,
- currentSettings.mCorrectionEnabled, sessionId);
+ 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, callback);
}
- private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) {
- return maybeRetrieveOlderSuggestions(mWordComposer.getTypedWord(),
- getSuggestedWords(sessionId));
+ private void getSuggestedWordsOrOlderSuggestionsAsync(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
+ mInputUpdater.getSuggestedWords(sessionId, new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(SuggestedWords suggestedWords) {
+ callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions(
+ mWordComposer.getTypedWord(), suggestedWords));
+ }
+ });
}
private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
@@ -2312,25 +2537,42 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
false /* isPrediction */);
}
- private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) {
- if (suggestedWords.isEmpty()) {
- clearSuggestionStrip();
- return;
- }
+ private void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) {
+ if (suggestedWords.isEmpty()) return;
final String autoCorrection;
if (suggestedWords.mWillAutoCorrect) {
- autoCorrection = suggestedWords.getWord(1);
+ 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);
- final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
- setSuggestedWords(suggestedWords, isAutoCorrection);
- setAutoCorrectionIndicator(isAutoCorrection);
- setSuggestionStripShown(isSuggestionsStripVisible());
}
- private void commitCurrentAutoCorrection(final String separatorString) {
+ private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords,
+ final String typedWord) {
+ if (suggestedWords.isEmpty()) {
+ clearSuggestionStrip();
+ return;
+ }
+ setAutoCorrection(suggestedWords, typedWord);
+ final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
+ setSuggestedWords(suggestedWords, isAutoCorrection);
+ setAutoCorrectionIndicator(isAutoCorrection);
+ setSuggestionStripShown(isSuggestionsStripVisible());
+ }
+
+ 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();
@@ -2346,16 +2588,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
if (mSettings.isInternal()) {
LatinImeLoggerUtils.onAutoCorrection(
- typedWord, autoCorrection, separatorString, mWordComposer);
+ typedWord, autoCorrection, separator, mWordComposer);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final SuggestedWords suggestedWords = mSuggestedWords;
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
- separatorString, mWordComposer.isBatchMode(), suggestedWords);
+ separator, mWordComposer.isBatchMode(), suggestedWords);
}
mExpectingUpdateSelection = true;
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
- separatorString);
+ 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
@@ -2430,7 +2672,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion,
mWordComposer.isBatchMode(), suggestionInfo.mScore, suggestionInfo.mKind,
- suggestionInfo.mSourceDict);
+ suggestionInfo.mSourceDict.mDictType);
}
mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
@@ -2525,6 +2767,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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.
@@ -2534,6 +2783,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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.
@@ -2543,12 +2797,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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()) {
@@ -2556,7 +2812,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!TextUtils.equals(s, typedWord)) {
suggestions.add(new SuggestedWordInfo(s,
SuggestionStripView.MAX_SUGGESTIONS - i,
- SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED));
+ SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE
+ /* autoCommitFirstWordConfidence */));
}
}
}
@@ -2566,41 +2825,56 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mConnection.setComposingRegion(
mLastSelectionStart - numberOfCharsInWordBeforeCursor,
mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor());
- final SuggestedWords suggestedWords;
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.
- final SuggestedWords suggestedWordsIncludingTypedWord =
- getSuggestedWords(Suggest.SESSION_TYPING);
- 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;
- }
+ mInputUpdater.getSuggestedWords(Suggest.SESSION_TYPING,
+ 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.
- suggestedWords = new SuggestedWords(suggestions,
+ final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
true /* typedWordValid */, false /* willAutoCorrect */,
false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
false /* isPrediction */);
+ // We need to pass typedWord because mWordComposer.mTypedWord may differ from typedWord.
+ unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords, typedWord);
}
+ }
+ public void unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(
+ final SuggestedWords suggestedWords, final String typedWord) {
// Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
- // We never want to auto-correct on a resumed suggestion. Please refer to the three
- // places above where suggestedWords is affected. We also need to reset
- // mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching the text to adapt it.
- // TODO: remove mIsAutoCorrectionIndicator on (see comment on definition)
+ // 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;
- showSuggestionStrip(suggestedWords, typedWord);
+ mHandler.showSuggestionStripWithTypedWord(suggestedWords, typedWord);
}
/**
@@ -2630,6 +2904,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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;
+ }
+ tryFixLyingCursorPosition();
+ if (tryResumeSuggestions) mHandler.postResumeSuggestions();
+ }
+
private void revertCommit() {
final String previousWord = mLastComposedWord.mPrevWord;
final String originallyTypedWord = mLastComposedWord.mTypedWord;
@@ -2656,7 +2951,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) {
mUserHistoryPredictionDictionary.cancelAddingUserHistory(previousWord, committedWord);
}
- mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
+ 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);
@@ -2674,7 +2980,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
- if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (currentSettings.shouldInsertSpacesAutomatically()
+ && currentSettings.mCurrentLanguageHasSpaces
&& !mConnection.textBeforeCursorLooksLikeURL()) {
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_promotePhantomSpace();
@@ -2887,6 +3195,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mSuggest.hasMainDictionary();
}
+ // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
+ @UsedForTesting
+ /* package for test */ void replaceMainDictionaryForTest(final Locale locale) {
+ mSuggest.resetMainDict(this, locale, null);
+ }
+
public void debugDumpStateAndCrashWithException(final String context) {
final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString());
s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 35920f8cb..8580a6e54 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -30,6 +30,7 @@ import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
+import com.android.inputmethod.latin.utils.SpannableStringUtils;
import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.ResearchLogger;
@@ -73,9 +74,6 @@ public final class RichInputConnection {
* This contains the currently composing text, as LatinIME thinks the TextView is seeing it.
*/
private final StringBuilder mComposingText = new StringBuilder();
- // A hint on how many characters to cache from the TextView. A good value of this is given by
- // how many characters we need to be able to almost always find the caps mode.
- private static final int DEFAULT_TEXT_CACHE_SIZE = 100;
private final InputMethodService mParent;
InputConnection mIC;
@@ -93,7 +91,8 @@ public final class RichInputConnection {
r.token = 1;
r.flags = 0;
final ExtractedText et = mIC.getExtractedText(r, 0);
- final CharSequence beforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0);
+ final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
+ 0);
final StringBuilder internal = new StringBuilder().append(mCommittedTextBeforeComposingText)
.append(mComposingText);
if (null == et || null == beforeCursor) return;
@@ -142,19 +141,56 @@ public final class RichInputConnection {
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
}
- public void resetCachesUponCursorMove(final int newCursorPosition,
+ /**
+ * Reset the cached text and retrieve it again from the editor.
+ *
+ * This should be called when the cursor moved. It's possible that we can't connect to
+ * the application when doing this; notably, this happens sometimes during rotation, probably
+ * because of a race condition in the framework. In this case, we just can't retrieve the
+ * 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.
+ * @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;
mComposingText.setLength(0);
mCommittedTextBeforeComposingText.setLength(0);
- final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0);
- if (null != textBeforeCursor) mCommittedTextBeforeComposingText.append(textBeforeCursor);
+ mIC = mParent.getCurrentInputConnection();
+ // Call upon the inputconnection directly since our own method is using the cache, and
+ // we want to refresh it.
+ final CharSequence textBeforeCursor = null == mIC ? null :
+ mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
+ 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");
+ 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;
}
private void checkBatchEdit() {
@@ -169,7 +205,6 @@ public final class RichInputConnection {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
mCommittedTextBeforeComposingText.append(mComposingText);
- mExpectedCursorPosition += mComposingText.length();
mComposingText.setLength(0);
if (null != mIC) {
mIC.finishComposingText();
@@ -234,8 +269,11 @@ public final class RichInputConnection {
// 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) {
- mCommittedTextBeforeComposingText.append(
- getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0));
+ final CharSequence textBeforeCursor = getTextBeforeCursor(
+ Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
+ if (!TextUtils.isEmpty(textBeforeCursor)) {
+ mCommittedTextBeforeComposingText.append(textBeforeCursor);
+ }
}
// This never calls InputConnection#getCapsMode - in fact, it's a static method that
// never blocks or initiates IPC.
@@ -363,7 +401,7 @@ public final class RichInputConnection {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
final CharSequence textBeforeCursor =
- getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE + (end - start), 0);
+ getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE + (end - start), 0);
mCommittedTextBeforeComposingText.setLength(0);
if (!TextUtils.isEmpty(textBeforeCursor)) {
final int indexOfStartOfComposingText =
@@ -405,7 +443,8 @@ public final class RichInputConnection {
}
mExpectedCursorPosition = start;
mCommittedTextBeforeComposingText.setLength(0);
- mCommittedTextBeforeComposingText.append(getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0));
+ mCommittedTextBeforeComposingText.append(
+ getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0));
}
public void commitCorrection(final CorrectionInfo correctionInfo) {
@@ -524,9 +563,9 @@ public final class RichInputConnection {
if (mIC == null || sep == null) {
return null;
}
- final CharSequence before = mIC.getTextBeforeCursor(1000,
+ final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
InputConnection.GET_TEXT_WITH_STYLES);
- final CharSequence after = mIC.getTextAfterCursor(1000,
+ final CharSequence after = mIC.getTextAfterCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
InputConnection.GET_TEXT_WITH_STYLES);
if (before == null || after == null) {
return null;
@@ -569,8 +608,12 @@ public final class RichInputConnection {
}
}
- return new TextRange(TextUtils.concat(before, after), startIndexInBefore,
- before.length() + endIndexInAfter, before.length());
+ // 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());
}
public boolean isCursorTouchingWord(final SettingsValues settingsValues) {
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index be03d4ae5..cd9c89f04 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -53,12 +53,25 @@ public final class SubtypeSwitcher {
private InputMethodInfo mShortcutInputMethodInfo;
private InputMethodSubtype mShortcutSubtype;
private InputMethodSubtype mNoLanguageSubtype;
+ private InputMethodSubtype mEmojiSubtype;
private boolean mIsNetworkConnected;
// 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_subtype_keyboard, "zz", "keyboard",
- "KeyboardLayoutSet=qwerty,AsciiCapable,EnabledWhenDefaultIsNotAsciiCapable",
+ 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 */);
+ // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}.
+ // Dummy Emoji subtype. See {@link R.xml.method}.
+ private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE = new InputMethodSubtype(
+ R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark,
+ SubtypeLocaleUtils.NO_LANGUAGE, "keyboard", "KeyboardLayoutSet="
+ + SubtypeLocaleUtils.EMOJI + ","
+ + Constants.Subtype.ExtraValue.EMOJI_CAPABLE,
false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */);
static final class NeedsToDisplayLanguage {
@@ -271,4 +284,17 @@ public final class SubtypeSwitcher {
+ DUMMY_NO_LANGUAGE_SUBTYPE);
return DUMMY_NO_LANGUAGE_SUBTYPE;
}
+
+ public InputMethodSubtype getEmojiSubtype() {
+ if (mEmojiSubtype == null) {
+ mEmojiSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
+ }
+ 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);
+ 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 55b70c6f8..6c18c948f 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -24,6 +24,7 @@ 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.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.settings.Settings;
@@ -47,8 +48,9 @@ public final class Suggest {
// Session id for
// {@link #getSuggestedWords(WordComposer,String,ProximityInfo,boolean,int)}.
+ // We are sharing the same ID between typing and gesture to save RAM footprint.
public static final int SESSION_TYPING = 0;
- public static final int SESSION_GESTURE = 1;
+ public static final int SESSION_GESTURE = 0;
// TODO: rename this to CORRECTION_OFF
public static final int CORRECTION_NONE = 0;
@@ -200,28 +202,41 @@ public final class Suggest {
personalizationPredictionDictionary);
}
+ public void setPersonalizationDictionary(
+ final PersonalizationDictionary personalizationDictionary) {
+ addOrReplaceDictionaryInternal(Dictionary.TYPE_PERSONALIZATION,
+ personalizationDictionary);
+ }
+
public void setAutoCorrectionThreshold(float threshold) {
mAutoCorrectionThreshold = threshold;
}
- public SuggestedWords getSuggestedWords(final WordComposer wordComposer,
+ public interface OnGetSuggestedWordsCallback {
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords);
+ }
+
+ public void getSuggestedWords(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final boolean isCorrectionEnabled,
- final int sessionId) {
+ final int[] additionalFeaturesOptions, final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
LatinImeLogger.onStartSuggestion(prevWordForBigram);
if (wordComposer.isBatchMode()) {
- return getSuggestedWordsForBatchInput(
- wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords, sessionId);
+ getSuggestedWordsForBatchInput(wordComposer, prevWordForBigram, proximityInfo,
+ blockOffensiveWords, additionalFeaturesOptions, sessionId, callback);
} else {
- return getSuggestedWordsForTypingInput(wordComposer, prevWordForBigram, proximityInfo,
- blockOffensiveWords, isCorrectionEnabled);
+ getSuggestedWordsForTypingInput(wordComposer, prevWordForBigram, proximityInfo,
+ blockOffensiveWords, isCorrectionEnabled, additionalFeaturesOptions, callback);
}
}
- // Retrieves suggestions for the typing input.
- private SuggestedWords getSuggestedWordsForTypingInput(final WordComposer wordComposer,
+ // Retrieves suggestions for the typing input
+ // and calls the callback function with the suggestions.
+ private void getSuggestedWordsForTypingInput(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords, final boolean isCorrectionEnabled) {
+ final boolean blockOffensiveWords, final boolean isCorrectionEnabled,
+ final int[] additionalFeaturesOptions, final OnGetSuggestedWordsCallback callback) {
final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
MAX_SUGGESTIONS);
@@ -244,8 +259,9 @@ public final class Suggest {
for (final String key : mDictionaries.keySet()) {
final Dictionary dictionary = mDictionaries.get(key);
- suggestionsSet.addAll(dictionary.getSuggestions(
- wordComposerForLookup, prevWordForBigram, proximityInfo, blockOffensiveWords));
+ suggestionsSet.addAll(dictionary.getSuggestions(wordComposerForLookup,
+ prevWordForBigram, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions));
}
final String whitelistedWord;
@@ -303,13 +319,16 @@ public final class Suggest {
for (int i = 0; i < suggestionsCount; ++i) {
final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
- LatinImeLogger.onAddSuggestedWord(wordInfo.mWord.toString(), wordInfo.mSourceDict);
+ LatinImeLogger.onAddSuggestedWord(wordInfo.mWord.toString(),
+ wordInfo.mSourceDict.mDictType);
}
if (!TextUtils.isEmpty(typedWord)) {
suggestionsContainer.add(0, new SuggestedWordInfo(typedWord,
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED,
- Dictionary.TYPE_USER_TYPED));
+ Dictionary.DICTIONARY_USER_TYPED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
SuggestedWordInfo.removeDups(suggestionsContainer);
@@ -320,7 +339,7 @@ public final class Suggest {
suggestionsList = suggestionsContainer;
}
- return new SuggestedWords(suggestionsList,
+ callback.onGetSuggestedWords(new SuggestedWords(suggestionsList,
// 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.
@@ -328,31 +347,28 @@ public final class Suggest {
hasAutoCorrection, /* willAutoCorrect */
false /* isPunctuationSuggestions */,
false /* isObsoleteSuggestions */,
- !wordComposer.isComposingWord() /* isPrediction */);
+ !wordComposer.isComposingWord() /* isPrediction */));
}
- // Retrieves suggestions for the batch input.
- private SuggestedWords getSuggestedWordsForBatchInput(final WordComposer wordComposer,
+ // Retrieves suggestions for the batch input
+ // and calls the callback function with the suggestions.
+ private void getSuggestedWordsForBatchInput(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords, final int sessionId) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
+ final int sessionId, 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()) {
- // Skip User history dictionary for lookup
- // TODO: The user history dictionary should just override getSuggestionsWithSessionId
- // to make sure it doesn't return anything and we should remove this test
- if (key.equals(Dictionary.TYPE_USER_HISTORY)) {
- continue;
- }
final Dictionary dictionary = mDictionaries.get(key);
suggestionsSet.addAll(dictionary.getSuggestionsWithSessionId(wordComposer,
- prevWordForBigram, proximityInfo, blockOffensiveWords, sessionId));
+ prevWordForBigram, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions, sessionId));
}
for (SuggestedWordInfo wordInfo : suggestionsSet) {
- LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict);
+ LatinImeLogger.onAddSuggestedWord(wordInfo.mWord, wordInfo.mSourceDict.mDictType);
}
final ArrayList<SuggestedWordInfo> suggestionsContainer =
@@ -387,12 +403,12 @@ 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).
- return new SuggestedWords(suggestionsContainer,
+ callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer,
true /* typedWordValid */,
false /* willAutoCorrect */,
false /* isPunctuationSuggestions */,
false /* isObsoleteSuggestions */,
- false /* isPrediction */);
+ false /* isPrediction */));
}
private static ArrayList<SuggestedWordInfo> getSuggestionsInfoListWithDebugInfo(
@@ -438,7 +454,7 @@ public final class Suggest {
private static final SuggestedWordInfoComparator sSuggestedWordInfoComparator =
new SuggestedWordInfoComparator();
- private static SuggestedWordInfo getTransformedSuggestedWordInfo(
+ /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo(
final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase,
final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) {
final StringBuilder sb = new StringBuilder(wordInfo.mWord.length());
@@ -449,11 +465,17 @@ public final class Suggest {
} else {
sb.append(wordInfo.mWord);
}
- for (int i = trailingSingleQuotesCount - 1; i >= 0; --i) {
+ // Appending quotes is here to help people quote words. However, it's not helpful
+ // when they type words with quotes toward the end like "it's" or "didn't", where
+ // it's more likely the user missed the last character (or didn't type it yet).
+ final int quotesToAppend = trailingSingleQuotesCount
+ - (-1 == wordInfo.mWord.indexOf(Constants.CODE_SINGLE_QUOTE) ? 0 : 1);
+ for (int i = quotesToAppend - 1; i >= 0; --i) {
sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE);
}
return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind,
- wordInfo.mSourceDict);
+ wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
}
public void close() {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 22beaefee..fed4cdbbb 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -113,7 +113,9 @@ public final class SuggestedWords {
if (null == text) continue;
final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
- Dictionary.TYPE_APPLICATION_DEFINED);
+ Dictionary.DICTIONARY_APPLICATION_DEFINED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
result.add(suggestedWordInfo);
}
return result;
@@ -126,7 +128,9 @@ public final class SuggestedWords {
final ArrayList<SuggestedWordInfo> suggestionsList = CollectionUtils.newArrayList();
final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
- SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_USER_TYPED));
+ SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
alreadySeen.add(typedWord.toString());
final int previousSize = previousSuggestions.size();
for (int index = 1; index < previousSize; index++) {
@@ -141,7 +145,15 @@ public final class SuggestedWords {
return suggestionsList;
}
+ public SuggestedWordInfo getAutoCommitCandidate() {
+ if (mSuggestedWordInfoList.size() <= 0) return null;
+ final SuggestedWordInfo candidate = mSuggestedWordInfoList.get(0);
+ return candidate.isEligibleForAutoCommit() ? candidate : null;
+ }
+
public static final class SuggestedWordInfo {
+ public static final int NOT_AN_INDEX = -1;
+ public static final int NOT_A_CONFIDENCE = -1;
public static final int MAX_SCORE = Integer.MAX_VALUE;
public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind
public static final int KIND_TYPED = 0; // What user typed
@@ -166,18 +178,40 @@ public final class SuggestedWords {
public final int mScore;
public final int mKind; // one of the KIND_* constants above
public final int mCodePointCount;
- public final String mSourceDict;
+ public final Dictionary mSourceDict;
+ // For auto-commit. This keeps track of the index inside the touch coordinates array
+ // passed to native code to get suggestions for a gesture that corresponds to the first
+ // letter of the second word.
+ public final int mIndexOfTouchPointOfSecondWord;
+ // For auto-commit. This is a measure of how confident we are that we can commit the
+ // first word of this suggestion.
+ public final int mAutoCommitFirstWordConfidence;
private String mDebugString = "";
+ /**
+ * Create a new suggested word info.
+ * @param word The string to suggest.
+ * @param score A measure of how likely this suggestion is.
+ * @param kind The kind of suggestion, as one of the above KIND_* constants.
+ * @param sourceDict What instance of Dictionary produced this suggestion.
+ * @param indexOfTouchPointOfSecondWord See mIndexOfTouchPointOfSecondWord.
+ * @param autoCommitFirstWordConfidence See mAutoCommitFirstWordConfidence.
+ */
public SuggestedWordInfo(final String word, final int score, final int kind,
- final String sourceDict) {
+ final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord,
+ final int autoCommitFirstWordConfidence) {
mWord = word;
mScore = score;
mKind = kind;
mSourceDict = sourceDict;
mCodePointCount = StringUtils.codePointCount(mWord);
+ mIndexOfTouchPointOfSecondWord = indexOfTouchPointOfSecondWord;
+ mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence;
}
+ public boolean isEligibleForAutoCommit() {
+ return (KIND_CORRECTION == mKind && NOT_AN_INDEX != mIndexOfTouchPointOfSecondWord);
+ }
public void setDebugString(final String str) {
if (null == str) throw new NullPointerException("Debug info is null");
@@ -242,4 +276,24 @@ public final class SuggestedWords {
false /* willAutoCorrect */, mIsPunctuationSuggestions, mIsObsoleteSuggestions,
mIsPrediction);
}
+
+ // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
+ // last word of all suggestions, separated by a space. This is necessary because when we commit
+ // a multiple-word suggestion, the IME only retains the last word as the composing word, and
+ // we should only suggest replacements for this last word.
+ // TODO: make this work with languages without spaces.
+ public SuggestedWords getSuggestedWordsForLastWordOfPhraseGesture() {
+ final ArrayList<SuggestedWordInfo> newSuggestions = CollectionUtils.newArrayList();
+ for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
+ final SuggestedWordInfo info = mSuggestedWordInfoList.get(i);
+ final int indexOfLastSpace = info.mWord.lastIndexOf(Constants.CODE_SPACE) + 1;
+ final String lastWord = info.mWord.substring(indexOfLastSpace);
+ newSuggestions.add(new SuggestedWordInfo(lastWord, info.mScore, info.mKind,
+ info.mSourceDict, SuggestedWordInfo.NOT_AN_INDEX,
+ SuggestedWordInfo.NOT_A_CONFIDENCE));
+ }
+ return new SuggestedWords(newSuggestions, mTypedWordValid,
+ mWillAutoCorrect, mIsPunctuationSuggestions, mIsObsoleteSuggestions,
+ mIsPrediction);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
index 92f96c027..3213c92c7 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java
@@ -34,14 +34,15 @@ public final class SynchronouslyLoadedContactsBinaryDictionary extends ContactsB
@Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
final String prevWordForBigrams, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
- syncReloadDictionaryIfRequired();
- return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords);
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
+ reloadDictionaryIfRequired();
+ return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions);
}
@Override
public synchronized boolean isValidWord(final String word) {
- syncReloadDictionaryIfRequired();
+ reloadDictionaryIfRequired();
return isValidWordInner(word);
}
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
index 33fe89611..6405b5e46 100644
--- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java
@@ -37,14 +37,15 @@ public final class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDic
@Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
final String prevWordForBigrams, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
- syncReloadDictionaryIfRequired();
- return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords);
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
+ reloadDictionaryIfRequired();
+ return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords,
+ additionalFeaturesOptions);
}
@Override
public synchronized boolean isValidWord(final String word) {
- syncReloadDictionaryIfRequired();
+ reloadDictionaryIfRequired();
return isValidWordInner(word);
}
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index ed6fefae4..864a17375 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -22,10 +22,12 @@ import android.content.ContentUris;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.provider.UserDictionary.Words;
import android.text.TextUtils;
+import android.util.Log;
import com.android.inputmethod.compat.UserDictionaryCompatUtils;
import com.android.inputmethod.latin.utils.LocaleUtils;
@@ -39,6 +41,7 @@ import java.util.Locale;
* dictionary file to use it from native code.
*/
public class UserBinaryDictionary extends ExpandableBinaryDictionary {
+ private static final String TAG = ExpandableBinaryDictionary.class.getSimpleName();
// The user dictionary provider uses an empty string to mean "all languages".
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
@@ -75,7 +78,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
public UserBinaryDictionary(final Context context, final String locale,
final boolean alsoUseMoreRestrictiveLocales) {
- super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_USER);
+ super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_USER,
+ false /* isUpdatable */);
if (null == locale) throw new NullPointerException(); // Catch the error earlier
if (SubtypeLocaleUtils.NO_LANGUAGE.equals(locale)) {
// If we don't have a locale, insert into the "all locales" user dictionary.
@@ -102,14 +106,6 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
@Override
public void onChange(final boolean self, final Uri uri) {
setRequiresReload(true);
- // We want to report back to Latin IME in case the user just entered the word.
- // If the user changed the word in the dialog box, then we want to replace
- // what was entered in the text field.
- if (null == uri || !(context instanceof LatinIME)) return;
- final long changedRowId = ContentUris.parseId(uri);
- if (-1 == changedRowId) return; // Unknown content... Not sure why we're here
- final String changedWord = getChangedWordForUri(uri);
- ((LatinIME)context).onWordAddedToUserDictionary(changedWord);
}
};
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
@@ -117,19 +113,6 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
loadDictionary();
}
- private String getChangedWordForUri(final Uri uri) {
- final Cursor cursor = mContext.getContentResolver().query(uri,
- PROJECTION_QUERY, null, null, null);
- if (cursor == null) return null;
- try {
- if (!cursor.moveToFirst()) return null;
- final int indexWord = cursor.getColumnIndex(Words.WORD);
- return cursor.getString(indexWord);
- } finally {
- cursor.close();
- }
- }
-
@Override
public synchronized void close() {
if (mObserver != null) {
@@ -188,12 +171,19 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
} else {
requestArguments = localeElements;
}
- final Cursor cursor = mContext.getContentResolver().query(
- Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null);
+ Cursor cursor = null;
try {
+ cursor = mContext.getContentResolver().query(
+ Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null);
addWords(cursor);
+ } catch (final SQLiteException e) {
+ Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
} finally {
- if (null != cursor) cursor.close();
+ try {
+ if (null != cursor) cursor.close();
+ } catch (final SQLiteException e) {
+ Log.e(TAG, "SQLiteException in the remote User dictionary process.", e);
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoder.java
deleted file mode 100644
index 767f4fc72..000000000
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoder.java
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.makedict;
-
-import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
-import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
-import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-import com.android.inputmethod.latin.utils.JniUtils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Decodes binary files for a FusionDictionary.
- *
- * All the methods in this class are static.
- */
-public final class BinaryDictDecoder {
-
- private static final boolean DBG = MakedictLog.DBG;
-
- static {
- JniUtils.loadNativeLibrary();
- }
-
- // TODO: implement something sensical instead of just a phony method
- private static native int doNothing();
-
- private BinaryDictDecoder() {
- // This utility class is not publicly instantiable.
- }
-
- private static final int MAX_JUMPS = 12;
-
- @UsedForTesting
- public interface FusionDictionaryBufferInterface {
- public int readUnsignedByte();
- public int readUnsignedShort();
- public int readUnsignedInt24();
- public int readInt();
- public int position();
- public void position(int newPosition);
- public void put(final byte b);
- public int limit();
- @UsedForTesting
- public int capacity();
- }
-
- public static final class ByteBufferWrapper implements FusionDictionaryBufferInterface {
- private ByteBuffer mBuffer;
-
- public ByteBufferWrapper(final ByteBuffer buffer) {
- mBuffer = buffer;
- }
-
- @Override
- public int readUnsignedByte() {
- return mBuffer.get() & 0xFF;
- }
-
- @Override
- public int readUnsignedShort() {
- return mBuffer.getShort() & 0xFFFF;
- }
-
- @Override
- public int readUnsignedInt24() {
- final int retval = readUnsignedByte();
- return (retval << 16) + readUnsignedShort();
- }
-
- @Override
- public int readInt() {
- return mBuffer.getInt();
- }
-
- @Override
- public int position() {
- return mBuffer.position();
- }
-
- @Override
- public void position(int newPos) {
- mBuffer.position(newPos);
- }
-
- @Override
- public void put(final byte b) {
- mBuffer.put(b);
- }
-
- @Override
- public int limit() {
- return mBuffer.limit();
- }
-
- @Override
- public int capacity() {
- return mBuffer.capacity();
- }
- }
-
- /**
- * A class grouping utility function for our specific character encoding.
- */
- static final class CharEncoding {
- private static final int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
- private static final int MAXIMAL_ONE_BYTE_CHARACTER_VALUE = 0xFF;
-
- /**
- * Helper method to find out whether this code fits on one byte
- */
- private static boolean fitsOnOneByte(final int character) {
- return character >= MINIMAL_ONE_BYTE_CHARACTER_VALUE
- && character <= MAXIMAL_ONE_BYTE_CHARACTER_VALUE;
- }
-
- /**
- * Compute the size of a character given its character code.
- *
- * Char format is:
- * 1 byte = bbbbbbbb match
- * case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte
- * else: if 00011111 (= 0x1F) : this is the terminator. This is a relevant choice because
- * unicode code points range from 0 to 0x10FFFF, so any 3-byte value starting with
- * 00011111 would be outside unicode.
- * else: iso-latin-1 code
- * This allows for the whole unicode range to be encoded, including chars outside of
- * the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control
- * characters which should never happen anyway (and still work, but take 3 bytes).
- *
- * @param character the character code.
- * @return the size in binary encoded-form, either 1 or 3 bytes.
- */
- static int getCharSize(final int character) {
- // See char encoding in FusionDictionary.java
- if (fitsOnOneByte(character)) return 1;
- if (FormatSpec.INVALID_CHARACTER == character) return 1;
- return 3;
- }
-
- /**
- * Compute the byte size of a character array.
- */
- static int getCharArraySize(final int[] chars) {
- int size = 0;
- for (int character : chars) size += getCharSize(character);
- return size;
- }
-
- /**
- * Writes a char array to a byte buffer.
- *
- * @param codePoints the code point array to write.
- * @param buffer the byte buffer to write to.
- * @param index the index in buffer to write the character array to.
- * @return the index after the last character.
- */
- static int writeCharArray(final int[] codePoints, final byte[] buffer, int index) {
- for (int codePoint : codePoints) {
- if (1 == getCharSize(codePoint)) {
- buffer[index++] = (byte)codePoint;
- } else {
- buffer[index++] = (byte)(0xFF & (codePoint >> 16));
- buffer[index++] = (byte)(0xFF & (codePoint >> 8));
- buffer[index++] = (byte)(0xFF & codePoint);
- }
- }
- return index;
- }
-
- /**
- * Writes a string with our character format to a byte buffer.
- *
- * This will also write the terminator byte.
- *
- * @param buffer the byte buffer to write to.
- * @param origin the offset to write from.
- * @param word the string to write.
- * @return the size written, in bytes.
- */
- static int writeString(final byte[] buffer, final int origin,
- final String word) {
- final int length = word.length();
- int index = origin;
- for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
- final int codePoint = word.codePointAt(i);
- if (1 == getCharSize(codePoint)) {
- buffer[index++] = (byte)codePoint;
- } else {
- buffer[index++] = (byte)(0xFF & (codePoint >> 16));
- buffer[index++] = (byte)(0xFF & (codePoint >> 8));
- buffer[index++] = (byte)(0xFF & codePoint);
- }
- }
- buffer[index++] = FormatSpec.GROUP_CHARACTERS_TERMINATOR;
- return index - origin;
- }
-
- /**
- * Writes a string with our character format to a ByteArrayOutputStream.
- *
- * This will also write the terminator byte.
- *
- * @param buffer the ByteArrayOutputStream to write to.
- * @param word the string to write.
- */
- static void writeString(final ByteArrayOutputStream buffer, final String word) {
- final int length = word.length();
- for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
- final int codePoint = word.codePointAt(i);
- if (1 == getCharSize(codePoint)) {
- buffer.write((byte) codePoint);
- } else {
- buffer.write((byte) (0xFF & (codePoint >> 16)));
- buffer.write((byte) (0xFF & (codePoint >> 8)));
- buffer.write((byte) (0xFF & codePoint));
- }
- }
- buffer.write(FormatSpec.GROUP_CHARACTERS_TERMINATOR);
- }
-
- /**
- * Reads a string from a buffer. This is the converse of the above method.
- */
- private static String readString(final FusionDictionaryBufferInterface buffer) {
- final StringBuilder s = new StringBuilder();
- int character = readChar(buffer);
- while (character != FormatSpec.INVALID_CHARACTER) {
- s.appendCodePoint(character);
- character = readChar(buffer);
- }
- return s.toString();
- }
-
- /**
- * Reads a character from the buffer.
- *
- * This follows the character format documented earlier in this source file.
- *
- * @param buffer the buffer, positioned over an encoded character.
- * @return the character code.
- */
- static int readChar(final FusionDictionaryBufferInterface buffer) {
- int character = buffer.readUnsignedByte();
- if (!fitsOnOneByte(character)) {
- if (FormatSpec.GROUP_CHARACTERS_TERMINATOR == character) {
- return FormatSpec.INVALID_CHARACTER;
- }
- character <<= 16;
- character += buffer.readUnsignedShort();
- }
- return character;
- }
- }
-
- // Input methods: Read a binary dictionary to memory.
- // readDictionaryBinary is the public entry point for them.
-
- static int readChildrenAddress(final FusionDictionaryBufferInterface buffer,
- final int optionFlags, final FormatOptions options) {
- if (options.mSupportsDynamicUpdate) {
- final int address = buffer.readUnsignedInt24();
- if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS;
- if ((address & FormatSpec.MSB24) != 0) {
- return -(address & FormatSpec.SINT24_MAX);
- } else {
- return address;
- }
- }
- int address;
- switch (optionFlags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) {
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
- return buffer.readUnsignedByte();
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
- return buffer.readUnsignedShort();
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
- return buffer.readUnsignedInt24();
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_NOADDRESS:
- default:
- return FormatSpec.NO_CHILDREN_ADDRESS;
- }
- }
-
- static int readParentAddress(final FusionDictionaryBufferInterface buffer,
- final FormatOptions formatOptions) {
- if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
- final int parentAddress = buffer.readUnsignedInt24();
- final int sign = ((parentAddress & FormatSpec.MSB24) != 0) ? -1 : 1;
- return sign * (parentAddress & FormatSpec.SINT24_MAX);
- } else {
- return FormatSpec.NO_PARENT_ADDRESS;
- }
- }
-
- private static final int[] CHARACTER_BUFFER = new int[FormatSpec.MAX_WORD_LENGTH];
- public static CharGroupInfo readCharGroup(final FusionDictionaryBufferInterface buffer,
- final int originalGroupAddress, final FormatOptions options) {
- int addressPointer = originalGroupAddress;
- final int flags = buffer.readUnsignedByte();
- ++addressPointer;
-
- final int parentAddress = readParentAddress(buffer, options);
- if (BinaryDictIOUtils.supportsDynamicUpdate(options)) {
- addressPointer += 3;
- }
-
- final int characters[];
- if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) {
- int index = 0;
- int character = CharEncoding.readChar(buffer);
- addressPointer += CharEncoding.getCharSize(character);
- while (-1 != 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 CHARACTER_BUFFER.
- CHARACTER_BUFFER[index++] = character;
- character = CharEncoding.readChar(buffer);
- addressPointer += CharEncoding.getCharSize(character);
- }
- characters = Arrays.copyOfRange(CHARACTER_BUFFER, 0, index);
- } else {
- final int character = CharEncoding.readChar(buffer);
- addressPointer += CharEncoding.getCharSize(character);
- characters = new int[] { character };
- }
- final int frequency;
- if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) {
- ++addressPointer;
- frequency = buffer.readUnsignedByte();
- } else {
- frequency = CharGroup.NOT_A_TERMINAL;
- }
- int childrenAddress = readChildrenAddress(buffer, flags, options);
- if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
- childrenAddress += addressPointer;
- }
- addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options);
- ArrayList<WeightedString> shortcutTargets = null;
- if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) {
- final int pointerBefore = buffer.position();
- shortcutTargets = new ArrayList<WeightedString>();
- buffer.readUnsignedShort(); // Skip the size
- while (true) {
- final int targetFlags = buffer.readUnsignedByte();
- final String word = CharEncoding.readString(buffer);
- shortcutTargets.add(new WeightedString(word,
- targetFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY));
- if (0 == (targetFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
- }
- addressPointer += buffer.position() - pointerBefore;
- }
- ArrayList<PendingAttribute> bigrams = null;
- if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) {
- bigrams = new ArrayList<PendingAttribute>();
- int bigramCount = 0;
- while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
- final int bigramFlags = buffer.readUnsignedByte();
- ++addressPointer;
- final int sign = 0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE)
- ? 1 : -1;
- int bigramAddress = addressPointer;
- switch (bigramFlags & FormatSpec.MASK_ATTRIBUTE_ADDRESS_TYPE) {
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- bigramAddress += sign * buffer.readUnsignedByte();
- addressPointer += 1;
- break;
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- bigramAddress += sign * buffer.readUnsignedShort();
- addressPointer += 2;
- break;
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- final int offset = (buffer.readUnsignedByte() << 16)
- + buffer.readUnsignedShort();
- bigramAddress += sign * offset;
- addressPointer += 3;
- break;
- default:
- throw new RuntimeException("Has bigrams with no address");
- }
- bigrams.add(new PendingAttribute(bigramFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY,
- bigramAddress));
- if (0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
- }
- if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
- MakedictLog.d("too many bigrams in a group.");
- }
- }
- return new CharGroupInfo(originalGroupAddress, addressPointer, flags, characters, frequency,
- parentAddress, childrenAddress, shortcutTargets, bigrams);
- }
-
- /**
- * Reads and returns the char group count out of a buffer and forwards the pointer.
- */
- public static int readCharGroupCount(final FusionDictionaryBufferInterface buffer) {
- final int msb = buffer.readUnsignedByte();
- if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) {
- return msb;
- } else {
- return ((FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT & msb) << 8)
- + buffer.readUnsignedByte();
- }
- }
-
- // The word cache here is a stopgap bandaid to help the catastrophic performance
- // of this method. Since it performs direct, unbuffered random access to the file and
- // may be called hundreds of thousands of times, the resulting performance is not
- // reasonable without some kind of cache. Thus:
- private static TreeMap<Integer, WeightedString> wordCache =
- new TreeMap<Integer, WeightedString>();
- /**
- * Finds, as a string, the word at the address passed as an argument.
- *
- * @param buffer the buffer to read from.
- * @param headerSize the size of the header.
- * @param address the address to seek.
- * @param formatOptions file format options.
- * @return the word with its frequency, as a weighted string.
- */
- /* package for tests */ static WeightedString getWordAtAddress(
- final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
- final FormatOptions formatOptions) {
- final WeightedString cachedString = wordCache.get(address);
- if (null != cachedString) return cachedString;
-
- final WeightedString result;
- final int originalPointer = buffer.position();
- buffer.position(address);
-
- if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
- result = getWordAtAddressWithParentAddress(buffer, headerSize, address, formatOptions);
- } else {
- result = getWordAtAddressWithoutParentAddress(buffer, headerSize, address,
- formatOptions);
- }
-
- wordCache.put(address, result);
- buffer.position(originalPointer);
- return result;
- }
-
- // TODO: static!? This will behave erratically when used in multi-threaded code.
- // We need to fix this
- private static int[] sGetWordBuffer = new int[FormatSpec.MAX_WORD_LENGTH];
- @SuppressWarnings("unused")
- private static WeightedString getWordAtAddressWithParentAddress(
- final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
- final FormatOptions options) {
- int currentAddress = address;
- int index = FormatSpec.MAX_WORD_LENGTH - 1;
- int frequency = Integer.MIN_VALUE;
- // 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) {
- CharGroupInfo currentInfo;
- int loopCounter = 0;
- do {
- buffer.position(currentAddress + headerSize);
- currentInfo = readCharGroup(buffer, currentAddress, options);
- if (BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags, options)) {
- currentAddress = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
- }
- if (DBG && loopCounter++ > MAX_JUMPS) {
- MakedictLog.d("Too many jumps - probably a bug");
- }
- } while (BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags, options));
- if (Integer.MIN_VALUE == frequency) frequency = currentInfo.mFrequency;
- for (int i = 0; i < currentInfo.mCharacters.length; ++i) {
- sGetWordBuffer[index--] =
- currentInfo.mCharacters[currentInfo.mCharacters.length - i - 1];
- }
- if (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS) break;
- currentAddress = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
- }
-
- return new WeightedString(
- new String(sGetWordBuffer, index + 1, FormatSpec.MAX_WORD_LENGTH - index - 1),
- frequency);
- }
-
- private static WeightedString getWordAtAddressWithoutParentAddress(
- final FusionDictionaryBufferInterface buffer, final int headerSize, final int address,
- final FormatOptions options) {
- buffer.position(headerSize);
- final int count = readCharGroupCount(buffer);
- int groupOffset = BinaryDictIOUtils.getGroupCountSize(count);
- final StringBuilder builder = new StringBuilder();
- WeightedString result = null;
-
- CharGroupInfo last = null;
- for (int i = count - 1; i >= 0; --i) {
- CharGroupInfo info = readCharGroup(buffer, groupOffset, options);
- groupOffset = info.mEndAddress;
- if (info.mOriginalAddress == address) {
- builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
- result = new WeightedString(builder.toString(), info.mFrequency);
- break; // and return
- }
- if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) {
- if (info.mChildrenAddress > address) {
- if (null == last) continue;
- builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
- buffer.position(last.mChildrenAddress + headerSize);
- i = readCharGroupCount(buffer);
- groupOffset = last.mChildrenAddress + BinaryDictIOUtils.getGroupCountSize(i);
- last = null;
- continue;
- }
- last = info;
- }
- if (0 == i && BinaryDictIOUtils.hasChildrenAddress(last.mChildrenAddress)) {
- builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
- buffer.position(last.mChildrenAddress + headerSize);
- i = readCharGroupCount(buffer);
- groupOffset = last.mChildrenAddress + BinaryDictIOUtils.getGroupCountSize(i);
- last = null;
- continue;
- }
- }
- return result;
- }
-
- /**
- * Reads a single node from a buffer.
- *
- * This methods reads the file at the current position. A node is fully expected to start at
- * the current position.
- * This will recursively read other nodes into the structure, populating the reverse
- * maps on the fly and using them to keep track of already read nodes.
- *
- * @param buffer the buffer, correctly positioned at the start of a node.
- * @param headerSize the size, in bytes, of the file header.
- * @param reverseNodeMap a mapping from addresses to already read nodes.
- * @param reverseGroupMap a mapping from addresses to already read character groups.
- * @param options file format options.
- * @return the read node with all his children already read.
- */
- private static Node readNode(final FusionDictionaryBufferInterface buffer, final int headerSize,
- final Map<Integer, Node> reverseNodeMap, final Map<Integer, CharGroup> reverseGroupMap,
- final FormatOptions options)
- throws IOException {
- final ArrayList<CharGroup> nodeContents = new ArrayList<CharGroup>();
- final int nodeOrigin = buffer.position() - headerSize;
-
- do { // Scan the linked-list node.
- final int nodeHeadPosition = buffer.position() - headerSize;
- final int count = readCharGroupCount(buffer);
- int groupOffset = nodeHeadPosition + BinaryDictIOUtils.getGroupCountSize(count);
- for (int i = count; i > 0; --i) { // Scan the array of CharGroup.
- CharGroupInfo info = readCharGroup(buffer, groupOffset, options);
- if (BinaryDictIOUtils.isMovedGroup(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 = getWordAtAddress(
- buffer, headerSize, bigram.mAddress, options);
- final int reconstructedFrequency =
- reconstructBigramFrequency(word.mFrequency, bigram.mFrequency);
- bigrams.add(new WeightedString(word.mWord, reconstructedFrequency));
- }
- }
- if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) {
- Node children = reverseNodeMap.get(info.mChildrenAddress);
- if (null == children) {
- final int currentPosition = buffer.position();
- buffer.position(info.mChildrenAddress + headerSize);
- children = readNode(
- buffer, headerSize, reverseNodeMap, reverseGroupMap, options);
- buffer.position(currentPosition);
- }
- nodeContents.add(
- new CharGroup(info.mCharacters, shortcutTargets, bigrams,
- info.mFrequency,
- 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD),
- 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children));
- } else {
- nodeContents.add(
- new CharGroup(info.mCharacters, shortcutTargets, bigrams,
- info.mFrequency,
- 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD),
- 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED)));
- }
- groupOffset = info.mEndAddress;
- }
-
- // reach the end of the array.
- if (options.mSupportsDynamicUpdate) {
- final int nextAddress = buffer.readUnsignedInt24();
- if (nextAddress >= 0 && nextAddress < buffer.limit()) {
- buffer.position(nextAddress);
- } else {
- break;
- }
- }
- } while (options.mSupportsDynamicUpdate &&
- buffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS);
-
- final Node node = new Node(nodeContents);
- node.mCachedAddressBeforeUpdate = nodeOrigin;
- node.mCachedAddressAfterUpdate = nodeOrigin;
- reverseNodeMap.put(node.mCachedAddressAfterUpdate, node);
- return node;
- }
-
- /**
- * Helper function to get the binary format version from the header.
- * @throws IOException
- */
- private static int getFormatVersion(final FusionDictionaryBufferInterface buffer)
- throws IOException {
- final int magic = buffer.readInt();
- if (FormatSpec.MAGIC_NUMBER == magic) return buffer.readUnsignedShort();
- return FormatSpec.NOT_A_VERSION_NUMBER;
- }
-
- /**
- * Helper function to get and validate the binary format version.
- * @throws UnsupportedFormatException
- * @throws IOException
- */
- private static int checkFormatVersion(final FusionDictionaryBufferInterface buffer)
- throws IOException, UnsupportedFormatException {
- final int version = getFormatVersion(buffer);
- 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 header from a buffer.
- * @param buffer the buffer to read.
- * @throws IOException
- * @throws UnsupportedFormatException
- */
- public static FileHeader readHeader(final FusionDictionaryBufferInterface buffer)
- throws IOException, UnsupportedFormatException {
- final int version = checkFormatVersion(buffer);
- final int optionsFlags = buffer.readUnsignedShort();
-
- final HashMap<String, String> attributes = new HashMap<String, String>();
- final int headerSize;
- headerSize = buffer.readInt();
-
- if (headerSize < 0) {
- throw new UnsupportedFormatException("header size can't be negative.");
- }
-
- populateOptions(buffer, headerSize, attributes);
- buffer.position(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)));
- return header;
- }
-
- /**
- * Reads options from a buffer and populate a map with their contents.
- *
- * The buffer is read at the current position, so the caller must take care the pointer
- * is in the right place before calling this.
- */
- public static void populateOptions(final FusionDictionaryBufferInterface buffer,
- final int headerSize, final HashMap<String, String> options) {
- while (buffer.position() < headerSize) {
- final String key = CharEncoding.readString(buffer);
- final String value = CharEncoding.readString(buffer);
- options.put(key, value);
- }
- }
-
- /**
- * 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 reader the reader.
- * @param dict an optional dictionary to add words to, or null.
- * @return the created (or merged) dictionary.
- */
- @UsedForTesting
- public static FusionDictionary readDictionaryBinary(final BinaryDictReader reader,
- final FusionDictionary dict) throws FileNotFoundException, IOException,
- UnsupportedFormatException {
- // clear cache
- wordCache.clear();
-
- // if the buffer has not been opened, open the buffer with bytebuffer.
- if (reader.getBuffer() == null) reader.openBuffer(
- new BinaryDictReader.FusionDictionaryBufferFromByteBufferFactory());
- if (reader.getBuffer() == null) {
- MakedictLog.e("Cannot open the buffer");
- }
-
- // Read header
- final FileHeader header = readHeader(reader.getBuffer());
-
- Map<Integer, Node> reverseNodeMapping = new TreeMap<Integer, Node>();
- Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
- final Node root = readNode(reader.getBuffer(), header.mHeaderSize, reverseNodeMapping,
- reverseGroupMapping, header.mFormatOptions);
-
- FusionDictionary newDict = new FusionDictionary(root, header.mDictionaryOptions);
- if (null != dict) {
- for (final Word w : dict) {
- if (w.mIsBlacklistEntry) {
- newDict.addBlacklistEntry(w.mWord, w.mShortcutTargets, w.mIsNotAWord);
- } else {
- newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets, w.mIsNotAWord);
- }
- }
- for (final Word w : dict) {
- // By construction a binary dictionary may not have bigrams pointing to
- // words that are not also registered as unigrams so we don't have to avoid
- // them explicitly here.
- for (final WeightedString bigram : w.mBigrams) {
- newDict.setBigram(w.mWord, bigram.mWord, bigram.mFrequency);
- }
- }
- }
-
- return newDict;
- }
-
- /**
- * Helper method to pass a file name instead of a File object to isBinaryDictionary.
- */
- public static boolean isBinaryDictionary(final String filename) {
- final File file = new File(filename);
- return isBinaryDictionary(file);
- }
-
- /**
- * Basic test to find out whether the file is a binary dictionary or not.
- *
- * Concretely this only tests the magic number.
- *
- * @param file The file to test.
- * @return true if it's a binary dictionary, false otherwise
- */
- public static boolean isBinaryDictionary(final File file) {
- FileInputStream inStream = null;
- try {
- inStream = new FileInputStream(file);
- final ByteBuffer buffer = inStream.getChannel().map(
- FileChannel.MapMode.READ_ONLY, 0, file.length());
- final int version = getFormatVersion(new ByteBufferWrapper(buffer));
- return (version >= FormatSpec.MINIMUM_SUPPORTED_VERSION
- && version <= FormatSpec.MAXIMUM_SUPPORTED_VERSION);
- } catch (FileNotFoundException e) {
- return false;
- } catch (IOException e) {
- return false;
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- }
- }
-
- /**
- * Calculate bigram frequency from compressed value
- *
- * @see #makeBigramFlags
- *
- * @param unigramFrequency
- * @param bigramFrequency compressed frequency
- * @return approximate bigram frequency
- */
- public static int reconstructBigramFrequency(final int unigramFrequency,
- final int bigramFrequency) {
- final float stepSize = (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency)
- / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY);
- final float resultFreqFloat = unigramFrequency + stepSize * (bigramFrequency + 1.0f);
- return (int)resultFreqFloat;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
new file mode 100644
index 000000000..665c7a27c
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java
@@ -0,0 +1,624 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Decodes binary files for a FusionDictionary.
+ *
+ * All the methods in this class are static.
+ *
+ * TODO: Remove calls from classes except Ver3DictDecoder
+ * TODO: Move this file to makedict/internal.
+ * TODO: Rename this class to DictDecoderUtils.
+ */
+public final class BinaryDictDecoderUtils {
+
+ private static final boolean DBG = MakedictLog.DBG;
+
+ private BinaryDictDecoderUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ private static final int MAX_JUMPS = 12;
+
+ @UsedForTesting
+ public interface DictBuffer {
+ public int readUnsignedByte();
+ public int readUnsignedShort();
+ public int readUnsignedInt24();
+ public int readInt();
+ public int position();
+ public void position(int newPosition);
+ public void put(final byte b);
+ public int limit();
+ @UsedForTesting
+ public int capacity();
+ }
+
+ public static final class ByteBufferDictBuffer implements DictBuffer {
+ private ByteBuffer mBuffer;
+
+ public ByteBufferDictBuffer(final ByteBuffer buffer) {
+ mBuffer = buffer;
+ }
+
+ @Override
+ public int readUnsignedByte() {
+ return mBuffer.get() & 0xFF;
+ }
+
+ @Override
+ public int readUnsignedShort() {
+ return mBuffer.getShort() & 0xFFFF;
+ }
+
+ @Override
+ public int readUnsignedInt24() {
+ final int retval = readUnsignedByte();
+ return (retval << 16) + readUnsignedShort();
+ }
+
+ @Override
+ public int readInt() {
+ return mBuffer.getInt();
+ }
+
+ @Override
+ public int position() {
+ return mBuffer.position();
+ }
+
+ @Override
+ public void position(int newPos) {
+ mBuffer.position(newPos);
+ }
+
+ @Override
+ public void put(final byte b) {
+ mBuffer.put(b);
+ }
+
+ @Override
+ public int limit() {
+ return mBuffer.limit();
+ }
+
+ @Override
+ public int capacity() {
+ return mBuffer.capacity();
+ }
+ }
+
+ /**
+ * A class grouping utility function for our specific character encoding.
+ */
+ static final class CharEncoding {
+ private static final int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
+ private static final int MAXIMAL_ONE_BYTE_CHARACTER_VALUE = 0xFF;
+
+ /**
+ * Helper method to find out whether this code fits on one byte
+ */
+ private static boolean fitsOnOneByte(final int character) {
+ return character >= MINIMAL_ONE_BYTE_CHARACTER_VALUE
+ && character <= MAXIMAL_ONE_BYTE_CHARACTER_VALUE;
+ }
+
+ /**
+ * Compute the size of a character given its character code.
+ *
+ * Char format is:
+ * 1 byte = bbbbbbbb match
+ * case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte
+ * else: if 00011111 (= 0x1F) : this is the terminator. This is a relevant choice because
+ * unicode code points range from 0 to 0x10FFFF, so any 3-byte value starting with
+ * 00011111 would be outside unicode.
+ * else: iso-latin-1 code
+ * This allows for the whole unicode range to be encoded, including chars outside of
+ * the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control
+ * characters which should never happen anyway (and still work, but take 3 bytes).
+ *
+ * @param character the character code.
+ * @return the size in binary encoded-form, either 1 or 3 bytes.
+ */
+ static int getCharSize(final int character) {
+ // See char encoding in FusionDictionary.java
+ if (fitsOnOneByte(character)) return 1;
+ if (FormatSpec.INVALID_CHARACTER == character) return 1;
+ return 3;
+ }
+
+ /**
+ * Compute the byte size of a character array.
+ */
+ static int getCharArraySize(final int[] chars) {
+ int size = 0;
+ for (int character : chars) size += getCharSize(character);
+ return size;
+ }
+
+ /**
+ * Writes a char array to a byte buffer.
+ *
+ * @param codePoints the code point array to write.
+ * @param buffer the byte buffer to write to.
+ * @param index the index in buffer to write the character array to.
+ * @return the index after the last character.
+ */
+ static int writeCharArray(final int[] codePoints, final byte[] buffer, int index) {
+ for (int codePoint : codePoints) {
+ if (1 == getCharSize(codePoint)) {
+ buffer[index++] = (byte)codePoint;
+ } else {
+ buffer[index++] = (byte)(0xFF & (codePoint >> 16));
+ buffer[index++] = (byte)(0xFF & (codePoint >> 8));
+ buffer[index++] = (byte)(0xFF & codePoint);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Writes a string with our character format to a byte buffer.
+ *
+ * This will also write the terminator byte.
+ *
+ * @param buffer the byte buffer to write to.
+ * @param origin the offset to write from.
+ * @param word the string to write.
+ * @return the size written, in bytes.
+ */
+ static int writeString(final byte[] buffer, final int origin,
+ final String word) {
+ final int length = word.length();
+ int index = origin;
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ if (1 == getCharSize(codePoint)) {
+ buffer[index++] = (byte)codePoint;
+ } else {
+ buffer[index++] = (byte)(0xFF & (codePoint >> 16));
+ buffer[index++] = (byte)(0xFF & (codePoint >> 8));
+ buffer[index++] = (byte)(0xFF & codePoint);
+ }
+ }
+ buffer[index++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR;
+ return index - origin;
+ }
+
+ /**
+ * Writes a string with our character format to a ByteArrayOutputStream.
+ *
+ * This will also write the terminator byte.
+ *
+ * @param buffer the ByteArrayOutputStream to write to.
+ * @param word the string to write.
+ */
+ static void writeString(final ByteArrayOutputStream buffer, final String word) {
+ final int length = word.length();
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ if (1 == getCharSize(codePoint)) {
+ buffer.write((byte) codePoint);
+ } else {
+ buffer.write((byte) (0xFF & (codePoint >> 16)));
+ buffer.write((byte) (0xFF & (codePoint >> 8)));
+ buffer.write((byte) (0xFF & codePoint));
+ }
+ }
+ buffer.write(FormatSpec.PTNODE_CHARACTERS_TERMINATOR);
+ }
+
+ /**
+ * Reads a string from a DictBuffer. This is the converse of the above method.
+ */
+ static String readString(final DictBuffer dictBuffer) {
+ final StringBuilder s = new StringBuilder();
+ int character = readChar(dictBuffer);
+ while (character != FormatSpec.INVALID_CHARACTER) {
+ s.appendCodePoint(character);
+ character = readChar(dictBuffer);
+ }
+ return s.toString();
+ }
+
+ /**
+ * Reads a character from the buffer.
+ *
+ * This follows the character format documented earlier in this source file.
+ *
+ * @param dictBuffer the buffer, positioned over an encoded character.
+ * @return the character code.
+ */
+ static int readChar(final DictBuffer dictBuffer) {
+ int character = dictBuffer.readUnsignedByte();
+ if (!fitsOnOneByte(character)) {
+ if (FormatSpec.PTNODE_CHARACTERS_TERMINATOR == character) {
+ return FormatSpec.INVALID_CHARACTER;
+ }
+ character <<= 16;
+ character += dictBuffer.readUnsignedShort();
+ }
+ return character;
+ }
+ }
+
+ // Input methods: Read a binary dictionary to memory.
+ // readDictionaryBinary is the public entry point for them.
+
+ static int readSInt24(final DictBuffer dictBuffer) {
+ final int retval = dictBuffer.readUnsignedInt24();
+ final int sign = ((retval & FormatSpec.MSB24) != 0) ? -1 : 1;
+ return sign * (retval & FormatSpec.SINT24_MAX);
+ }
+
+ static int readChildrenAddress(final DictBuffer dictBuffer,
+ final int optionFlags, final FormatOptions options) {
+ if (options.mSupportsDynamicUpdate) {
+ final int address = dictBuffer.readUnsignedInt24();
+ if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS;
+ if ((address & FormatSpec.MSB24) != 0) {
+ return -(address & FormatSpec.SINT24_MAX);
+ } else {
+ return address;
+ }
+ }
+ int address;
+ switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE:
+ return dictBuffer.readUnsignedByte();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES:
+ return dictBuffer.readUnsignedShort();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES:
+ return dictBuffer.readUnsignedInt24();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS:
+ default:
+ return FormatSpec.NO_CHILDREN_ADDRESS;
+ }
+ }
+
+ static int readParentAddress(final DictBuffer dictBuffer,
+ final FormatOptions formatOptions) {
+ if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
+ final int parentAddress = dictBuffer.readUnsignedInt24();
+ final int sign = ((parentAddress & FormatSpec.MSB24) != 0) ? -1 : 1;
+ return sign * (parentAddress & FormatSpec.SINT24_MAX);
+ } else {
+ return FormatSpec.NO_PARENT_ADDRESS;
+ }
+ }
+
+ /**
+ * Reads and returns the PtNode count out of a buffer and forwards the pointer.
+ */
+ /* package */ static int readPtNodeCount(final DictBuffer dictBuffer) {
+ final int msb = dictBuffer.readUnsignedByte();
+ if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= msb) {
+ return msb;
+ } else {
+ return ((FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT & msb) << 8)
+ + dictBuffer.readUnsignedByte();
+ }
+ }
+
+ /**
+ * Finds, as a string, the word at the position passed as an argument.
+ *
+ * @param dictDecoder the dict decoder.
+ * @param headerSize the size of the header.
+ * @param pos the position to seek.
+ * @param formatOptions file format options.
+ * @return the word with its frequency, as a weighted string.
+ */
+ /* package for tests */ static WeightedString getWordAtPosition(final DictDecoder dictDecoder,
+ final int headerSize, final int pos, final FormatOptions formatOptions) {
+ final WeightedString result;
+ final int originalPos = dictDecoder.getPosition();
+ dictDecoder.setPosition(pos);
+
+ if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
+ result = getWordAtPositionWithParentAddress(dictDecoder, pos, formatOptions);
+ } else {
+ result = getWordAtPositionWithoutParentAddress(dictDecoder, headerSize, pos,
+ formatOptions);
+ }
+
+ dictDecoder.setPosition(originalPos);
+ return result;
+ }
+
+ @SuppressWarnings("unused")
+ private static WeightedString getWordAtPositionWithParentAddress(final DictDecoder dictDecoder,
+ final int pos, final FormatOptions options) {
+ int currentPos = pos;
+ int frequency = Integer.MIN_VALUE;
+ final StringBuilder builder = new StringBuilder();
+ // the length of the path from the root to the leaf is limited by MAX_WORD_LENGTH
+ for (int count = 0; count < FormatSpec.MAX_WORD_LENGTH; ++count) {
+ PtNodeInfo currentInfo;
+ int loopCounter = 0;
+ do {
+ dictDecoder.setPosition(currentPos);
+ currentInfo = dictDecoder.readPtNode(currentPos, options);
+ if (BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, options)) {
+ currentPos = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
+ }
+ if (DBG && loopCounter++ > MAX_JUMPS) {
+ MakedictLog.d("Too many jumps - probably a bug");
+ }
+ } while (BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, options));
+ if (Integer.MIN_VALUE == frequency) frequency = currentInfo.mFrequency;
+ builder.insert(0,
+ new String(currentInfo.mCharacters, 0, currentInfo.mCharacters.length));
+ if (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS) break;
+ currentPos = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
+ }
+ return new WeightedString(builder.toString(), frequency);
+ }
+
+ private static WeightedString getWordAtPositionWithoutParentAddress(
+ final DictDecoder dictDecoder, final int headerSize, final int pos,
+ final FormatOptions options) {
+ dictDecoder.setPosition(headerSize);
+ final int count = dictDecoder.readPtNodeCount();
+ int groupPos = headerSize + BinaryDictIOUtils.getPtNodeCountSize(count);
+ final StringBuilder builder = new StringBuilder();
+ WeightedString result = null;
+
+ PtNodeInfo last = null;
+ for (int i = count - 1; i >= 0; --i) {
+ PtNodeInfo info = dictDecoder.readPtNode(groupPos, options);
+ groupPos = info.mEndAddress;
+ if (info.mOriginalAddress == pos) {
+ builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
+ result = new WeightedString(builder.toString(), info.mFrequency);
+ break; // and return
+ }
+ if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) {
+ if (info.mChildrenAddress > pos) {
+ if (null == last) continue;
+ builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
+ dictDecoder.setPosition(last.mChildrenAddress);
+ i = dictDecoder.readPtNodeCount();
+ groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i);
+ last = null;
+ continue;
+ }
+ last = info;
+ }
+ if (0 == i && BinaryDictIOUtils.hasChildrenAddress(last.mChildrenAddress)) {
+ builder.append(new String(last.mCharacters, 0, last.mCharacters.length));
+ dictDecoder.setPosition(last.mChildrenAddress);
+ i = dictDecoder.readPtNodeCount();
+ groupPos = last.mChildrenAddress + BinaryDictIOUtils.getPtNodeCountSize(i);
+ last = null;
+ continue;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Reads a single node array from a buffer.
+ *
+ * This methods reads the file at the current position. A node array is fully expected to start
+ * at the current position.
+ * This will recursively read other node arrays into the structure, populating the reverse
+ * maps on the fly and using them to keep track of already read nodes.
+ *
+ * @param dictDecoder the dict decoder, correctly positioned at the start of a node array.
+ * @param headerSize the size, in bytes, of the file header.
+ * @param reverseNodeArrayMap a mapping from addresses to already read node arrays.
+ * @param reversePtNodeMap a mapping from addresses to already read PtNodes.
+ * @param options file format options.
+ * @return the read node array with all his children already read.
+ */
+ private static PtNodeArray readNodeArray(final DictDecoder dictDecoder,
+ final int headerSize, final Map<Integer, PtNodeArray> reverseNodeArrayMap,
+ final Map<Integer, PtNode> reversePtNodeMap, final FormatOptions options)
+ throws IOException {
+ final ArrayList<PtNode> nodeArrayContents = new ArrayList<PtNode>();
+ final int nodeArrayOriginPos = dictDecoder.getPosition();
+
+ do { // Scan the linked-list node.
+ final int nodeArrayHeadPos = dictDecoder.getPosition();
+ final int count = dictDecoder.readPtNodeCount();
+ int groupOffsetPos = nodeArrayHeadPos + BinaryDictIOUtils.getPtNodeCountSize(count);
+ for (int i = count; i > 0; --i) { // Scan the array of PtNode.
+ PtNodeInfo info = dictDecoder.readPtNode(groupOffsetPos, options);
+ if (BinaryDictIOUtils.isMovedPtNode(info.mFlags, options)) continue;
+ ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets;
+ ArrayList<WeightedString> bigrams = null;
+ if (null != info.mBigrams) {
+ bigrams = new ArrayList<WeightedString>();
+ for (PendingAttribute bigram : info.mBigrams) {
+ final WeightedString word = getWordAtPosition(dictDecoder, headerSize,
+ bigram.mAddress, options);
+ final int reconstructedFrequency =
+ BinaryDictIOUtils.reconstructBigramFrequency(word.mFrequency,
+ bigram.mFrequency);
+ bigrams.add(new WeightedString(word.mWord, reconstructedFrequency));
+ }
+ }
+ if (BinaryDictIOUtils.hasChildrenAddress(info.mChildrenAddress)) {
+ PtNodeArray children = reverseNodeArrayMap.get(info.mChildrenAddress);
+ if (null == children) {
+ final int currentPosition = dictDecoder.getPosition();
+ dictDecoder.setPosition(info.mChildrenAddress);
+ children = readNodeArray(dictDecoder, headerSize, reverseNodeArrayMap,
+ reversePtNodeMap, options);
+ dictDecoder.setPosition(currentPosition);
+ }
+ nodeArrayContents.add(
+ new PtNode(info.mCharacters, shortcutTargets, bigrams,
+ info.mFrequency,
+ 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD),
+ 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED), children));
+ } else {
+ nodeArrayContents.add(
+ new PtNode(info.mCharacters, shortcutTargets, bigrams,
+ info.mFrequency,
+ 0 != (info.mFlags & FormatSpec.FLAG_IS_NOT_A_WORD),
+ 0 != (info.mFlags & FormatSpec.FLAG_IS_BLACKLISTED)));
+ }
+ groupOffsetPos = info.mEndAddress;
+ }
+
+ // reach the end of the array.
+ if (options.mSupportsDynamicUpdate) {
+ final boolean hasValidForwardLink = dictDecoder.readAndFollowForwardLink();
+ if (!hasValidForwardLink) break;
+ }
+ } while (options.mSupportsDynamicUpdate && dictDecoder.hasNextPtNodeArray());
+
+ final PtNodeArray nodeArray = new PtNodeArray(nodeArrayContents);
+ nodeArray.mCachedAddressBeforeUpdate = nodeArrayOriginPos;
+ nodeArray.mCachedAddressAfterUpdate = nodeArrayOriginPos;
+ reverseNodeArrayMap.put(nodeArray.mCachedAddressAfterUpdate, nodeArray);
+ return nodeArray;
+ }
+
+ /**
+ * Helper function to get the binary format version from the header.
+ * @throws IOException
+ */
+ private static int getFormatVersion(final DictBuffer dictBuffer)
+ throws IOException {
+ final int magic = dictBuffer.readInt();
+ if (FormatSpec.MAGIC_NUMBER == magic) return dictBuffer.readUnsignedShort();
+ return FormatSpec.NOT_A_VERSION_NUMBER;
+ }
+
+ /**
+ * Helper function to get and validate the binary format version.
+ * @throws UnsupportedFormatException
+ * @throws IOException
+ */
+ static int checkFormatVersion(final DictBuffer dictBuffer)
+ throws IOException, UnsupportedFormatException {
+ final int version = getFormatVersion(dictBuffer);
+ if (version < FormatSpec.MINIMUM_SUPPORTED_VERSION
+ || version > FormatSpec.MAXIMUM_SUPPORTED_VERSION) {
+ throw new UnsupportedFormatException("This file has version " + version
+ + ", but this implementation does not support versions above "
+ + FormatSpec.MAXIMUM_SUPPORTED_VERSION);
+ }
+ return version;
+ }
+
+ /**
+ * Reads a buffer and returns the memory representation of the dictionary.
+ *
+ * This high-level method takes a buffer and reads its contents, populating a
+ * FusionDictionary structure. The optional dict argument is an existing dictionary to
+ * which words from the buffer should be added. If it is null, a new dictionary is created.
+ *
+ * @param dictDecoder the dict decoder.
+ * @param dict an optional dictionary to add words to, or null.
+ * @return the created (or merged) dictionary.
+ */
+ @UsedForTesting
+ /* package */ static FusionDictionary readDictionaryBinary(final DictDecoder dictDecoder,
+ final FusionDictionary dict) throws IOException, UnsupportedFormatException {
+ // Read header
+ final FileHeader fileHeader = dictDecoder.readHeader();
+
+ Map<Integer, PtNodeArray> reverseNodeArrayMapping = new TreeMap<Integer, PtNodeArray>();
+ Map<Integer, PtNode> reversePtNodeMapping = new TreeMap<Integer, PtNode>();
+ final PtNodeArray root = readNodeArray(dictDecoder, fileHeader.mHeaderSize,
+ reverseNodeArrayMapping, reversePtNodeMapping, fileHeader.mFormatOptions);
+
+ FusionDictionary newDict = new FusionDictionary(root, fileHeader.mDictionaryOptions);
+ if (null != dict) {
+ for (final Word w : dict) {
+ if (w.mIsBlacklistEntry) {
+ newDict.addBlacklistEntry(w.mWord, w.mShortcutTargets, w.mIsNotAWord);
+ } else {
+ newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets, w.mIsNotAWord);
+ }
+ }
+ for (final Word w : dict) {
+ // By construction a binary dictionary may not have bigrams pointing to
+ // words that are not also registered as unigrams so we don't have to avoid
+ // them explicitly here.
+ for (final WeightedString bigram : w.mBigrams) {
+ newDict.setBigram(w.mWord, bigram.mWord, bigram.mFrequency);
+ }
+ }
+ }
+
+ return newDict;
+ }
+
+ /**
+ * Helper method to pass a file name instead of a File object to isBinaryDictionary.
+ */
+ public static boolean isBinaryDictionary(final String filename) {
+ final File file = new File(filename);
+ return isBinaryDictionary(file);
+ }
+
+ /**
+ * Basic test to find out whether the file is a binary dictionary or not.
+ *
+ * Concretely this only tests the magic number.
+ *
+ * @param file The file to test.
+ * @return true if it's a binary dictionary, false otherwise
+ */
+ public static boolean isBinaryDictionary(final File file) {
+ FileInputStream inStream = null;
+ try {
+ inStream = new FileInputStream(file);
+ final ByteBuffer buffer = inStream.getChannel().map(
+ FileChannel.MapMode.READ_ONLY, 0, file.length());
+ final int version = getFormatVersion(new ByteBufferDictBuffer(buffer));
+ return (version >= FormatSpec.MINIMUM_SUPPORTED_VERSION
+ && version <= FormatSpec.MAXIMUM_SUPPORTED_VERSION);
+ } catch (FileNotFoundException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ // do nothing
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoder.java
deleted file mode 100644
index 85219e485..000000000
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoder.java
+++ /dev/null
@@ -1,993 +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.latin.makedict.BinaryDictDecoder.CharEncoding;
-import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
-import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
-import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * Encodes binary files for a FusionDictionary.
- *
- * All the methods in this class are static.
- */
-public class BinaryDictEncoder {
-
- private static final boolean DBG = MakedictLog.DBG;
-
- private BinaryDictEncoder() {
- // This utility class is not publicly instantiable.
- }
-
- // Arbitrary limit to how much passes we consider address size compression should
- // terminate in. At the time of this writing, our largest dictionary completes
- // compression in five passes.
- // If the number of passes exceeds this number, makedict bails with an exception on
- // suspicion that a bug might be causing an infinite loop.
- private static final int MAX_PASSES = 24;
-
- /**
- * Compute the binary size of the character array.
- *
- * If only one character, this is the size of this character. If many, it's the sum of their
- * sizes + 1 byte for the terminator.
- *
- * @param characters the character array
- * @return the size of the char array, including the terminator if any
- */
- static int getGroupCharactersSize(final int[] characters) {
- int size = CharEncoding.getCharArraySize(characters);
- if (characters.length > 1) size += FormatSpec.GROUP_TERMINATOR_SIZE;
- return size;
- }
-
- /**
- * Compute the binary size of the character array in a group
- *
- * If only one character, this is the size of this character. If many, it's the sum of their
- * sizes + 1 byte for the terminator.
- *
- * @param group the group
- * @return the size of the char array, including the terminator if any
- */
- private static int getGroupCharactersSize(final CharGroup group) {
- return getGroupCharactersSize(group.mChars);
- }
-
- /**
- * Compute the binary size of the group count for a node
- * @param node the node
- * @return the size of the group count, either 1 or 2 bytes.
- */
- private static int getGroupCountSize(final Node node) {
- return BinaryDictIOUtils.getGroupCountSize(node.mData.size());
- }
-
- /**
- * Compute the size of a shortcut in bytes.
- */
- private static int getShortcutSize(final WeightedString shortcut) {
- int size = FormatSpec.GROUP_ATTRIBUTE_FLAGS_SIZE;
- final String word = shortcut.mWord;
- final int length = word.length();
- for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
- final int codePoint = word.codePointAt(i);
- size += CharEncoding.getCharSize(codePoint);
- }
- size += FormatSpec.GROUP_TERMINATOR_SIZE;
- return size;
- }
-
- /**
- * Compute the size of a shortcut list in bytes.
- *
- * This is known in advance and does not change according to position in the file
- * like address lists do.
- */
- static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) {
- if (null == shortcutList) return 0;
- int size = FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE;
- for (final WeightedString shortcut : shortcutList) {
- size += getShortcutSize(shortcut);
- }
- return size;
- }
-
- /**
- * Compute the maximum size of a CharGroup, assuming 3-byte addresses for everything.
- *
- * @param group the CharGroup to compute the size of.
- * @param options file format options.
- * @return the maximum size of the group.
- */
- private static int getCharGroupMaximumSize(final CharGroup group, final FormatOptions options) {
- int size = getGroupHeaderSize(group, options);
- // If terminal, one byte for the frequency
- if (group.isTerminal()) size += FormatSpec.GROUP_FREQUENCY_SIZE;
- size += FormatSpec.GROUP_MAX_ADDRESS_SIZE; // For children address
- size += getShortcutListSize(group.mShortcutTargets);
- if (null != group.mBigrams) {
- size += (FormatSpec.GROUP_ATTRIBUTE_FLAGS_SIZE
- + FormatSpec.GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE)
- * group.mBigrams.size();
- }
- return size;
- }
-
- /**
- * Compute the maximum size of a node, assuming 3-byte addresses for everything, and caches
- * it in the 'actualSize' member of the node.
- *
- * @param node the node to compute the maximum size of.
- * @param options file format options.
- */
- private static void calculateNodeMaximumSize(final Node node, final FormatOptions options) {
- int size = getGroupCountSize(node);
- for (CharGroup g : node.mData) {
- final int groupSize = getCharGroupMaximumSize(g, options);
- g.mCachedSize = groupSize;
- size += groupSize;
- }
- if (options.mSupportsDynamicUpdate) {
- size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
- }
- node.mCachedSize = size;
- }
-
- /**
- * Compute the size of the header (flag + [parent address] + characters size) of a CharGroup.
- *
- * @param group the group of which to compute the size of the header
- * @param options file format options.
- */
- private static int getGroupHeaderSize(final CharGroup group, final FormatOptions options) {
- if (BinaryDictIOUtils.supportsDynamicUpdate(options)) {
- return FormatSpec.GROUP_FLAGS_SIZE + FormatSpec.PARENT_ADDRESS_SIZE
- + getGroupCharactersSize(group);
- } else {
- return FormatSpec.GROUP_FLAGS_SIZE + getGroupCharactersSize(group);
- }
- }
-
- /**
- * Compute the size, in bytes, that an address will occupy.
- *
- * This can be used either for children addresses (which are always positive) or for
- * attribute, which may be positive or negative but
- * store their sign bit separately.
- *
- * @param address the address
- * @return the byte size.
- */
- static int getByteSize(final int address) {
- assert(address <= FormatSpec.UINT24_MAX);
- if (!BinaryDictIOUtils.hasChildrenAddress(address)) {
- return 0;
- } else if (Math.abs(address) <= FormatSpec.UINT8_MAX) {
- return 1;
- } else if (Math.abs(address) <= FormatSpec.UINT16_MAX) {
- return 2;
- } else {
- return 3;
- }
- }
-
- // End utility methods
-
- // This method is responsible for finding a nice ordering of the nodes that favors run-time
- // cache performance and dictionary size.
- /* package for tests */ static ArrayList<Node> flattenTree(final Node root) {
- final int treeSize = FusionDictionary.countCharGroups(root);
- MakedictLog.i("Counted nodes : " + treeSize);
- final ArrayList<Node> flatTree = new ArrayList<Node>(treeSize);
- return flattenTreeInner(flatTree, root);
- }
-
- private static ArrayList<Node> flattenTreeInner(final ArrayList<Node> list, final Node node) {
- // Removing the node is necessary if the tails are merged, because we would then
- // add the same node several times when we only want it once. A number of places in
- // the code also depends on any node being only once in the list.
- // Merging tails can only be done if there are no attributes. Searching for attributes
- // in LatinIME code depends on a total breadth-first ordering, which merging tails
- // breaks. If there are no attributes, it should be fine (and reduce the file size)
- // to merge tails, and removing the node from the list would be necessary. However,
- // we don't merge tails because breaking the breadth-first ordering would result in
- // extreme overhead at bigram lookup time (it would make the search function O(n) instead
- // of the current O(log(n)), where n=number of nodes in the dictionary which is pretty
- // high).
- // If no nodes are ever merged, we can't have the same node twice in the list, hence
- // searching for duplicates in unnecessary. It is also very performance consuming,
- // since `list' is an ArrayList so it's an O(n) operation that runs on all nodes, making
- // this simple list.remove operation O(n*n) overall. On Android this overhead is very
- // high.
- // For future reference, the code to remove duplicate is a simple : list.remove(node);
- list.add(node);
- final ArrayList<CharGroup> branches = node.mData;
- final int nodeSize = branches.size();
- for (CharGroup group : branches) {
- if (null != group.mChildren) flattenTreeInner(list, group.mChildren);
- }
- return list;
- }
-
- /**
- * Get the offset from a position inside a current node to a target node, during update.
- *
- * If the current node is before the target node, the target node has not been updated yet,
- * so we should return the offset from the old position of the current node to the old position
- * of the target node. If on the other hand the target is before the current node, it already
- * has been updated, so we should return the offset from the new position in the current node
- * to the new position in the target node.
- * @param currentNode the node containing the CharGroup where the offset will be written
- * @param offsetFromStartOfCurrentNode the offset, in bytes, from the start of currentNode
- * @param targetNode the target node to get the offset to
- * @return the offset to the target node
- */
- private static int getOffsetToTargetNodeDuringUpdate(final Node currentNode,
- final int offsetFromStartOfCurrentNode, final Node targetNode) {
- final boolean isTargetBeforeCurrent = (targetNode.mCachedAddressBeforeUpdate
- < currentNode.mCachedAddressBeforeUpdate);
- if (isTargetBeforeCurrent) {
- return targetNode.mCachedAddressAfterUpdate
- - (currentNode.mCachedAddressAfterUpdate + offsetFromStartOfCurrentNode);
- } else {
- return targetNode.mCachedAddressBeforeUpdate
- - (currentNode.mCachedAddressBeforeUpdate + offsetFromStartOfCurrentNode);
- }
- }
-
- /**
- * Get the offset from a position inside a current node to a target CharGroup, during update.
- * @param currentNode the node containing the CharGroup where the offset will be written
- * @param offsetFromStartOfCurrentNode the offset, in bytes, from the start of currentNode
- * @param targetCharGroup the target CharGroup to get the offset to
- * @return the offset to the target CharGroup
- */
- // TODO: is there any way to factorize this method with the one above?
- private static int getOffsetToTargetCharGroupDuringUpdate(final Node currentNode,
- final int offsetFromStartOfCurrentNode, final CharGroup targetCharGroup) {
- final int oldOffsetBasePoint = currentNode.mCachedAddressBeforeUpdate
- + offsetFromStartOfCurrentNode;
- final boolean isTargetBeforeCurrent = (targetCharGroup.mCachedAddressBeforeUpdate
- < oldOffsetBasePoint);
- // If the target is before the current node, then its address has already been updated.
- // We can use the AfterUpdate member, and compare it to our own member after update.
- // Otherwise, the AfterUpdate member is not updated yet, so we need to use the BeforeUpdate
- // member, and of course we have to compare this to our own address before update.
- if (isTargetBeforeCurrent) {
- final int newOffsetBasePoint = currentNode.mCachedAddressAfterUpdate
- + offsetFromStartOfCurrentNode;
- return targetCharGroup.mCachedAddressAfterUpdate - newOffsetBasePoint;
- } else {
- return targetCharGroup.mCachedAddressBeforeUpdate - oldOffsetBasePoint;
- }
- }
-
- /**
- * Computes the actual node size, based on the cached addresses of the children nodes.
- *
- * Each node stores its tentative address. During dictionary address computing, these
- * are not final, but they can be used to compute the node size (the node size depends
- * on the address of the children because the number of bytes necessary to store an
- * address depends on its numeric value. The return value indicates whether the node
- * contents (as in, any of the addresses stored in the cache fields) have changed with
- * respect to their previous value.
- *
- * @param node the node 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 changed, true otherwise.
- */
- private static boolean computeActualNodeSize(final Node node, final FusionDictionary dict,
- final FormatOptions formatOptions) {
- boolean changed = false;
- int size = getGroupCountSize(node);
- for (CharGroup group : node.mData) {
- group.mCachedAddressAfterUpdate = node.mCachedAddressAfterUpdate + size;
- if (group.mCachedAddressAfterUpdate != group.mCachedAddressBeforeUpdate) {
- changed = true;
- }
- int groupSize = getGroupHeaderSize(group, formatOptions);
- if (group.isTerminal()) groupSize += FormatSpec.GROUP_FREQUENCY_SIZE;
- if (null == group.mChildren && formatOptions.mSupportsDynamicUpdate) {
- groupSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
- } else if (null != group.mChildren) {
- if (formatOptions.mSupportsDynamicUpdate) {
- groupSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
- } else {
- groupSize += getByteSize(getOffsetToTargetNodeDuringUpdate(node,
- groupSize + size, group.mChildren));
- }
- }
- groupSize += getShortcutListSize(group.mShortcutTargets);
- if (null != group.mBigrams) {
- for (WeightedString bigram : group.mBigrams) {
- final int offset = getOffsetToTargetCharGroupDuringUpdate(node,
- groupSize + size + FormatSpec.GROUP_FLAGS_SIZE,
- FusionDictionary.findWordInTree(dict.mRoot, bigram.mWord));
- groupSize += getByteSize(offset) + FormatSpec.GROUP_FLAGS_SIZE;
- }
- }
- group.mCachedSize = groupSize;
- size += groupSize;
- }
- if (formatOptions.mSupportsDynamicUpdate) {
- size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
- }
- if (node.mCachedSize != size) {
- node.mCachedSize = size;
- changed = true;
- }
- return changed;
- }
-
- /**
- * Initializes the cached addresses of nodes from their size.
- *
- * @param flatNodes the array of nodes.
- * @param formatOptions file format options.
- * @return the byte size of the entire stack.
- */
- private static int initializeNodesCachedAddresses(final ArrayList<Node> flatNodes,
- final FormatOptions formatOptions) {
- int nodeOffset = 0;
- for (final Node n : flatNodes) {
- n.mCachedAddressBeforeUpdate = nodeOffset;
- int groupCountSize = getGroupCountSize(n);
- int groupOffset = 0;
- for (final CharGroup g : n.mData) {
- g.mCachedAddressBeforeUpdate = g.mCachedAddressAfterUpdate =
- groupCountSize + nodeOffset + groupOffset;
- groupOffset += g.mCachedSize;
- }
- final int nodeSize = groupCountSize + groupOffset
- + (formatOptions.mSupportsDynamicUpdate
- ? FormatSpec.FORWARD_LINK_ADDRESS_SIZE : 0);
- nodeOffset += n.mCachedSize;
- }
- return nodeOffset;
- }
-
- /**
- * Updates the cached addresses of nodes after recomputing their new positions.
- *
- * @param flatNodes the array of nodes.
- */
- private static void updateNodeCachedAddresses(final ArrayList<Node> flatNodes) {
- for (final Node n : flatNodes) {
- n.mCachedAddressBeforeUpdate = n.mCachedAddressAfterUpdate;
- for (final CharGroup g : n.mData) {
- g.mCachedAddressBeforeUpdate = g.mCachedAddressAfterUpdate;
- }
- }
- }
-
- /**
- * 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 nodes to fill in
- */
- private static void computeParentAddresses(final ArrayList<Node> flatNodes) {
- for (final Node node : flatNodes) {
- for (final CharGroup group : node.mData) {
- if (null != group.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.
- group.mChildren.mCachedParentAddress = group.mCachedAddressAfterUpdate
- - group.mChildren.mCachedAddressAfterUpdate;
- }
- }
- }
- }
-
- /**
- * Compute the addresses and sizes of an ordered node array.
- *
- * This method takes a node array and will update its cached address and size values
- * so that they can be written into a file. It determines the smallest size each of the
- * nodes can be given the addresses of its children and attributes, and store that into
- * each node.
- * The order of the node is given by the order of the array. This method makes no effort
- * to find a good order; it only mechanically computes the size this order results in.
- *
- * @param dict the dictionary
- * @param flatNodes the ordered array of nodes
- * @param formatOptions file format options.
- * @return the same array it was passed. The nodes have been updated for address and size.
- */
- private static ArrayList<Node> computeAddresses(final FusionDictionary dict,
- final ArrayList<Node> flatNodes, final FormatOptions formatOptions) {
- // First get the worst possible sizes and offsets
- for (final Node n : flatNodes) calculateNodeMaximumSize(n, formatOptions);
- final int offset = initializeNodesCachedAddresses(flatNodes, formatOptions);
-
- MakedictLog.i("Compressing the array addresses. Original size : " + offset);
- MakedictLog.i("(Recursively seen size : " + offset + ")");
-
- int passes = 0;
- boolean changesDone = false;
- do {
- changesDone = false;
- int nodeStartOffset = 0;
- for (final Node n : flatNodes) {
- n.mCachedAddressAfterUpdate = nodeStartOffset;
- final int oldNodeSize = n.mCachedSize;
- final boolean changed = computeActualNodeSize(n, dict, formatOptions);
- final int newNodeSize = n.mCachedSize;
- if (oldNodeSize < newNodeSize) throw new RuntimeException("Increased size ?!");
- nodeStartOffset += newNodeSize;
- changesDone |= changed;
- }
- updateNodeCachedAddresses(flatNodes);
- ++passes;
- if (passes > MAX_PASSES) throw new RuntimeException("Too many passes - probably a bug");
- } while (changesDone);
-
- if (formatOptions.mSupportsDynamicUpdate) {
- computeParentAddresses(flatNodes);
- }
- final Node lastNode = flatNodes.get(flatNodes.size() - 1);
- MakedictLog.i("Compression complete in " + passes + " passes.");
- MakedictLog.i("After address compression : "
- + (lastNode.mCachedAddressAfterUpdate + lastNode.mCachedSize));
-
- return flatNodes;
- }
-
- /**
- * Sanity-checking method.
- *
- * This method checks an array of node for juxtaposition, that is, it will do
- * nothing if each node's cached address is actually the previous node's address
- * plus the previous node's size.
- * If this is not the case, it will throw an exception.
- *
- * @param array the array node to check
- */
- private static void checkFlatNodeArray(final ArrayList<Node> array) {
- int offset = 0;
- int index = 0;
- for (final Node n : array) {
- // BeforeUpdate and AfterUpdate addresses are the same here, so it does not matter
- // which we use.
- if (n.mCachedAddressAfterUpdate != offset) {
- throw new RuntimeException("Wrong address for node " + index
- + " : expected " + offset + ", got " + n.mCachedAddressAfterUpdate);
- }
- ++index;
- offset += n.mCachedSize;
- }
- }
-
- /**
- * Helper method to write a variable-size address to a file.
- *
- * @param buffer the buffer to write to.
- * @param index the index in the buffer to write the address to.
- * @param address the address to write.
- * @return the size in bytes the address actually took.
- */
- private static int writeVariableAddress(final byte[] buffer, int index, final int address) {
- switch (getByteSize(address)) {
- case 1:
- buffer[index++] = (byte)address;
- return 1;
- case 2:
- buffer[index++] = (byte)(0xFF & (address >> 8));
- buffer[index++] = (byte)(0xFF & address);
- return 2;
- case 3:
- buffer[index++] = (byte)(0xFF & (address >> 16));
- buffer[index++] = (byte)(0xFF & (address >> 8));
- buffer[index++] = (byte)(0xFF & address);
- return 3;
- case 0:
- return 0;
- default:
- throw new RuntimeException("Address " + address + " has a strange size");
- }
- }
-
- /**
- * Helper method to write a variable-size signed address to a file.
- *
- * @param buffer the buffer to write to.
- * @param index the index in the buffer to write the address to.
- * @param address the address to write.
- * @return the size in bytes the address actually took.
- */
- private static int writeVariableSignedAddress(final byte[] buffer, int index,
- final int address) {
- if (!BinaryDictIOUtils.hasChildrenAddress(address)) {
- buffer[index] = buffer[index + 1] = buffer[index + 2] = 0;
- } else {
- final int absAddress = Math.abs(address);
- buffer[index++] =
- (byte)((address < 0 ? FormatSpec.MSB8 : 0) | (0xFF & (absAddress >> 16)));
- buffer[index++] = (byte)(0xFF & (absAddress >> 8));
- buffer[index++] = (byte)(0xFF & absAddress);
- }
- return 3;
- }
-
- /**
- * Makes the flag value for a char group.
- *
- * @param hasMultipleChars whether the group has multiple chars.
- * @param isTerminal whether the group is terminal.
- * @param childrenAddressSize the size of a children address.
- * @param hasShortcuts whether the group has shortcuts.
- * @param hasBigrams whether the group has bigrams.
- * @param isNotAWord whether the group is not a word.
- * @param isBlackListEntry whether the group is a blacklist entry.
- * @param formatOptions file format options.
- * @return the flags
- */
- static int makeCharGroupFlags(final boolean hasMultipleChars, final boolean isTerminal,
- final int childrenAddressSize, final boolean hasShortcuts, final boolean hasBigrams,
- final boolean isNotAWord, final boolean isBlackListEntry,
- final FormatOptions formatOptions) {
- 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_GROUP_ADDRESS_TYPE_ONEBYTE;
- break;
- case 2:
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES;
- break;
- case 3:
- flags |= FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES;
- break;
- case 0:
- flags |= FormatSpec.FLAG_GROUP_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;
- if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
- if (isBlackListEntry) flags |= FormatSpec.FLAG_IS_BLACKLISTED;
- return flags;
- }
-
- private static byte makeCharGroupFlags(final CharGroup group, final int groupAddress,
- final int childrenOffset, final FormatOptions formatOptions) {
- return (byte) makeCharGroupFlags(group.mChars.length > 1, group.mFrequency >= 0,
- getByteSize(childrenOffset), group.mShortcutTargets != null, group.mBigrams != null,
- group.mIsNotAWord, group.mIsBlacklistEntry, formatOptions);
- }
-
- /**
- * Makes the flag value for a bigram.
- *
- * @param more whether there are more bigrams after this one.
- * @param offset the offset of the bigram.
- * @param bigramFrequency the frequency of the bigram, 0..255.
- * @param unigramFrequency the unigram frequency of the same word, 0..255.
- * @param word the second bigram, for debugging purposes
- * @return the flags
- */
- private static final int makeBigramFlags(final boolean more, final int offset,
- int bigramFrequency, final int unigramFrequency, final String word) {
- int bigramFlags = (more ? FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT : 0)
- + (offset < 0 ? FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE : 0);
- switch (getByteSize(offset)) {
- case 1:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
- break;
- case 2:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
- break;
- case 3:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
- break;
- default:
- throw new RuntimeException("Strange offset size");
- }
- if (unigramFrequency > bigramFrequency) {
- MakedictLog.e("Unigram freq is superior to bigram freq for \"" + word
- + "\". Bigram freq is " + bigramFrequency + ", unigram freq for "
- + word + " is " + unigramFrequency);
- bigramFrequency = unigramFrequency;
- }
- // 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
- // represents an increase of 16 steps: a value of 15 will be interpreted as the median
- // value of the 16th step. In all justice, if the bigram frequency is low enough to be
- // rounded below the first step (which means it is less than half a step higher than the
- // unigram frequency) then the unigram frequency itself is the best approximation of the
- // bigram freq that we could possibly supply, hence we should *not* include this bigram
- // in the file at all.
- // until this is done, we'll write 0 and slightly overestimate this case.
- // In other words, 0 means "between 0.5 step and 1.5 step", 1 means "between 1.5 step
- // and 2.5 steps", and 15 means "between 15.5 steps and 16.5 steps". So we want to
- // divide our range [unigramFreq..MAX_TERMINAL_FREQUENCY] in 16.5 steps to get the
- // step size. Then we compute the start of the first step (the one where value 0 starts)
- // by adding half-a-step to the unigramFrequency. From there, we compute the integer
- // number of steps to the bigramFrequency. One last thing: we want our steps to include
- // their lower bound and exclude their higher bound so we need to have the first step
- // start at exactly 1 unit higher than floor(unigramFreq + half a step).
- // Note : to reconstruct the score, the dictionary reader will need to divide
- // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise to get the value of the step,
- // and add (discretizedFrequency + 0.5 + 0.5) times this value to get the best
- // approximation. (0.5 to get the first step start, and 0.5 to get the middle of the
- // step pointed by the discretized frequency.
- final float stepSize =
- (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency)
- / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY);
- final float firstStepStart = 1 + unigramFrequency + (stepSize / 2.0f);
- final int discretizedFrequency = (int)((bigramFrequency - firstStepStart) / stepSize);
- // If the bigram freq is less than half-a-step higher than the unigram freq, we get -1
- // here. The best approximation would be the unigram freq itself, so we should not
- // 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_ATTRIBUTE_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);
- }
-
- /**
- * Makes the flag value for a shortcut.
- *
- * @param more whether there are more attributes after this one.
- * @param frequency the frequency of the attribute, 0..15
- * @return the flags
- */
- static final int makeShortcutFlags(final boolean more, final int frequency) {
- return (more ? FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT : 0)
- + (frequency & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY);
- }
-
- private 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;
- }
- }
-
- /**
- * Write a node to memory. The node is expected to have its final position cached.
- *
- * This can be an empty map, but the more is inside the faster the lookups will be. It can
- * be carried on as long as nodes do not move.
- *
- * @param dict the dictionary the node is a part of (for relative offsets).
- * @param buffer the memory buffer to write to.
- * @param node the node to write.
- * @param formatOptions file format options.
- * @return the address of the END of the node.
- */
- @SuppressWarnings("unused")
- private static int writePlacedNode(final FusionDictionary dict, byte[] buffer,
- final Node node, final FormatOptions formatOptions) {
- // TODO: Make the code in common with BinaryDictIOUtils#writeCharGroup
- int index = node.mCachedAddressAfterUpdate;
-
- final int groupCount = node.mData.size();
- final int countSize = getGroupCountSize(node);
- final int parentAddress = node.mCachedParentAddress;
- if (1 == countSize) {
- buffer[index++] = (byte)groupCount;
- } else if (2 == countSize) {
- // We need to signal 2-byte size by setting the top bit of the MSB to 1, so
- // we | 0x80 to do this.
- buffer[index++] = (byte)((groupCount >> 8) | 0x80);
- buffer[index++] = (byte)(groupCount & 0xFF);
- } else {
- throw new RuntimeException("Strange size from getGroupCountSize : " + countSize);
- }
- int groupAddress = index;
- for (int i = 0; i < groupCount; ++i) {
- final CharGroup group = node.mData.get(i);
- if (index != group.mCachedAddressAfterUpdate) {
- throw new RuntimeException("Bug: write index is not the same as the cached address "
- + "of the group : " + index + " <> " + group.mCachedAddressAfterUpdate);
- }
- groupAddress += getGroupHeaderSize(group, formatOptions);
- // Sanity checks.
- if (DBG && group.mFrequency > FormatSpec.MAX_TERMINAL_FREQUENCY) {
- throw new RuntimeException("A node has a frequency > "
- + FormatSpec.MAX_TERMINAL_FREQUENCY
- + " : " + group.mFrequency);
- }
- if (group.mFrequency >= 0) groupAddress += FormatSpec.GROUP_FREQUENCY_SIZE;
- final int childrenOffset = null == group.mChildren
- ? FormatSpec.NO_CHILDREN_ADDRESS
- : group.mChildren.mCachedAddressAfterUpdate - groupAddress;
- buffer[index++] =
- makeCharGroupFlags(group, groupAddress, childrenOffset, formatOptions);
-
- if (parentAddress == FormatSpec.NO_PARENT_ADDRESS) {
- index = writeParentAddress(buffer, index, parentAddress, formatOptions);
- } else {
- index = writeParentAddress(buffer, index, parentAddress
- + (node.mCachedAddressAfterUpdate - group.mCachedAddressAfterUpdate),
- formatOptions);
- }
-
- index = CharEncoding.writeCharArray(group.mChars, buffer, index);
- if (group.hasSeveralChars()) {
- buffer[index++] = FormatSpec.GROUP_CHARACTERS_TERMINATOR;
- }
- if (group.mFrequency >= 0) {
- buffer[index++] = (byte) group.mFrequency;
- }
-
- final int shift;
- if (formatOptions.mSupportsDynamicUpdate) {
- shift = writeVariableSignedAddress(buffer, index, childrenOffset);
- } else {
- shift = writeVariableAddress(buffer, index, childrenOffset);
- }
- index += shift;
- groupAddress += shift;
-
- // Write shortcuts
- if (null != group.mShortcutTargets) {
- final int indexOfShortcutByteSize = index;
- index += FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE;
- groupAddress += FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE;
- final Iterator<WeightedString> shortcutIterator = group.mShortcutTargets.iterator();
- while (shortcutIterator.hasNext()) {
- final WeightedString target = shortcutIterator.next();
- ++groupAddress;
- int shortcutFlags = makeShortcutFlags(shortcutIterator.hasNext(),
- target.mFrequency);
- buffer[index++] = (byte)shortcutFlags;
- final int shortcutShift = CharEncoding.writeString(buffer, index, target.mWord);
- index += shortcutShift;
- groupAddress += shortcutShift;
- }
- final int shortcutByteSize = index - indexOfShortcutByteSize;
- if (shortcutByteSize > 0xFFFF) {
- throw new RuntimeException("Shortcut list too large");
- }
- buffer[indexOfShortcutByteSize] = (byte)(shortcutByteSize >> 8);
- buffer[indexOfShortcutByteSize + 1] = (byte)(shortcutByteSize & 0xFF);
- }
- // Write bigrams
- if (null != group.mBigrams) {
- final Iterator<WeightedString> bigramIterator = group.mBigrams.iterator();
- while (bigramIterator.hasNext()) {
- final WeightedString bigram = bigramIterator.next();
- final CharGroup target =
- FusionDictionary.findWordInTree(dict.mRoot, bigram.mWord);
- final int addressOfBigram = target.mCachedAddressAfterUpdate;
- final int unigramFrequencyForThisWord = target.mFrequency;
- ++groupAddress;
- final int offset = addressOfBigram - groupAddress;
- int bigramFlags = makeBigramFlags(bigramIterator.hasNext(), offset,
- bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord);
- buffer[index++] = (byte)bigramFlags;
- final int bigramShift = writeVariableAddress(buffer, index, Math.abs(offset));
- index += bigramShift;
- groupAddress += bigramShift;
- }
- }
-
- }
- if (formatOptions.mSupportsDynamicUpdate) {
- buffer[index] = buffer[index + 1] = buffer[index + 2]
- = FormatSpec.NO_FORWARD_LINK_ADDRESS;
- index += FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
- }
- if (index != node.mCachedAddressAfterUpdate + node.mCachedSize) throw new RuntimeException(
- "Not the same size : written "
- + (index - node.mCachedAddressAfterUpdate) + " bytes from a node that should have "
- + node.mCachedSize + " bytes");
- return index;
- }
-
- /**
- * Dumps a collection of useful statistics about a node array.
- *
- * This prints purely informative stuff, like the total estimated file size, the
- * number of nodes, of character groups, the repartition of each address size, etc
- *
- * @param nodes the node array.
- */
- private static void showStatistics(ArrayList<Node> nodes) {
- int firstTerminalAddress = Integer.MAX_VALUE;
- int lastTerminalAddress = Integer.MIN_VALUE;
- int size = 0;
- int charGroups = 0;
- int maxGroups = 0;
- int maxRuns = 0;
- for (final Node n : nodes) {
- if (maxGroups < n.mData.size()) maxGroups = n.mData.size();
- for (final CharGroup cg : n.mData) {
- ++charGroups;
- if (cg.mChars.length > maxRuns) maxRuns = cg.mChars.length;
- if (cg.mFrequency >= 0) {
- if (n.mCachedAddressAfterUpdate < firstTerminalAddress)
- firstTerminalAddress = n.mCachedAddressAfterUpdate;
- if (n.mCachedAddressAfterUpdate > lastTerminalAddress)
- lastTerminalAddress = n.mCachedAddressAfterUpdate;
- }
- }
- if (n.mCachedAddressAfterUpdate + n.mCachedSize > size) {
- size = n.mCachedAddressAfterUpdate + n.mCachedSize;
- }
- }
- final int[] groupCounts = new int[maxGroups + 1];
- final int[] runCounts = new int[maxRuns + 1];
- for (final Node n : nodes) {
- ++groupCounts[n.mData.size()];
- for (final CharGroup cg : n.mData) {
- ++runCounts[cg.mChars.length];
- }
- }
-
- MakedictLog.i("Statistics:\n"
- + " total file size " + size + "\n"
- + " " + nodes.size() + " nodes\n"
- + " " + charGroups + " groups (" + ((float)charGroups / nodes.size())
- + " groups per node)\n"
- + " first terminal at " + firstTerminalAddress + "\n"
- + " last terminal at " + lastTerminalAddress + "\n"
- + " Group stats : max = " + maxGroups);
- for (int i = 0; i < groupCounts.length; ++i) {
- MakedictLog.i(" " + i + " : " + groupCounts[i]);
- }
- MakedictLog.i(" Character run stats : max = " + maxRuns);
- for (int i = 0; i < runCounts.length; ++i) {
- MakedictLog.i(" " + i + " : " + runCounts[i]);
- }
- }
-
- /**
- * Dumps a FusionDictionary to a file.
- *
- * This is the public entry point to write a dictionary to a file.
- *
- * @param destination the stream to write the binary data to.
- * @param dict the dictionary to write.
- * @param formatOptions file format options.
- */
- public static void writeDictionaryBinary(final OutputStream destination,
- final FusionDictionary dict, final FormatOptions formatOptions)
- throws IOException, UnsupportedFormatException {
-
- // Addresses are limited to 3 bytes, but since addresses can be relative to each node, the
- // structure itself is not limited to 16MB. However, if it is over 16MB deciding the order
- // of the nodes becomes a quite complicated problem, because though the dictionary itself
- // does not have a size limit, each node must still be within 16MB of all its children and
- // parents. As long as this is ensured, the dictionary file may grow to any size.
-
- final int version = formatOptions.mVersion;
- if (version < FormatSpec.MINIMUM_SUPPORTED_VERSION
- || version > FormatSpec.MAXIMUM_SUPPORTED_VERSION) {
- throw new UnsupportedFormatException("Requested file format version " + version
- + ", but this implementation only supports versions "
- + FormatSpec.MINIMUM_SUPPORTED_VERSION + " through "
- + FormatSpec.MAXIMUM_SUPPORTED_VERSION);
- }
-
- ByteArrayOutputStream headerBuffer = new ByteArrayOutputStream(256);
-
- // The magic number in big-endian order.
- // Magic number for all versions.
- headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 24)));
- headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 16)));
- headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 8)));
- headerBuffer.write((byte) (0xFF & FormatSpec.MAGIC_NUMBER));
- // Dictionary version.
- headerBuffer.write((byte) (0xFF & (version >> 8)));
- headerBuffer.write((byte) (0xFF & version));
-
- // Options flags
- final int options = makeOptionsValue(dict, formatOptions);
- headerBuffer.write((byte) (0xFF & (options >> 8)));
- headerBuffer.write((byte) (0xFF & options));
- final int headerSizeOffset = headerBuffer.size();
- // Placeholder to be written later with header size.
- for (int i = 0; i < 4; ++i) {
- headerBuffer.write(0);
- }
- // Write out the options.
- for (final String key : dict.mOptions.mAttributes.keySet()) {
- final String value = dict.mOptions.mAttributes.get(key);
- CharEncoding.writeString(headerBuffer, key);
- CharEncoding.writeString(headerBuffer, value);
- }
- final int size = headerBuffer.size();
- final byte[] bytes = headerBuffer.toByteArray();
- // Write out the header size.
- bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
- bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
- bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
- bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
- destination.write(bytes);
-
- headerBuffer.close();
-
- // Leave the choice of the optimal node order to the flattenTree function.
- MakedictLog.i("Flattening the tree...");
- ArrayList<Node> flatNodes = flattenTree(dict.mRoot);
-
- MakedictLog.i("Computing addresses...");
- computeAddresses(dict, flatNodes, formatOptions);
- MakedictLog.i("Checking array...");
- if (DBG) checkFlatNodeArray(flatNodes);
-
- // Create a buffer that matches the final dictionary size.
- final Node lastNode = flatNodes.get(flatNodes.size() - 1);
- final int bufferSize = lastNode.mCachedAddressAfterUpdate + lastNode.mCachedSize;
- final byte[] buffer = new byte[bufferSize];
- int index = 0;
-
- MakedictLog.i("Writing file...");
- int dataEndOffset = 0;
- for (Node n : flatNodes) {
- dataEndOffset = writePlacedNode(dict, buffer, n, formatOptions);
- }
-
- if (DBG) showStatistics(flatNodes);
-
- destination.write(buffer, 0, dataEndOffset);
-
- destination.close();
- MakedictLog.i("Done");
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
new file mode 100644
index 000000000..6cc0bfb76
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
@@ -0,0 +1,958 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+/**
+ * Encodes binary files for a FusionDictionary.
+ *
+ * All the methods in this class are static.
+ *
+ * TODO: Rename this class to DictEncoderUtils.
+ */
+public class BinaryDictEncoderUtils {
+
+ private static final boolean DBG = MakedictLog.DBG;
+
+ private BinaryDictEncoderUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ // Arbitrary limit to how much passes we consider address size compression should
+ // terminate in. At the time of this writing, our largest dictionary completes
+ // compression in five passes.
+ // If the number of passes exceeds this number, makedict bails with an exception on
+ // suspicion that a bug might be causing an infinite loop.
+ private static final int MAX_PASSES = 24;
+
+ /**
+ * Compute the binary size of the character array.
+ *
+ * If only one character, this is the size of this character. If many, it's the sum of their
+ * sizes + 1 byte for the terminator.
+ *
+ * @param characters the character array
+ * @return the size of the char array, including the terminator if any
+ */
+ static int getPtNodeCharactersSize(final int[] characters) {
+ int size = CharEncoding.getCharArraySize(characters);
+ if (characters.length > 1) size += FormatSpec.PTNODE_TERMINATOR_SIZE;
+ return size;
+ }
+
+ /**
+ * Compute the binary size of the character array in a PtNode
+ *
+ * If only one character, this is the size of this character. If many, it's the sum of their
+ * sizes + 1 byte for the terminator.
+ *
+ * @param ptNode the PtNode
+ * @return the size of the char array, including the terminator if any
+ */
+ private static int getPtNodeCharactersSize(final PtNode ptNode) {
+ return getPtNodeCharactersSize(ptNode.mChars);
+ }
+
+ /**
+ * Compute the binary size of the PtNode count for a node array.
+ * @param nodeArray the nodeArray
+ * @return the size of the PtNode count, either 1 or 2 bytes.
+ */
+ private static int getPtNodeCountSize(final PtNodeArray nodeArray) {
+ return BinaryDictIOUtils.getPtNodeCountSize(nodeArray.mData.size());
+ }
+
+ /**
+ * Compute the size of a shortcut in bytes.
+ */
+ private static int getShortcutSize(final WeightedString shortcut) {
+ int size = FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE;
+ final String word = shortcut.mWord;
+ final int length = word.length();
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = word.codePointAt(i);
+ size += CharEncoding.getCharSize(codePoint);
+ }
+ size += FormatSpec.PTNODE_TERMINATOR_SIZE;
+ return size;
+ }
+
+ /**
+ * Compute the size of a shortcut list in bytes.
+ *
+ * This is known in advance and does not change according to position in the file
+ * like address lists do.
+ */
+ static int getShortcutListSize(final ArrayList<WeightedString> shortcutList) {
+ if (null == shortcutList || shortcutList.isEmpty()) return 0;
+ int size = FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
+ for (final WeightedString shortcut : shortcutList) {
+ size += getShortcutSize(shortcut);
+ }
+ return size;
+ }
+
+ /**
+ * 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);
+ 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;
+ }
+ }
+ size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address
+ size += getShortcutListSize(ptNode.mShortcutTargets);
+ if (null != ptNode.mBigrams) {
+ size += (FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE
+ + FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE)
+ * ptNode.mBigrams.size();
+ }
+ return size;
+ }
+
+ /**
+ * Compute the maximum size of each PtNode of a PtNode array, assuming 3-byte addresses for
+ * everything, and caches it in the `mCachedSize' member of the nodes; deduce the size of
+ * 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) {
+ int size = getPtNodeCountSize(ptNodeArray);
+ for (PtNode node : ptNodeArray.mData) {
+ final int nodeSize = getPtNodeMaximumSize(node, options);
+ node.mCachedSize = nodeSize;
+ size += nodeSize;
+ }
+ if (options.mSupportsDynamicUpdate) {
+ size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
+ }
+ ptNodeArray.mCachedSize = size;
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Compute the size, in bytes, that an address will occupy.
+ *
+ * This can be used either for children addresses (which are always positive) or for
+ * attribute, which may be positive or negative but
+ * store their sign bit separately.
+ *
+ * @param address the address
+ * @return the byte size.
+ */
+ static int getByteSize(final int address) {
+ assert(address <= FormatSpec.UINT24_MAX);
+ if (!BinaryDictIOUtils.hasChildrenAddress(address)) {
+ return 0;
+ } else if (Math.abs(address) <= FormatSpec.UINT8_MAX) {
+ return 1;
+ } else if (Math.abs(address) <= FormatSpec.UINT16_MAX) {
+ return 2;
+ } else {
+ return 3;
+ }
+ }
+
+ static int writeUIntToBuffer(final byte[] buffer, int position, final int value,
+ final int size) {
+ switch(size) {
+ case 4:
+ buffer[position++] = (byte) ((value >> 24) & 0xFF);
+ /* fall through */
+ case 3:
+ buffer[position++] = (byte) ((value >> 16) & 0xFF);
+ /* fall through */
+ case 2:
+ buffer[position++] = (byte) ((value >> 8) & 0xFF);
+ /* fall through */
+ case 1:
+ buffer[position++] = (byte) (value & 0xFF);
+ break;
+ default:
+ /* nop */
+ }
+ return position;
+ }
+
+ static void writeUIntToStream(final OutputStream stream, final int value, final int size)
+ throws IOException {
+ switch(size) {
+ case 4:
+ stream.write((value >> 24) & 0xFF);
+ /* fall through */
+ case 3:
+ stream.write((value >> 16) & 0xFF);
+ /* fall through */
+ case 2:
+ stream.write((value >> 8) & 0xFF);
+ /* fall through */
+ case 1:
+ stream.write(value & 0xFF);
+ break;
+ default:
+ /* nop */
+ }
+ }
+
+ // End utility methods
+
+ // This method is responsible for finding a nice ordering of the nodes that favors run-time
+ // cache performance and dictionary size.
+ /* package for tests */ static ArrayList<PtNodeArray> flattenTree(
+ final PtNodeArray rootNodeArray) {
+ final int treeSize = FusionDictionary.countPtNodes(rootNodeArray);
+ MakedictLog.i("Counted nodes : " + treeSize);
+ final ArrayList<PtNodeArray> flatTree = new ArrayList<PtNodeArray>(treeSize);
+ return flattenTreeInner(flatTree, rootNodeArray);
+ }
+
+ private static ArrayList<PtNodeArray> flattenTreeInner(final ArrayList<PtNodeArray> list,
+ final PtNodeArray ptNodeArray) {
+ // Removing the node is necessary if the tails are merged, because we would then
+ // add the same node several times when we only want it once. A number of places in
+ // the code also depends on any node being only once in the list.
+ // Merging tails can only be done if there are no attributes. Searching for attributes
+ // in LatinIME code depends on a total breadth-first ordering, which merging tails
+ // breaks. If there are no attributes, it should be fine (and reduce the file size)
+ // to merge tails, and removing the node from the list would be necessary. However,
+ // we don't merge tails because breaking the breadth-first ordering would result in
+ // extreme overhead at bigram lookup time (it would make the search function O(n) instead
+ // of the current O(log(n)), where n=number of nodes in the dictionary which is pretty
+ // high).
+ // If no nodes are ever merged, we can't have the same node twice in the list, hence
+ // searching for duplicates in unnecessary. It is also very performance consuming,
+ // since `list' is an ArrayList so it's an O(n) operation that runs on all nodes, making
+ // this simple list.remove operation O(n*n) overall. On Android this overhead is very
+ // high.
+ // For future reference, the code to remove duplicate is a simple : list.remove(node);
+ list.add(ptNodeArray);
+ final ArrayList<PtNode> branches = ptNodeArray.mData;
+ final int nodeSize = branches.size();
+ for (PtNode ptNode : branches) {
+ if (null != ptNode.mChildren) flattenTreeInner(list, ptNode.mChildren);
+ }
+ return list;
+ }
+
+ /**
+ * Get the offset from a position inside a current node array to a target node array, during
+ * update.
+ *
+ * If the current node array is before the target node array, the target node array has not
+ * been updated yet, so we should return the offset from the old position of the current node
+ * array to the old position of the target node array. If on the other hand the target is
+ * before the current node array, it already has been updated, so we should return the offset
+ * from the new position in the current node array to the new position in the target node
+ * array.
+ *
+ * @param currentNodeArray node array containing the PtNode where the offset will be written
+ * @param offsetFromStartOfCurrentNodeArray offset, in bytes, from the start of currentNodeArray
+ * @param targetNodeArray the target node array to get the offset to
+ * @return the offset to the target node array
+ */
+ private static int getOffsetToTargetNodeArrayDuringUpdate(final PtNodeArray currentNodeArray,
+ final int offsetFromStartOfCurrentNodeArray, final PtNodeArray targetNodeArray) {
+ final boolean isTargetBeforeCurrent = (targetNodeArray.mCachedAddressBeforeUpdate
+ < currentNodeArray.mCachedAddressBeforeUpdate);
+ if (isTargetBeforeCurrent) {
+ return targetNodeArray.mCachedAddressAfterUpdate
+ - (currentNodeArray.mCachedAddressAfterUpdate
+ + offsetFromStartOfCurrentNodeArray);
+ } else {
+ return targetNodeArray.mCachedAddressBeforeUpdate
+ - (currentNodeArray.mCachedAddressBeforeUpdate
+ + offsetFromStartOfCurrentNodeArray);
+ }
+ }
+
+ /**
+ * Get the offset from a position inside a current node array to a target PtNode, during
+ * update.
+ *
+ * @param currentNodeArray node array containing the PtNode where the offset will be written
+ * @param offsetFromStartOfCurrentNodeArray offset, in bytes, from the start of currentNodeArray
+ * @param targetPtNode the target PtNode to get the offset to
+ * @return the offset to the target PtNode
+ */
+ // TODO: is there any way to factorize this method with the one above?
+ private static int getOffsetToTargetPtNodeDuringUpdate(final PtNodeArray currentNodeArray,
+ final int offsetFromStartOfCurrentNodeArray, final PtNode targetPtNode) {
+ final int oldOffsetBasePoint = currentNodeArray.mCachedAddressBeforeUpdate
+ + offsetFromStartOfCurrentNodeArray;
+ final boolean isTargetBeforeCurrent = (targetPtNode.mCachedAddressBeforeUpdate
+ < oldOffsetBasePoint);
+ // If the target is before the current node array, then its address has already been
+ // updated. We can use the AfterUpdate member, and compare it to our own member after
+ // update. Otherwise, the AfterUpdate member is not updated yet, so we need to use the
+ // BeforeUpdate member, and of course we have to compare this to our own address before
+ // update.
+ if (isTargetBeforeCurrent) {
+ final int newOffsetBasePoint = currentNodeArray.mCachedAddressAfterUpdate
+ + offsetFromStartOfCurrentNodeArray;
+ return targetPtNode.mCachedAddressAfterUpdate - newOffsetBasePoint;
+ } else {
+ return targetPtNode.mCachedAddressBeforeUpdate - oldOffsetBasePoint;
+ }
+ }
+
+ /**
+ * Computes the actual node array size, based on the cached addresses of the children nodes.
+ *
+ * Each node array stores its tentative address. During dictionary address computing, these
+ * are not final, but they can be used to compute the node array size (the node array size
+ * depends on the address of the children because the number of bytes necessary to store an
+ * address depends on its numeric value. The return value indicates whether the node array
+ * contents (as in, any of the addresses stored in the cache fields) have changed with
+ * respect to their previous value.
+ *
+ * @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) {
+ boolean changed = false;
+ int size = getPtNodeCountSize(ptNodeArray);
+ for (PtNode ptNode : ptNodeArray.mData) {
+ ptNode.mCachedAddressAfterUpdate = ptNodeArray.mCachedAddressAfterUpdate + size;
+ if (ptNode.mCachedAddressAfterUpdate != ptNode.mCachedAddressBeforeUpdate) {
+ changed = true;
+ }
+ int nodeSize = getNodeHeaderSize(ptNode, formatOptions);
+ if (ptNode.isTerminal()) {
+ if (formatOptions.mHasTerminalId) {
+ nodeSize += FormatSpec.PTNODE_TERMINAL_ID_SIZE;
+ } else {
+ nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE;
+ }
+ }
+ if (formatOptions.mSupportsDynamicUpdate) {
+ nodeSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
+ } else if (null != ptNode.mChildren) {
+ nodeSize += getByteSize(getOffsetToTargetNodeArrayDuringUpdate(ptNodeArray,
+ nodeSize + size, ptNode.mChildren));
+ }
+ 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;
+ }
+ return changed;
+ }
+
+ /**
+ * 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) {
+ int nodeArrayOffset = 0;
+ for (final PtNodeArray nodeArray : flatNodes) {
+ nodeArray.mCachedAddressBeforeUpdate = nodeArrayOffset;
+ int nodeCountSize = getPtNodeCountSize(nodeArray);
+ int nodeffset = 0;
+ for (final PtNode ptNode : nodeArray.mData) {
+ ptNode.mCachedAddressBeforeUpdate = ptNode.mCachedAddressAfterUpdate =
+ nodeCountSize + nodeArrayOffset + nodeffset;
+ nodeffset += ptNode.mCachedSize;
+ }
+ final int nodeSize = nodeCountSize + nodeffset
+ + (formatOptions.mSupportsDynamicUpdate
+ ? FormatSpec.FORWARD_LINK_ADDRESS_SIZE : 0);
+ nodeArrayOffset += nodeArray.mCachedSize;
+ }
+ return nodeArrayOffset;
+ }
+
+ /**
+ * Updates the cached addresses of node arrays after recomputing their new positions.
+ *
+ * @param flatNodes the list of node arrays.
+ */
+ private static void updatePtNodeArraysCachedAddresses(final ArrayList<PtNodeArray> flatNodes) {
+ for (final PtNodeArray nodeArray : flatNodes) {
+ nodeArray.mCachedAddressBeforeUpdate = nodeArray.mCachedAddressAfterUpdate;
+ for (final PtNode ptNode : nodeArray.mData) {
+ ptNode.mCachedAddressBeforeUpdate = ptNode.mCachedAddressAfterUpdate;
+ }
+ }
+ }
+
+ /**
+ * 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
+ * values so that they can be written into a file. It determines the smallest size each of the
+ * PtNode arrays can be given the addresses of its children and attributes, and store that into
+ * each PtNode.
+ * The order of the PtNode is given by the order of the array. This method makes no effort
+ * to find a good order; it only mechanically computes the size this order results in.
+ *
+ * @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) {
+ // First get the worst possible sizes and offsets
+ for (final PtNodeArray n : flatNodes) calculatePtNodeArrayMaximumSize(n, formatOptions);
+ final int offset = initializePtNodeArraysCachedAddresses(flatNodes, formatOptions);
+
+ MakedictLog.i("Compressing the array addresses. Original size : " + offset);
+ MakedictLog.i("(Recursively seen size : " + offset + ")");
+
+ int passes = 0;
+ boolean changesDone = false;
+ do {
+ changesDone = false;
+ int ptNodeArrayStartOffset = 0;
+ for (final PtNodeArray ptNodeArray : flatNodes) {
+ ptNodeArray.mCachedAddressAfterUpdate = ptNodeArrayStartOffset;
+ final int oldNodeArraySize = ptNodeArray.mCachedSize;
+ final boolean changed =
+ computeActualPtNodeArraySize(ptNodeArray, dict, formatOptions);
+ final int newNodeArraySize = ptNodeArray.mCachedSize;
+ if (oldNodeArraySize < newNodeArraySize) {
+ throw new RuntimeException("Increased size ?!");
+ }
+ ptNodeArrayStartOffset += newNodeArraySize;
+ changesDone |= changed;
+ }
+ updatePtNodeArraysCachedAddresses(flatNodes);
+ ++passes;
+ 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 : "
+ + (lastPtNodeArray.mCachedAddressAfterUpdate + lastPtNodeArray.mCachedSize));
+
+ return flatNodes;
+ }
+
+ /**
+ * Sanity-checking method.
+ *
+ * This method checks a list of PtNode arrays for juxtaposition, that is, it will do
+ * nothing if each node array's cached address is actually the previous node array's address
+ * plus the previous node's size.
+ * If this is not the case, it will throw an exception.
+ *
+ * @param arrays the list of node arrays to check
+ */
+ /* package */ static void checkFlatPtNodeArrayList(final ArrayList<PtNodeArray> arrays) {
+ int offset = 0;
+ int index = 0;
+ for (final PtNodeArray ptNodeArray : arrays) {
+ // BeforeUpdate and AfterUpdate addresses are the same here, so it does not matter
+ // which we use.
+ if (ptNodeArray.mCachedAddressAfterUpdate != offset) {
+ throw new RuntimeException("Wrong address for node " + index
+ + " : expected " + offset + ", got " +
+ ptNodeArray.mCachedAddressAfterUpdate);
+ }
+ ++index;
+ offset += ptNodeArray.mCachedSize;
+ }
+ }
+
+ /**
+ * Helper method to write a children position to a file.
+ *
+ * @param buffer the buffer to write to.
+ * @param index the index in the buffer to write the address to.
+ * @param position the position to write.
+ * @return the size in bytes the address actually took.
+ */
+ /* package */ static int writeChildrenPosition(final byte[] buffer, int index,
+ final int position) {
+ switch (getByteSize(position)) {
+ case 1:
+ buffer[index++] = (byte)position;
+ return 1;
+ case 2:
+ buffer[index++] = (byte)(0xFF & (position >> 8));
+ buffer[index++] = (byte)(0xFF & position);
+ return 2;
+ case 3:
+ buffer[index++] = (byte)(0xFF & (position >> 16));
+ buffer[index++] = (byte)(0xFF & (position >> 8));
+ buffer[index++] = (byte)(0xFF & position);
+ return 3;
+ case 0:
+ return 0;
+ default:
+ throw new RuntimeException("Position " + position + " has a strange size");
+ }
+ }
+
+ /**
+ * Helper method to write a signed children position to a file.
+ *
+ * @param buffer the buffer to write to.
+ * @param index the index in the buffer to write the address to.
+ * @param position the position to write.
+ * @return the size in bytes the address actually took.
+ */
+ /* package */ static int writeSignedChildrenPosition(final byte[] buffer, int index,
+ final int position) {
+ if (!BinaryDictIOUtils.hasChildrenAddress(position)) {
+ buffer[index] = buffer[index + 1] = buffer[index + 2] = 0;
+ } else {
+ final int absPosition = Math.abs(position);
+ buffer[index++] =
+ (byte)((position < 0 ? FormatSpec.MSB8 : 0) | (0xFF & (absPosition >> 16)));
+ buffer[index++] = (byte)(0xFF & (absPosition >> 8));
+ buffer[index++] = (byte)(0xFF & absPosition);
+ }
+ return 3;
+ }
+
+ /**
+ * Makes the flag value for a PtNode.
+ *
+ * @param hasMultipleChars whether the PtNode has multiple chars.
+ * @param isTerminal whether the PtNode is terminal.
+ * @param childrenAddressSize the size of a children address.
+ * @param hasShortcuts whether the PtNode has shortcuts.
+ * @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) {
+ 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");
+ }
+ }
+ if (hasShortcuts) flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS;
+ if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS;
+ if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
+ if (isBlackListEntry) flags |= FormatSpec.FLAG_IS_BLACKLISTED;
+ return flags;
+ }
+
+ /* package */ static byte makePtNodeFlags(final PtNode node, final int ptNodeAddress,
+ final int childrenOffset, final FormatOptions formatOptions) {
+ return (byte) makePtNodeFlags(node.mChars.length > 1, node.mFrequency >= 0,
+ getByteSize(childrenOffset),
+ node.mShortcutTargets != null && !node.mShortcutTargets.isEmpty(),
+ node.mBigrams != null, node.mIsNotAWord, node.mIsBlacklistEntry, formatOptions);
+ }
+
+ /**
+ * Makes the flag value for a bigram.
+ *
+ * @param more whether there are more bigrams after this one.
+ * @param offset the offset of the bigram.
+ * @param bigramFrequency the frequency of the bigram, 0..255.
+ * @param unigramFrequency the unigram frequency of the same word, 0..255.
+ * @param word the second bigram, for debugging purposes
+ * @return the flags
+ */
+ /* package */ static final int makeBigramFlags(final boolean more, final int offset,
+ int bigramFrequency, final int unigramFrequency, final String word) {
+ int bigramFlags = (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
+ + (offset < 0 ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0);
+ switch (getByteSize(offset)) {
+ 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;
+ default:
+ throw new RuntimeException("Strange offset size");
+ }
+ if (unigramFrequency > bigramFrequency) {
+ MakedictLog.e("Unigram freq is superior to bigram freq for \"" + word
+ + "\". Bigram freq is " + bigramFrequency + ", unigram freq for "
+ + word + " is " + unigramFrequency);
+ bigramFrequency = unigramFrequency;
+ }
+ // 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
+ // represents an increase of 16 steps: a value of 15 will be interpreted as the median
+ // value of the 16th step. In all justice, if the bigram frequency is low enough to be
+ // rounded below the first step (which means it is less than half a step higher than the
+ // unigram frequency) then the unigram frequency itself is the best approximation of the
+ // bigram freq that we could possibly supply, hence we should *not* include this bigram
+ // in the file at all.
+ // until this is done, we'll write 0 and slightly overestimate this case.
+ // In other words, 0 means "between 0.5 step and 1.5 step", 1 means "between 1.5 step
+ // and 2.5 steps", and 15 means "between 15.5 steps and 16.5 steps". So we want to
+ // divide our range [unigramFreq..MAX_TERMINAL_FREQUENCY] in 16.5 steps to get the
+ // step size. Then we compute the start of the first step (the one where value 0 starts)
+ // by adding half-a-step to the unigramFrequency. From there, we compute the integer
+ // number of steps to the bigramFrequency. One last thing: we want our steps to include
+ // their lower bound and exclude their higher bound so we need to have the first step
+ // start at exactly 1 unit higher than floor(unigramFreq + half a step).
+ // Note : to reconstruct the score, the dictionary reader will need to divide
+ // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise to get the value of the step,
+ // and add (discretizedFrequency + 0.5 + 0.5) times this value to get the best
+ // approximation. (0.5 to get the first step start, and 0.5 to get the middle of the
+ // step pointed by the discretized frequency.
+ final float stepSize =
+ (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency)
+ / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY);
+ final float firstStepStart = 1 + unigramFrequency + (stepSize / 2.0f);
+ final int discretizedFrequency = (int)((bigramFrequency - firstStepStart) / stepSize);
+ // If the bigram freq is less than half-a-step higher than the unigram freq, we get -1
+ // here. The best approximation would be the unigram freq itself, so we should not
+ // 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);
+ }
+
+ /**
+ * Makes the flag value for a shortcut.
+ *
+ * @param more whether there are more attributes after this one.
+ * @param frequency the frequency of the attribute, 0..15
+ * @return the flags
+ */
+ static final int makeShortcutFlags(final boolean more, final int frequency) {
+ return (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
+ + (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) {
+ int positionOfChildrenPosField = ptNode.mCachedAddressAfterUpdate
+ + getNodeHeaderSize(ptNode, formatOptions);
+ if (ptNode.isTerminal()) {
+ // A terminal node has either the terminal id or 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;
+ }
+ }
+ return null == ptNode.mChildren ? FormatSpec.NO_CHILDREN_ADDRESS
+ : ptNode.mChildren.mCachedAddressAfterUpdate - positionOfChildrenPosField;
+ }
+
+ /**
+ * Write a PtNodeArray. The PtNodeArray is expected to have its final position cached.
+ *
+ * @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) {
+ // TODO: Make the code in common with BinaryDictIOUtils#writePtNode
+ dictEncoder.setPosition(ptNodeArray.mCachedAddressAfterUpdate);
+
+ final int ptNodeCount = ptNodeArray.mData.size();
+ dictEncoder.writePtNodeCount(ptNodeCount);
+ final int parentPosition =
+ (ptNodeArray.mCachedParentAddress == FormatSpec.NO_PARENT_ADDRESS)
+ ? FormatSpec.NO_PARENT_ADDRESS
+ : ptNodeArray.mCachedParentAddress + ptNodeArray.mCachedAddressAfterUpdate;
+ for (int i = 0; i < ptNodeCount; ++i) {
+ final PtNode ptNode = ptNodeArray.mData.get(i);
+ if (dictEncoder.getPosition() != ptNode.mCachedAddressAfterUpdate) {
+ throw new RuntimeException("Bug: write index is not the same as the cached address "
+ + "of the node : " + dictEncoder.getPosition() + " <> "
+ + ptNode.mCachedAddressAfterUpdate);
+ }
+ // Sanity checks.
+ if (DBG && ptNode.mFrequency > FormatSpec.MAX_TERMINAL_FREQUENCY) {
+ throw new RuntimeException("A node has a frequency > "
+ + FormatSpec.MAX_TERMINAL_FREQUENCY
+ + " : " + ptNode.mFrequency);
+ }
+ dictEncoder.writePtNode(ptNode, parentPosition, formatOptions, dict);
+ }
+ if (formatOptions.mSupportsDynamicUpdate) {
+ dictEncoder.writeForwardLinkAddress(FormatSpec.NO_FORWARD_LINK_ADDRESS);
+ }
+ if (dictEncoder.getPosition() != ptNodeArray.mCachedAddressAfterUpdate
+ + ptNodeArray.mCachedSize) {
+ throw new RuntimeException("Not the same size : written "
+ + (dictEncoder.getPosition() - ptNodeArray.mCachedAddressAfterUpdate)
+ + " bytes from a node that should have " + ptNodeArray.mCachedSize + " bytes");
+ }
+ }
+
+ /**
+ * Dumps a collection of useful statistics about a list of PtNode arrays.
+ *
+ * This prints purely informative stuff, like the total estimated file size, the
+ * number of PtNode arrays, of PtNodes, the repartition of each address size, etc
+ *
+ * @param ptNodeArrays the list of PtNode arrays.
+ */
+ /* package */ static void showStatistics(ArrayList<PtNodeArray> ptNodeArrays) {
+ int firstTerminalAddress = Integer.MAX_VALUE;
+ int lastTerminalAddress = Integer.MIN_VALUE;
+ int size = 0;
+ int ptNodes = 0;
+ int maxNodes = 0;
+ int maxRuns = 0;
+ for (final PtNodeArray ptNodeArray : ptNodeArrays) {
+ if (maxNodes < ptNodeArray.mData.size()) maxNodes = ptNodeArray.mData.size();
+ for (final PtNode ptNode : ptNodeArray.mData) {
+ ++ptNodes;
+ if (ptNode.mChars.length > maxRuns) maxRuns = ptNode.mChars.length;
+ if (ptNode.mFrequency >= 0) {
+ if (ptNodeArray.mCachedAddressAfterUpdate < firstTerminalAddress)
+ firstTerminalAddress = ptNodeArray.mCachedAddressAfterUpdate;
+ if (ptNodeArray.mCachedAddressAfterUpdate > lastTerminalAddress)
+ lastTerminalAddress = ptNodeArray.mCachedAddressAfterUpdate;
+ }
+ }
+ if (ptNodeArray.mCachedAddressAfterUpdate + ptNodeArray.mCachedSize > size) {
+ size = ptNodeArray.mCachedAddressAfterUpdate + ptNodeArray.mCachedSize;
+ }
+ }
+ final int[] ptNodeCounts = new int[maxNodes + 1];
+ final int[] runCounts = new int[maxRuns + 1];
+ for (final PtNodeArray ptNodeArray : ptNodeArrays) {
+ ++ptNodeCounts[ptNodeArray.mData.size()];
+ for (final PtNode ptNode : ptNodeArray.mData) {
+ ++runCounts[ptNode.mChars.length];
+ }
+ }
+
+ MakedictLog.i("Statistics:\n"
+ + " total file size " + size + "\n"
+ + " " + ptNodeArrays.size() + " node arrays\n"
+ + " " + ptNodes + " PtNodes (" + ((float)ptNodes / ptNodeArrays.size())
+ + " PtNodes per node)\n"
+ + " first terminal at " + firstTerminalAddress + "\n"
+ + " last terminal at " + lastTerminalAddress + "\n"
+ + " PtNode stats : max = " + maxNodes);
+ for (int i = 0; i < ptNodeCounts.length; ++i) {
+ MakedictLog.i(" " + i + " : " + ptNodeCounts[i]);
+ }
+ MakedictLog.i(" Character run stats : max = " + maxRuns);
+ for (int i = 0; i < runCounts.length; ++i) {
+ MakedictLog.i(" " + i + " : " + runCounts[i]);
+ }
+ }
+
+ /**
+ * Writes a file header to an output stream.
+ *
+ * @param destination the stream to write the file header to.
+ * @param dict the dictionary to write.
+ * @param formatOptions file format options.
+ * @return the size of the header.
+ */
+ /* package */ static int writeDictionaryHeader(final OutputStream destination,
+ final FusionDictionary dict, final FormatOptions formatOptions)
+ throws IOException, UnsupportedFormatException {
+ final int version = formatOptions.mVersion;
+ if (version < FormatSpec.MINIMUM_SUPPORTED_VERSION
+ || version > FormatSpec.MAXIMUM_SUPPORTED_VERSION) {
+ throw new UnsupportedFormatException("Requested file format version " + version
+ + ", but this implementation only supports versions "
+ + FormatSpec.MINIMUM_SUPPORTED_VERSION + " through "
+ + FormatSpec.MAXIMUM_SUPPORTED_VERSION);
+ }
+
+ ByteArrayOutputStream headerBuffer = new ByteArrayOutputStream(256);
+
+ // The magic number in big-endian order.
+ // Magic number for all versions.
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 24)));
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 16)));
+ headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 8)));
+ headerBuffer.write((byte) (0xFF & FormatSpec.MAGIC_NUMBER));
+ // Dictionary version.
+ headerBuffer.write((byte) (0xFF & (version >> 8)));
+ headerBuffer.write((byte) (0xFF & version));
+
+ // Options flags
+ final int options = makeOptionsValue(dict, formatOptions);
+ headerBuffer.write((byte) (0xFF & (options >> 8)));
+ headerBuffer.write((byte) (0xFF & options));
+ final int headerSizeOffset = headerBuffer.size();
+ // Placeholder to be written later with header size.
+ for (int i = 0; i < 4; ++i) {
+ headerBuffer.write(0);
+ }
+ // Write out the options.
+ for (final String key : dict.mOptions.mAttributes.keySet()) {
+ final String value = dict.mOptions.mAttributes.get(key);
+ CharEncoding.writeString(headerBuffer, key);
+ CharEncoding.writeString(headerBuffer, value);
+ }
+ final int size = headerBuffer.size();
+ final byte[] bytes = headerBuffer.toByteArray();
+ // Write out the header size.
+ bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
+ bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
+ bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
+ bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
+ destination.write(bytes);
+
+ headerBuffer.close();
+ return size;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
index c013013e6..a282f595c 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java
@@ -18,19 +18,19 @@ package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.CharEncoding;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
+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.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.utils.ByteArrayDictBuffer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
-import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
@@ -44,26 +44,26 @@ public final class BinaryDictIOUtils {
}
private static final class Position {
- public static final int NOT_READ_GROUPCOUNT = -1;
+ public static final int NOT_READ_PTNODE_COUNT = -1;
public int mAddress;
- public int mNumOfCharGroup;
+ public int mNumOfPtNode;
public int mPosition;
public int mLength;
public Position(int address, int length) {
mAddress = address;
mLength = length;
- mNumOfCharGroup = NOT_READ_GROUPCOUNT;
+ mNumOfPtNode = NOT_READ_PTNODE_COUNT;
}
}
/**
- * Tours all node without recursive call.
+ * Retrieves all node arrays without recursive call.
*/
- private static void readUnigramsAndBigramsBinaryInner(
- final FusionDictionaryBufferInterface buffer, final int headerSize,
- final Map<Integer, String> words, final Map<Integer, Integer> frequencies,
+ private static void readUnigramsAndBigramsBinaryInner(final DictDecoder dictDecoder,
+ final int headerSize, final Map<Integer, String> words,
+ final Map<Integer, Integer> frequencies,
final Map<Integer, ArrayList<PendingAttribute>> bigrams,
final FormatOptions formatOptions) {
int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1];
@@ -78,47 +78,47 @@ public final class BinaryDictIOUtils {
Position p = stack.peek();
if (DBG) {
- MakedictLog.d("read: address=" + p.mAddress + ", numOfCharGroup=" +
- p.mNumOfCharGroup + ", position=" + p.mPosition + ", length=" + p.mLength);
+ MakedictLog.d("read: address=" + p.mAddress + ", numOfPtNode=" +
+ p.mNumOfPtNode + ", position=" + p.mPosition + ", length=" + p.mLength);
}
- if (buffer.position() != p.mAddress) buffer.position(p.mAddress);
+ if (dictDecoder.getPosition() != p.mAddress) dictDecoder.setPosition(p.mAddress);
if (index != p.mLength) index = p.mLength;
- if (p.mNumOfCharGroup == Position.NOT_READ_GROUPCOUNT) {
- p.mNumOfCharGroup = BinaryDictDecoder.readCharGroupCount(buffer);
- p.mAddress += getGroupCountSize(p.mNumOfCharGroup);
+ if (p.mNumOfPtNode == Position.NOT_READ_PTNODE_COUNT) {
+ p.mNumOfPtNode = dictDecoder.readPtNodeCount();
+ p.mAddress += getPtNodeCountSize(p.mNumOfPtNode);
p.mPosition = 0;
}
- if (p.mNumOfCharGroup == 0) {
+ if (p.mNumOfPtNode == 0) {
stack.pop();
continue;
}
- CharGroupInfo info = BinaryDictDecoder.readCharGroup(buffer,
- p.mAddress - headerSize, formatOptions);
+ PtNodeInfo info = dictDecoder.readPtNode(p.mAddress, formatOptions);
for (int i = 0; i < info.mCharacters.length; ++i) {
pushedChars[index++] = info.mCharacters[i];
}
p.mPosition++;
- final boolean isMovedGroup = isMovedGroup(info.mFlags,
+ final boolean isMovedPtNode = isMovedPtNode(info.mFlags,
formatOptions);
- final boolean isDeletedGroup = isDeletedGroup(info.mFlags,
+ final boolean isDeletedPtNode = isDeletedPtNode(info.mFlags,
formatOptions);
- if (!isMovedGroup && !isDeletedGroup
- && info.mFrequency != FusionDictionary.CharGroup.NOT_A_TERMINAL) {// found word
+ if (!isMovedPtNode && !isDeletedPtNode
+ && info.mFrequency != FusionDictionary.PtNode.NOT_A_TERMINAL) {// found word
words.put(info.mOriginalAddress, new String(pushedChars, 0, index));
frequencies.put(info.mOriginalAddress, info.mFrequency);
if (info.mBigrams != null) bigrams.put(info.mOriginalAddress, info.mBigrams);
}
- if (p.mPosition == p.mNumOfCharGroup) {
+ if (p.mPosition == p.mNumOfPtNode) {
if (formatOptions.mSupportsDynamicUpdate) {
- final int forwardLinkAddress = buffer.readUnsignedInt24();
- if (forwardLinkAddress != FormatSpec.NO_FORWARD_LINK_ADDRESS) {
- // the node has a forward link.
- p.mNumOfCharGroup = Position.NOT_READ_GROUPCOUNT;
- p.mAddress = forwardLinkAddress;
+ 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();
}
@@ -126,12 +126,12 @@ public final class BinaryDictIOUtils {
stack.pop();
}
} else {
- // the node has more groups.
- p.mAddress = buffer.position();
+ // The Ptnode array has more PtNodes.
+ p.mAddress = dictDecoder.getPosition();
}
- if (!isMovedGroup && hasChildrenAddress(info.mChildrenAddress)) {
- Position childrenPos = new Position(info.mChildrenAddress + headerSize, index);
+ if (!isMovedPtNode && hasChildrenAddress(info.mChildrenAddress)) {
+ final Position childrenPos = new Position(info.mChildrenAddress, index);
stack.push(childrenPos);
}
}
@@ -139,59 +139,59 @@ public final class BinaryDictIOUtils {
/**
* Reads unigrams and bigrams from the binary file.
- * Doesn't make the memory representation of the dictionary.
+ * Doesn't store a full memory representation of the dictionary.
*
- * @param reader the reader.
+ * @param dictDecoder the dict decoder.
* @param words the map to store the address as a key and the word as a value.
* @param frequencies the map to store the address as a key and the frequency as a value.
* @param bigrams the map to store the address as a key and the list of address as a value.
- * @throws IOException
- * @throws UnsupportedFormatException
+ * @throws IOException if the file can't be read.
+ * @throws UnsupportedFormatException if the format of the file is not recognized.
*/
- public static void readUnigramsAndBigramsBinary(final BinaryDictReader reader,
+ /* package */ static void readUnigramsAndBigramsBinary(final DictDecoder dictDecoder,
final Map<Integer, String> words, final Map<Integer, Integer> frequencies,
final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException,
UnsupportedFormatException {
// Read header
- final FileHeader header = BinaryDictDecoder.readHeader(reader.getBuffer());
- readUnigramsAndBigramsBinaryInner(reader.getBuffer(), header.mHeaderSize, words,
+ final FileHeader header = dictDecoder.readHeader();
+ readUnigramsAndBigramsBinaryInner(dictDecoder, header.mHeaderSize, words,
frequencies, bigrams, header.mFormatOptions);
}
/**
- * Gets the address of the last CharGroup of the exact matching word in the dictionary.
+ * Gets the address of the last PtNode of the exact matching word in the dictionary.
* If no match is found, returns NOT_VALID_WORD.
*
- * @param buffer the buffer to read.
+ * @param dictDecoder the dict decoder.
* @param word the word we search for.
* @return the address of the terminal node.
- * @throws IOException
- * @throws UnsupportedFormatException
+ * @throws IOException if the file can't be read.
+ * @throws UnsupportedFormatException if the format of the file is not recognized.
*/
@UsedForTesting
- public static int getTerminalPosition(final FusionDictionaryBufferInterface buffer,
+ /* package */ static int getTerminalPosition(final DictDecoder dictDecoder,
final String word) throws IOException, UnsupportedFormatException {
if (word == null) return FormatSpec.NOT_VALID_WORD;
- if (buffer.position() != 0) buffer.position(0);
+ dictDecoder.setPosition(0);
- final FileHeader header = BinaryDictDecoder.readHeader(buffer);
+ final FileHeader header = dictDecoder.readHeader();
int wordPos = 0;
final int wordLen = word.codePointCount(0, word.length());
for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) {
if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD;
do {
- final int charGroupCount = BinaryDictDecoder.readCharGroupCount(buffer);
- boolean foundNextCharGroup = false;
- for (int i = 0; i < charGroupCount; ++i) {
- final int charGroupPos = buffer.position();
- final CharGroupInfo currentInfo = BinaryDictDecoder.readCharGroup(buffer,
- buffer.position(), header.mFormatOptions);
- final boolean isMovedGroup = isMovedGroup(currentInfo.mFlags,
+ final int ptNodeCount = dictDecoder.readPtNodeCount();
+ boolean foundNextPtNode = false;
+ for (int i = 0; i < ptNodeCount; ++i) {
+ final int ptNodePos = dictDecoder.getPosition();
+ final PtNodeInfo currentInfo = dictDecoder.readPtNode(ptNodePos,
header.mFormatOptions);
- final boolean isDeletedGroup = isDeletedGroup(currentInfo.mFlags,
+ final boolean isMovedNode = isMovedPtNode(currentInfo.mFlags,
header.mFormatOptions);
- if (isMovedGroup) continue;
+ final boolean isDeletedNode = isDeletedPtNode(currentInfo.mFlags,
+ header.mFormatOptions);
+ if (isMovedNode) continue;
boolean same = true;
for (int p = 0, j = word.offsetByCodePoints(0, wordPos);
p < currentInfo.mCharacters.length;
@@ -204,39 +204,39 @@ public final class BinaryDictIOUtils {
}
if (same) {
- // found the group matches the word.
+ // found the PtNode matches the word.
if (wordPos + currentInfo.mCharacters.length == wordLen) {
- if (currentInfo.mFrequency == CharGroup.NOT_A_TERMINAL
- || isDeletedGroup) {
+ if (currentInfo.mFrequency == PtNode.NOT_A_TERMINAL
+ || isDeletedNode) {
return FormatSpec.NOT_VALID_WORD;
} else {
- return charGroupPos;
+ return ptNodePos;
}
}
wordPos += currentInfo.mCharacters.length;
if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) {
return FormatSpec.NOT_VALID_WORD;
}
- foundNextCharGroup = true;
- buffer.position(currentInfo.mChildrenAddress);
+ foundNextPtNode = true;
+ dictDecoder.setPosition(currentInfo.mChildrenAddress);
break;
}
}
- // If we found the next char group, it is under the file pointer.
- // But if not, we are at the end of this node so we expect to have
+ // 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 in the linked list.
- if (foundNextCharGroup) break;
+ // search on the next node array in the linked list.
+ if (foundNextPtNode) break;
if (!header.mFormatOptions.mSupportsDynamicUpdate) {
return FormatSpec.NOT_VALID_WORD;
}
- final int forwardLinkAddress = buffer.readUnsignedInt24();
- if (forwardLinkAddress == FormatSpec.NO_FORWARD_LINK_ADDRESS) {
+ final boolean hasValidForwardLinkAddress =
+ dictDecoder.readAndFollowForwardLink();
+ if (!hasValidForwardLinkAddress || !dictDecoder.hasNextPtNodeArray()) {
return FormatSpec.NOT_VALID_WORD;
}
- buffer.position(forwardLinkAddress);
} while(true);
}
return FormatSpec.NOT_VALID_WORD;
@@ -245,12 +245,12 @@ public final class BinaryDictIOUtils {
/**
* @return the size written, in bytes. Always 3 bytes.
*/
- static int writeSInt24ToBuffer(final FusionDictionaryBufferInterface buffer,
+ static int writeSInt24ToBuffer(final DictBuffer dictBuffer,
final int value) {
final int absValue = Math.abs(value);
- buffer.put((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF));
- buffer.put((byte)((absValue >> 8) & 0xFF));
- buffer.put((byte)(absValue & 0xFF));
+ dictBuffer.put((byte)(((value < 0 ? 0x80 : 0) | (absValue >> 16)) & 0xFF));
+ dictBuffer.put((byte)((absValue >> 8) & 0xFF));
+ dictBuffer.put((byte)(absValue & 0xFF));
return 3;
}
@@ -271,7 +271,7 @@ public final class BinaryDictIOUtils {
*/
private static int writeVariableAddress(final OutputStream destination, final int value)
throws IOException {
- switch (BinaryDictEncoder.getByteSize(value)) {
+ switch (BinaryDictEncoderUtils.getByteSize(value)) {
case 1:
destination.write((byte)value);
break;
@@ -285,53 +285,52 @@ public final class BinaryDictIOUtils {
destination.write((byte)(0xFF & value));
break;
}
- return BinaryDictEncoder.getByteSize(value);
+ return BinaryDictEncoderUtils.getByteSize(value);
}
- static void skipCharGroup(final FusionDictionaryBufferInterface buffer,
- final FormatOptions formatOptions) {
- final int flags = buffer.readUnsignedByte();
- BinaryDictDecoder.readParentAddress(buffer, formatOptions);
- skipString(buffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0);
- BinaryDictDecoder.readChildrenAddress(buffer, flags, formatOptions);
- if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) buffer.readUnsignedByte();
+ static void skipPtNode(final DictBuffer dictBuffer, final FormatOptions formatOptions) {
+ final int flags = dictBuffer.readUnsignedByte();
+ BinaryDictDecoderUtils.readParentAddress(dictBuffer, formatOptions);
+ skipString(dictBuffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0);
+ BinaryDictDecoderUtils.readChildrenAddress(dictBuffer, flags, formatOptions);
+ if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) dictBuffer.readUnsignedByte();
if ((flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS) != 0) {
- final int shortcutsSize = buffer.readUnsignedShort();
- buffer.position(buffer.position() + shortcutsSize
- - FormatSpec.GROUP_SHORTCUT_LIST_SIZE_SIZE);
+ final int shortcutsSize = dictBuffer.readUnsignedShort();
+ dictBuffer.position(dictBuffer.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_GROUP) {
- final int bigramFlags = buffer.readUnsignedByte();
- switch (bigramFlags & FormatSpec.MASK_ATTRIBUTE_ADDRESS_TYPE) {
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- buffer.readUnsignedByte();
+ while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) {
+ final int bigramFlags = dictBuffer.readUnsignedByte();
+ switch (bigramFlags & FormatSpec.MASK_BIGRAM_ATTR_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE:
+ dictBuffer.readUnsignedByte();
break;
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- buffer.readUnsignedShort();
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES:
+ dictBuffer.readUnsignedShort();
break;
- case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- buffer.readUnsignedInt24();
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES:
+ dictBuffer.readUnsignedInt24();
break;
}
- if ((bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT) == 0) break;
+ if ((bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT) == 0) break;
}
- if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
- throw new RuntimeException("Too many bigrams in a group.");
+ if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) {
+ throw new RuntimeException("Too many bigrams in a PtNode.");
}
}
}
- static void skipString(final FusionDictionaryBufferInterface buffer,
+ static void skipString(final DictBuffer dictBuffer,
final boolean hasMultipleChars) {
if (hasMultipleChars) {
- int character = CharEncoding.readChar(buffer);
+ int character = CharEncoding.readChar(dictBuffer);
while (character != FormatSpec.INVALID_CHARACTER) {
- character = CharEncoding.readChar(buffer);
+ character = CharEncoding.readChar(dictBuffer);
}
} else {
- CharEncoding.readChar(buffer);
+ CharEncoding.readChar(dictBuffer);
}
}
@@ -359,23 +358,24 @@ public final class BinaryDictIOUtils {
size += 3;
}
}
- destination.write((byte)FormatSpec.GROUP_CHARACTERS_TERMINATOR);
- size += FormatSpec.GROUP_TERMINATOR_SIZE;
+ destination.write((byte)FormatSpec.PTNODE_CHARACTERS_TERMINATOR);
+ size += FormatSpec.PTNODE_TERMINATOR_SIZE;
return size;
}
/**
- * Write a char group to an output stream.
- * A char group is an in-memory representation of a node in trie.
- * A char group info is an on-disk representation of a node.
+ * 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 char group info to be written.
+ * @param info the PtNode info to be written.
* @return the size written, in bytes.
*/
- public static int writeCharGroup(final OutputStream destination, final CharGroupInfo info)
+ private static int writePtNode(final OutputStream destination, final PtNodeInfo info)
throws IOException {
- int size = FormatSpec.GROUP_FLAGS_SIZE;
+ 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;
@@ -390,7 +390,7 @@ public final class BinaryDictIOUtils {
}
}
if (info.mCharacters.length > 1) {
- destination.write((byte)FormatSpec.GROUP_CHARACTERS_TERMINATOR);
+ destination.write((byte)FormatSpec.PTNODE_CHARACTERS_TERMINATOR);
size++;
}
@@ -400,7 +400,7 @@ public final class BinaryDictIOUtils {
}
if (DBG) {
- MakedictLog.d("writeCharGroup origin=" + info.mOriginalAddress + ", size=" + size
+ MakedictLog.d("writePtNode origin=" + info.mOriginalAddress + ", size=" + size
+ ", child=" + info.mChildrenAddress + ", characters ="
+ new String(info.mCharacters, 0, info.mCharacters.length));
}
@@ -411,14 +411,14 @@ public final class BinaryDictIOUtils {
if (info.mShortcutTargets != null && info.mShortcutTargets.size() > 0) {
final int shortcutListSize =
- BinaryDictEncoder.getShortcutListSize(info.mShortcutTargets);
+ 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)BinaryDictEncoder.makeShortcutFlags(
+ destination.write((byte)BinaryDictEncoderUtils.makeShortcutFlags(
shortcutIterator.hasNext(), target.mFrequency));
size++;
size += writeString(destination, target.mWord);
@@ -427,28 +427,28 @@ public final class BinaryDictIOUtils {
if (info.mBigrams != null) {
// TODO: Consolidate this code with the code that computes the size of the bigram list
- // in BinaryDictEncoder#computeActualNodeSize
+ // 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_ATTRIBUTE_HAS_NEXT : 0;
+ ? 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_ATTRIBUTE_OFFSET_NEGATIVE : 0;
- switch (BinaryDictEncoder.getByteSize(bigramOffset)) {
+ bigramFlags |= (bigramOffset < 0) ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0;
+ switch (BinaryDictEncoderUtils.getByteSize(bigramOffset)) {
case 1:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
+ bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE;
break;
case 2:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
+ bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES;
break;
case 3:
- bigramFlags |= FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+ bigramFlags |= FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES;
break;
}
- bigramFlags |= bigramFrequency & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY;
+ bigramFlags |= bigramFrequency & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY;
destination.write((byte)bigramFlags);
size += writeVariableAddress(destination, Math.abs(bigramOffset));
}
@@ -457,39 +457,39 @@ public final class BinaryDictIOUtils {
}
/**
- * Compute the size of the char group.
+ * Compute the size of the PtNode.
*/
- static int computeGroupSize(final CharGroupInfo info, final FormatOptions formatOptions) {
- int size = FormatSpec.GROUP_FLAGS_SIZE + FormatSpec.PARENT_ADDRESS_SIZE
- + BinaryDictEncoder.getGroupCharactersSize(info.mCharacters)
+ 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.GROUP_FREQUENCY_SIZE;
+ size += FormatSpec.PTNODE_FREQUENCY_SIZE;
}
if (info.mShortcutTargets != null && !info.mShortcutTargets.isEmpty()) {
- size += BinaryDictEncoder.getShortcutListSize(info.mShortcutTargets);
+ size += BinaryDictEncoderUtils.getShortcutListSize(info.mShortcutTargets);
}
if (info.mBigrams != null) {
for (final PendingAttribute attr : info.mBigrams) {
- size += FormatSpec.GROUP_FLAGS_SIZE;
- size += BinaryDictEncoder.getByteSize(attr.mAddress);
+ size += FormatSpec.PTNODE_FLAGS_SIZE;
+ size += BinaryDictEncoderUtils.getByteSize(attr.mAddress);
}
}
return size;
}
/**
- * Write a node to the stream.
+ * Write a node array to the stream.
*
* @param destination the stream to write.
- * @param infos groups to be written.
+ * @param infos an array of PtNodeInfo to be written.
* @return the size written, in bytes.
* @throws IOException
*/
- static int writeNode(final OutputStream destination, final CharGroupInfo[] infos)
+ static int writeNodes(final OutputStream destination, final PtNodeInfo[] infos)
throws IOException {
- int size = getGroupCountSize(infos.length);
- switch (getGroupCountSize(infos.length)) {
+ int size = getPtNodeCountSize(infos.length);
+ switch (getPtNodeCountSize(infos.length)) {
case 1:
destination.write((byte)infos.length);
break;
@@ -498,35 +498,13 @@ public final class BinaryDictIOUtils {
destination.write((byte)(infos.length & 0xFF));
break;
default:
- throw new RuntimeException("Invalid group count size.");
+ throw new RuntimeException("Invalid node count size.");
}
- for (final CharGroupInfo info : infos) size += writeCharGroup(destination, info);
+ for (final PtNodeInfo info : infos) size += writePtNode(destination, info);
writeSInt24ToStream(destination, FormatSpec.NO_FORWARD_LINK_ADDRESS);
return size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
}
- /**
- * Find a word from the buffer.
- *
- * @param buffer the buffer representing the body of the dictionary file.
- * @param word the word searched
- * @return the found group
- * @throws IOException
- * @throws UnsupportedFormatException
- */
- @UsedForTesting
- public static CharGroupInfo findWordFromBuffer(final FusionDictionaryBufferInterface buffer,
- final String word) throws IOException, UnsupportedFormatException {
- int position = getTerminalPosition(buffer, word);
- if (position != FormatSpec.NOT_VALID_WORD) {
- buffer.position(0);
- final FileHeader header = BinaryDictDecoder.readHeader(buffer);
- buffer.position(position);
- return BinaryDictDecoder.readCharGroup(buffer, position, header.mFormatOptions);
- }
- return null;
- }
-
private static final int HEADER_READING_BUFFER_SIZE = 16384;
/**
* Convenience method to read the header of a binary file.
@@ -537,20 +515,27 @@ public final class BinaryDictIOUtils {
* @param offset The offset in the file where to start reading the data.
* @param length The length of the data file.
*/
- public static FileHeader getDictionaryFileHeader(
+ private static FileHeader getDictionaryFileHeader(
final File file, final long offset, final long length)
throws FileNotFoundException, IOException, UnsupportedFormatException {
final byte[] buffer = new byte[HEADER_READING_BUFFER_SIZE];
- final FileInputStream inStream = new FileInputStream(file);
- try {
- inStream.read(buffer);
- final BinaryDictDecoder.ByteBufferWrapper wrapper =
- new BinaryDictDecoder.ByteBufferWrapper(inStream.getChannel().map(
- FileChannel.MapMode.READ_ONLY, offset, length));
- return BinaryDictDecoder.readHeader(wrapper);
- } finally {
- inStream.close();
- }
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file,
+ new DictDecoder.DictionaryBufferFactory() {
+ @Override
+ public DictBuffer getDictionaryBuffer(File file)
+ throws FileNotFoundException, IOException {
+ final FileInputStream inStream = new FileInputStream(file);
+ try {
+ inStream.skip(offset);
+ inStream.read(buffer);
+ return new ByteArrayDictBuffer(buffer);
+ } finally {
+ inStream.close();
+ }
+ }
+ }
+ );
+ return dictDecoder.readHeader();
}
public static FileHeader getDictionaryFileHeaderOrNull(final File file, final long offset,
@@ -573,11 +558,11 @@ public final class BinaryDictIOUtils {
}
/**
- * Helper method to check whether the group is moved.
+ * Helper method to check whether the node is moved.
*/
- public static boolean isMovedGroup(final int flags, final FormatOptions options) {
+ public static boolean isMovedPtNode(final int flags, final FormatOptions options) {
return options.mSupportsDynamicUpdate
- && ((flags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) == FormatSpec.FLAG_IS_MOVED);
+ && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_MOVED);
}
/**
@@ -589,43 +574,58 @@ public final class BinaryDictIOUtils {
}
/**
- * Helper method to check whether the group is deleted.
+ * Helper method to check whether the node is deleted.
*/
- public static boolean isDeletedGroup(final int flags, final FormatOptions formatOptions) {
+ public static boolean isDeletedPtNode(final int flags, final FormatOptions formatOptions) {
return formatOptions.mSupportsDynamicUpdate
- && ((flags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) == FormatSpec.FLAG_IS_DELETED);
+ && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_DELETED);
}
/**
- * Compute the binary size of the group count
- * @param count the group count
- * @return the size of the group count, either 1 or 2 bytes.
+ * Compute the binary size of the node count
+ * @param count the node count
+ * @return the size of the node count, either 1 or 2 bytes.
*/
- public static int getGroupCountSize(final int count) {
- if (FormatSpec.MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= count) {
+ public static int getPtNodeCountSize(final int count) {
+ if (FormatSpec.MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT >= count) {
return 1;
- } else if (FormatSpec.MAX_CHARGROUPS_IN_A_NODE >= count) {
+ } else if (FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY >= count) {
return 2;
} else {
throw new RuntimeException("Can't have more than "
- + FormatSpec.MAX_CHARGROUPS_IN_A_NODE + " groups in a node (found " + count
- + ")");
+ + FormatSpec.MAX_PTNODES_IN_A_PT_NODE_ARRAY + " PtNode in a PtNodeArray (found "
+ + count + ")");
}
}
static int getChildrenAddressSize(final int optionFlags,
final FormatOptions formatOptions) {
if (formatOptions.mSupportsDynamicUpdate) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
- switch (optionFlags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) {
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
+ switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE:
return 1;
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES:
return 2;
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES:
return 3;
- case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_NOADDRESS:
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS:
default:
return 0;
}
}
+
+ /**
+ * Calculate bigram frequency from compressed value
+ *
+ * @param unigramFrequency
+ * @param bigramFrequency compressed frequency
+ * @return approximate bigram frequency
+ */
+ public static int reconstructBigramFrequency(final int unigramFrequency,
+ final int bigramFrequency) {
+ final float stepSize = (FormatSpec.MAX_TERMINAL_FREQUENCY - unigramFrequency)
+ / (1.5f + FormatSpec.MAX_BIGRAM_FREQUENCY);
+ final float resultFreqFloat = unigramFrequency + stepSize * (bigramFrequency + 1.0f);
+ return (int)resultFreqFloat;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java
deleted file mode 100644
index f2f3c465d..000000000
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictReader.java
+++ /dev/null
@@ -1,136 +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.BinaryDictDecoder.FusionDictionaryBufferInterface;
-import com.android.inputmethod.latin.utils.ByteArrayWrapper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-
-public class BinaryDictReader {
-
- public interface FusionDictionaryBufferFactory {
- public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
- throws FileNotFoundException, IOException;
- }
-
- /**
- * Creates FusionDictionaryBuffer from a ByteBuffer
- */
- public static final class FusionDictionaryBufferFromByteBufferFactory
- implements FusionDictionaryBufferFactory {
- @Override
- public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
- throws FileNotFoundException, IOException {
- FileInputStream inStream = null;
- ByteBuffer buffer = null;
- try {
- inStream = new FileInputStream(file);
- buffer = inStream.getChannel().map(FileChannel.MapMode.READ_ONLY,
- 0, file.length());
- } finally {
- if (inStream != null) {
- inStream.close();
- }
- }
- if (buffer != null) {
- return new BinaryDictDecoder.ByteBufferWrapper(buffer);
- }
- return null;
- }
- }
-
- /**
- * Creates FusionDictionaryBuffer from a byte array
- */
- public static final class FusionDictionaryBufferFromByteArrayFactory
- implements FusionDictionaryBufferFactory {
- @Override
- public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
- throws FileNotFoundException, IOException {
- FileInputStream inStream = null;
- try {
- inStream = new FileInputStream(file);
- final byte[] array = new byte[(int) file.length()];
- inStream.read(array);
- return new ByteArrayWrapper(array);
- } finally {
- if (inStream != null) {
- inStream.close();
- }
- }
- }
- }
-
- /**
- * Creates FusionDictionaryBuffer from a RandomAccessFile.
- */
- @UsedForTesting
- public static final class FusionDictionaryBufferFromWritableByteBufferFactory
- implements FusionDictionaryBufferFactory {
- @Override
- public FusionDictionaryBufferInterface getFusionDictionaryBuffer(final File file)
- throws FileNotFoundException, IOException {
- RandomAccessFile raFile = null;
- ByteBuffer buffer = null;
- try {
- raFile = new RandomAccessFile(file, "rw");
- buffer = raFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, file.length());
- } finally {
- if (raFile != null) {
- raFile.close();
- }
- }
- if (buffer != null) {
- return new BinaryDictDecoder.ByteBufferWrapper(buffer);
- }
- return null;
- }
- }
-
- private final File mDictionaryBinaryFile;
- private FusionDictionaryBufferInterface mFusionDictionaryBuffer;
-
- public BinaryDictReader(final File file) {
- mDictionaryBinaryFile = file;
- mFusionDictionaryBuffer = null;
- }
-
- public void openBuffer(final FusionDictionaryBufferFactory factory)
- throws FileNotFoundException, IOException {
- mFusionDictionaryBuffer = factory.getFusionDictionaryBuffer(mDictionaryBinaryFile);
- }
-
- public FusionDictionaryBufferInterface getBuffer() {
- return mFusionDictionaryBuffer;
- }
-
- @UsedForTesting
- public FusionDictionaryBufferInterface openAndGetBuffer(
- final FusionDictionaryBufferFactory factory)
- throws FileNotFoundException, IOException {
- openBuffer(factory);
- return getBuffer();
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
new file mode 100644
index 000000000..3796a466c
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.utils.ByteArrayDictBuffer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.TreeMap;
+
+/**
+ * The base class of binary dictionary decoders.
+ */
+public abstract class 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)));
+ return header;
+ }
+
+ /**
+ * Reads and returns the file header.
+ */
+ public abstract FileHeader readHeader() throws IOException, UnsupportedFormatException;
+
+ /**
+ * Reads PtNode from nodeAddress.
+ * @param ptNodePos the position of PtNode.
+ * @param formatOptions the format options.
+ * @return PtNodeInfo.
+ */
+ public abstract PtNodeInfo readPtNode(final int ptNodePos, final FormatOptions formatOptions);
+
+ /**
+ * 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 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.
+ */
+ @UsedForTesting
+ public abstract FusionDictionary readDictionaryBinary(final FusionDictionary dict,
+ final boolean deleteDictIfBroken)
+ throws FileNotFoundException, IOException, UnsupportedFormatException;
+
+ /**
+ * Gets the address of the last PtNode of the exact matching word in the dictionary.
+ * If no match is found, returns NOT_VALID_WORD.
+ *
+ * @param word the word we search for.
+ * @return the address of the terminal node.
+ * @throws IOException if the file can't be read.
+ * @throws UnsupportedFormatException if the format of the file is not recognized.
+ */
+ @UsedForTesting
+ public int getTerminalPosition(final String word)
+ throws IOException, UnsupportedFormatException {
+ if (!isDictBufferOpen()) {
+ openDictBuffer();
+ }
+ return BinaryDictIOUtils.getTerminalPosition(this, word);
+ }
+
+ /**
+ * Reads unigrams and bigrams from the binary file.
+ * Doesn't store a full memory representation of the dictionary.
+ *
+ * @param words the map to store the address as a key and the word as a value.
+ * @param frequencies the map to store the address as a key and the frequency as a value.
+ * @param bigrams the map to store the address as a key and the list of address as a value.
+ * @throws IOException if the file can't be read.
+ * @throws UnsupportedFormatException if the format of the file is not recognized.
+ */
+ @UsedForTesting
+ public void readUnigramsAndBigramsBinary(final TreeMap<Integer, String> words,
+ final TreeMap<Integer, Integer> frequencies,
+ final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams)
+ throws IOException, UnsupportedFormatException {
+ if (!isDictBufferOpen()) {
+ openDictBuffer();
+ }
+ BinaryDictIOUtils.readUnigramsAndBigramsBinary(this, words, frequencies, bigrams);
+ }
+
+ /**
+ * Sets the position of the buffer to the given value.
+ *
+ * @param newPos the new position
+ */
+ public abstract void setPosition(final int newPos);
+
+ /**
+ * Gets the position of the buffer.
+ *
+ * @return the position
+ */
+ public abstract int getPosition();
+
+ /**
+ * Reads and returns the PtNode count out of a buffer and forwards the pointer.
+ */
+ public abstract int readPtNodeCount();
+
+ /**
+ * Reads the forward link and advances the position.
+ *
+ * @return true if this method moves the file pointer, false otherwise.
+ */
+ public abstract boolean readAndFollowForwardLink();
+ public abstract boolean hasNextPtNodeArray();
+
+ /**
+ * Opens the dictionary file and makes DictBuffer.
+ */
+ @UsedForTesting
+ public abstract void openDictBuffer() throws FileNotFoundException, IOException;
+ @UsedForTesting
+ public abstract boolean isDictBufferOpen();
+
+ // Constants for DictionaryBufferFactory.
+ public static final int USE_READONLY_BYTEBUFFER = 0x01000000;
+ public static final int USE_BYTEARRAY = 0x02000000;
+ public static final int USE_WRITABLE_BYTEBUFFER = 0x03000000;
+ public static final int MASK_DICTBUFFER = 0x0F000000;
+
+ public interface DictionaryBufferFactory {
+ public DictBuffer getDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException;
+ }
+
+ /**
+ * Creates DictionaryBuffer using a ByteBuffer
+ *
+ * This class uses less memory than DictionaryBufferFromByteArrayFactory,
+ * but doesn't perform as fast.
+ * When operating on a big dictionary, this class is preferred.
+ */
+ public static final class DictionaryBufferFromReadOnlyByteBufferFactory
+ implements DictionaryBufferFactory {
+ @Override
+ public DictBuffer getDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException {
+ FileInputStream inStream = null;
+ ByteBuffer buffer = null;
+ try {
+ inStream = new FileInputStream(file);
+ buffer = inStream.getChannel().map(FileChannel.MapMode.READ_ONLY,
+ 0, file.length());
+ } finally {
+ if (inStream != null) {
+ inStream.close();
+ }
+ }
+ if (buffer != null) {
+ return new BinaryDictDecoderUtils.ByteBufferDictBuffer(buffer);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Creates DictionaryBuffer using a byte array
+ *
+ * This class performs faster than other classes, but consumes more memory.
+ * When operating on a small dictionary, this class is preferred.
+ */
+ public static final class DictionaryBufferFromByteArrayFactory
+ implements DictionaryBufferFactory {
+ @Override
+ public DictBuffer getDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException {
+ FileInputStream inStream = null;
+ try {
+ inStream = new FileInputStream(file);
+ final byte[] array = new byte[(int) file.length()];
+ inStream.read(array);
+ return new ByteArrayDictBuffer(array);
+ } finally {
+ if (inStream != null) {
+ inStream.close();
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates DictionaryBuffer using a writable ByteBuffer and a RandomAccessFile.
+ *
+ * This class doesn't perform as fast as other classes,
+ * but this class is the only option available for destructive operations (insert or delete)
+ * on a dictionary.
+ */
+ @UsedForTesting
+ public static final class DictionaryBufferFromWritableByteBufferFactory
+ implements DictionaryBufferFactory {
+ @Override
+ public DictBuffer getDictionaryBuffer(final File file)
+ throws FileNotFoundException, IOException {
+ RandomAccessFile raFile = null;
+ ByteBuffer buffer = null;
+ try {
+ raFile = new RandomAccessFile(file, "rw");
+ buffer = raFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, file.length());
+ } finally {
+ if (raFile != null) {
+ raFile.close();
+ }
+ }
+ if (buffer != null) {
+ return new BinaryDictDecoderUtils.ByteBufferDictBuffer(buffer);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * A utility class for reading a file header.
+ */
+ protected static class HeaderReader {
+ protected static int readVersion(final DictBuffer dictBuffer)
+ throws IOException, UnsupportedFormatException {
+ return BinaryDictDecoderUtils.checkFormatVersion(dictBuffer);
+ }
+
+ protected static int readOptionFlags(final DictBuffer dictBuffer) {
+ return dictBuffer.readUnsignedShort();
+ }
+
+ protected static int readHeaderSize(final DictBuffer dictBuffer) {
+ return dictBuffer.readInt();
+ }
+
+ protected static HashMap<String, String> readAttributes(final DictBuffer dictBuffer,
+ final int headerSize) {
+ final HashMap<String, String> attributes = new HashMap<String, String>();
+ while (dictBuffer.position() < headerSize) {
+ // We can avoid an infinite loop here since dictBuffer.position() is always
+ // increased by calling CharEncoding.readString.
+ final String key = CharEncoding.readString(dictBuffer);
+ final String value = CharEncoding.readString(dictBuffer);
+ attributes.put(key, value);
+ }
+ dictBuffer.position(headerSize);
+ return attributes;
+ }
+ }
+
+ /**
+ * A utility class for reading a PtNode.
+ */
+ protected static class PtNodeReader {
+ protected static int readPtNodeOptionFlags(final DictBuffer dictBuffer) {
+ return dictBuffer.readUnsignedByte();
+ }
+
+ protected static int readParentAddress(final DictBuffer dictBuffer,
+ final FormatOptions formatOptions) {
+ if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
+ return BinaryDictDecoderUtils.readSInt24(dictBuffer);
+ } else {
+ return FormatSpec.NO_PARENT_ADDRESS;
+ }
+ }
+
+ protected static int readChildrenAddress(final DictBuffer dictBuffer, final int optionFlags,
+ final FormatOptions formatOptions) {
+ if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
+ final int address = BinaryDictDecoderUtils.readSInt24(dictBuffer);
+ if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS;
+ return address;
+ } else {
+ switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE:
+ return dictBuffer.readUnsignedByte();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES:
+ return dictBuffer.readUnsignedShort();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES:
+ return dictBuffer.readUnsignedInt24();
+ case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS:
+ default:
+ return FormatSpec.NO_CHILDREN_ADDRESS;
+ }
+ }
+ }
+
+ // Reads shortcuts and returns the read length.
+ protected static int readShortcut(final DictBuffer dictBuffer,
+ final ArrayList<WeightedString> shortcutTargets) {
+ final int pointerBefore = dictBuffer.position();
+ dictBuffer.readUnsignedShort(); // skip the size
+ while (true) {
+ final int targetFlags = dictBuffer.readUnsignedByte();
+ final String word = CharEncoding.readString(dictBuffer);
+ shortcutTargets.add(new WeightedString(word,
+ targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY));
+ if (0 == (targetFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break;
+ }
+ return dictBuffer.position() - pointerBefore;
+ }
+
+ protected static int readBigramAddresses(final DictBuffer dictBuffer,
+ final ArrayList<PendingAttribute> bigrams, final int baseAddress) {
+ int readLength = 0;
+ int bigramCount = 0;
+ while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) {
+ final int bigramFlags = dictBuffer.readUnsignedByte();
+ ++readLength;
+ final int sign = 0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE)
+ ? 1 : -1;
+ int bigramAddress = baseAddress + readLength;
+ switch (bigramFlags & FormatSpec.MASK_BIGRAM_ATTR_ADDRESS_TYPE) {
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE:
+ bigramAddress += sign * dictBuffer.readUnsignedByte();
+ readLength += 1;
+ break;
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES:
+ bigramAddress += sign * dictBuffer.readUnsignedShort();
+ readLength += 2;
+ break;
+ case FormatSpec.FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES:
+ bigramAddress += sign * dictBuffer.readUnsignedInt24();
+ readLength += 3;
+ break;
+ default:
+ throw new RuntimeException("Has bigrams with no address");
+ }
+ bigrams.add(new PendingAttribute(
+ bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY,
+ bigramAddress));
+ if (0 == (bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT)) break;
+ }
+ return readLength;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
new file mode 100644
index 000000000..ea5d492d8
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+
+import java.io.IOException;
+
+/**
+ * An interface of binary dictionary encoder.
+ */
+public interface DictEncoder {
+ public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
+ throws IOException, UnsupportedFormatException;
+
+ public void setPosition(final int position);
+ 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);
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
index 4dbfcb77d..bf3d19101 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
@@ -18,7 +18,7 @@ package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
+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;
@@ -43,146 +43,152 @@ public final class DynamicBinaryDictIOUtils {
}
private static int markAsDeleted(final int flags) {
- return (flags & (~FormatSpec.MASK_GROUP_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED;
+ return (flags & (~FormatSpec.MASK_CHILDREN_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED;
}
/**
* Delete the word from the binary file.
*
- * @param buffer the buffer to write.
+ * @param dictDecoder the dict decoder.
* @param word the word we delete
* @throws IOException
* @throws UnsupportedFormatException
*/
@UsedForTesting
- public static void deleteWord(final FusionDictionaryBufferInterface buffer,
- final String word) throws IOException, UnsupportedFormatException {
- buffer.position(0);
- final FileHeader header = BinaryDictDecoder.readHeader(buffer);
- final int wordPosition = BinaryDictIOUtils.getTerminalPosition(buffer, word);
+ public static void deleteWord(final Ver3DictDecoder dictDecoder, final String word)
+ throws IOException, UnsupportedFormatException {
+ final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
+ dictBuffer.position(0);
+ final FileHeader header = dictDecoder.readHeader();
+ final int wordPosition = dictDecoder.getTerminalPosition(word);
if (wordPosition == FormatSpec.NOT_VALID_WORD) return;
- buffer.position(wordPosition);
- final int flags = buffer.readUnsignedByte();
- buffer.position(wordPosition);
- buffer.put((byte)markAsDeleted(flags));
+ dictBuffer.position(wordPosition);
+ final int flags = dictBuffer.readUnsignedByte();
+ dictBuffer.position(wordPosition);
+ dictBuffer.put((byte)markAsDeleted(flags));
}
/**
- * Update a parent address in a CharGroup that is referred to by groupOriginAddress.
+ * Update a parent address in a PtNode that is referred to by ptNodeOriginAddress.
*
- * @param buffer the buffer to write.
- * @param groupOriginAddress the address of the group.
+ * @param dictBuffer the DictBuffer to write.
+ * @param ptNodeOriginAddress the address of the PtNode.
* @param newParentAddress the absolute address of the parent.
* @param formatOptions file format options.
*/
- public static void updateParentAddress(final FusionDictionaryBufferInterface buffer,
- final int groupOriginAddress, final int newParentAddress,
+ public static void updateParentAddress(final DictBuffer dictBuffer,
+ final int ptNodeOriginAddress, final int newParentAddress,
final FormatOptions formatOptions) {
- final int originalPosition = buffer.position();
- buffer.position(groupOriginAddress);
+ 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 = buffer.readUnsignedByte();
- if (BinaryDictIOUtils.isMovedGroup(flags, formatOptions)) {
- // if the group is moved, the parent address is stored in the destination group.
- // We are guaranteed to process the destination group later, so there is no need to
+ 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.
- buffer.position(originalPosition);
+ dictBuffer.position(originalPosition);
return;
}
if (DBG) {
- MakedictLog.d("update parent address flags=" + flags + ", " + groupOriginAddress);
+ MakedictLog.d("update parent address flags=" + flags + ", " + ptNodeOriginAddress);
}
- final int parentOffset = newParentAddress - groupOriginAddress;
- BinaryDictIOUtils.writeSInt24ToBuffer(buffer, parentOffset);
- buffer.position(originalPosition);
+ final int parentOffset = newParentAddress - ptNodeOriginAddress;
+ BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, parentOffset);
+ dictBuffer.position(originalPosition);
}
/**
- * Update parent addresses in a Node that is referred to by nodeOriginAddress.
+ * Update parent addresses in a node array stored at ptNodeOriginAddress.
*
- * @param buffer the buffer to be modified.
- * @param nodeOriginAddress the address of a modified Node.
+ * @param dictBuffer the DictBuffer 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.
*/
- public static void updateParentAddresses(final FusionDictionaryBufferInterface buffer,
- final int nodeOriginAddress, final int newParentAddress,
+ public static void updateParentAddresses(final DictBuffer dictBuffer,
+ final int ptNodeOriginAddress, final int newParentAddress,
final FormatOptions formatOptions) {
- final int originalPosition = buffer.position();
- buffer.position(nodeOriginAddress);
+ final int originalPosition = dictBuffer.position();
+ dictBuffer.position(ptNodeOriginAddress);
do {
- final int count = BinaryDictDecoder.readCharGroupCount(buffer);
+ final int count = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer);
for (int i = 0; i < count; ++i) {
- updateParentAddress(buffer, buffer.position(), newParentAddress, formatOptions);
- BinaryDictIOUtils.skipCharGroup(buffer, formatOptions);
+ updateParentAddress(dictBuffer, dictBuffer.position(), newParentAddress,
+ formatOptions);
+ BinaryDictIOUtils.skipPtNode(dictBuffer, formatOptions);
}
- final int forwardLinkAddress = buffer.readUnsignedInt24();
- buffer.position(forwardLinkAddress);
+ final int forwardLinkAddress = dictBuffer.readUnsignedInt24();
+ dictBuffer.position(forwardLinkAddress);
} while (formatOptions.mSupportsDynamicUpdate
- && buffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS);
- buffer.position(originalPosition);
+ && dictBuffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS);
+ dictBuffer.position(originalPosition);
}
/**
- * Update a children address in a CharGroup that is addressed by groupOriginAddress.
+ * Update a children address in a PtNode that is addressed by ptNodeOriginAddress.
*
- * @param buffer the buffer to write.
- * @param groupOriginAddress the address of the group.
+ * @param dictBuffer the DictBuffer to write.
+ * @param ptNodeOriginAddress the address of the PtNode.
* @param newChildrenAddress the absolute address of the child.
* @param formatOptions file format options.
*/
- public static void updateChildrenAddress(final FusionDictionaryBufferInterface buffer,
- final int groupOriginAddress, final int newChildrenAddress,
+ public static void updateChildrenAddress(final DictBuffer dictBuffer,
+ final int ptNodeOriginAddress, final int newChildrenAddress,
final FormatOptions formatOptions) {
- final int originalPosition = buffer.position();
- buffer.position(groupOriginAddress);
- final int flags = buffer.readUnsignedByte();
- final int parentAddress = BinaryDictDecoder.readParentAddress(buffer, formatOptions);
- BinaryDictIOUtils.skipString(buffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0);
- if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) buffer.readUnsignedByte();
+ final int originalPosition = dictBuffer.position();
+ dictBuffer.position(ptNodeOriginAddress);
+ final int flags = dictBuffer.readUnsignedByte();
+ final int parentAddress = 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 - buffer.position();
- BinaryDictIOUtils.writeSInt24ToBuffer(buffer, childrenOffset);
- buffer.position(originalPosition);
+ ? FormatSpec.NO_CHILDREN_ADDRESS : newChildrenAddress - dictBuffer.position();
+ BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, childrenOffset);
+ dictBuffer.position(originalPosition);
}
/**
- * Helper method to move a char group to the tail of the file.
+ * Helper method to move a PtNode to the tail of the file.
*/
- private static int moveCharGroup(final OutputStream destination,
- final FusionDictionaryBufferInterface buffer, final CharGroupInfo info,
- final int nodeOriginAddress, final int oldGroupAddress,
+ private static int movePtNode(final OutputStream destination,
+ final DictBuffer dictBuffer, final PtNodeInfo info,
+ final int nodeArrayOriginAddress, final int oldNodeAddress,
final FormatOptions formatOptions) throws IOException {
- updateParentAddress(buffer, oldGroupAddress, buffer.limit() + 1, formatOptions);
- buffer.position(oldGroupAddress);
- final int currentFlags = buffer.readUnsignedByte();
- buffer.position(oldGroupAddress);
- buffer.put((byte)(FormatSpec.FLAG_IS_MOVED | (currentFlags
+ updateParentAddress(dictBuffer, 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.GROUP_FLAGS_SIZE;
- updateForwardLink(buffer, nodeOriginAddress, buffer.limit(), formatOptions);
- size += BinaryDictIOUtils.writeNode(destination, new CharGroupInfo[] { info });
+ int size = FormatSpec.PTNODE_FLAGS_SIZE;
+ updateForwardLink(dictBuffer, nodeArrayOriginAddress, dictBuffer.limit(), formatOptions);
+ size += BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { info });
return size;
}
+
@SuppressWarnings("unused")
- private static void updateForwardLink(final FusionDictionaryBufferInterface buffer,
- final int nodeOriginAddress, final int newNodeAddress,
+ private static void updateForwardLink(final DictBuffer dictBuffer,
+ final int nodeArrayOriginAddress, final int newNodeArrayAddress,
final FormatOptions formatOptions) {
- buffer.position(nodeOriginAddress);
+ dictBuffer.position(nodeArrayOriginAddress);
int jumpCount = 0;
while (jumpCount++ < MAX_JUMPS) {
- final int count = BinaryDictDecoder.readCharGroupCount(buffer);
- for (int i = 0; i < count; ++i) BinaryDictIOUtils.skipCharGroup(buffer, formatOptions);
- final int forwardLinkAddress = buffer.readUnsignedInt24();
+ final int count = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer);
+ for (int i = 0; i < count; ++i) {
+ BinaryDictIOUtils.skipPtNode(dictBuffer, formatOptions);
+ }
+ final int forwardLinkAddress = dictBuffer.readUnsignedInt24();
if (forwardLinkAddress == FormatSpec.NO_FORWARD_LINK_ADDRESS) {
- buffer.position(buffer.position() - FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
- BinaryDictIOUtils.writeSInt24ToBuffer(buffer, newNodeAddress);
+ dictBuffer.position(dictBuffer.position() - FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
+ BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeArrayAddress);
return;
}
- buffer.position(forwardLinkAddress);
+ dictBuffer.position(forwardLinkAddress);
}
if (DBG && jumpCount >= MAX_JUMPS) {
throw new RuntimeException("too many jumps, probably a bug.");
@@ -190,71 +196,74 @@ public final class DynamicBinaryDictIOUtils {
}
/**
- * Move a group that is referred to by oldGroupOrigin to the tail of the file.
- * And set the children address to the byte after the group.
+ * 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 nodeOrigin the address of the tail of the file.
- * @param characters
- * @param length
- * @param flags
- * @param frequency
- * @param parentAddress
- * @param shortcutTargets
- * @param bigrams
+ * @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 buffer the buffer representing the (constant-size) body of the file.
- * @param oldNodeOrigin
- * @param oldGroupOrigin
- * @param formatOptions
+ * @param dictBuffer the DictBuffer representing the (constant-size) body of the file.
+ * @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
+ * @throws IOException if the file can't be accessed
*/
- private static int moveGroup(final int nodeOrigin, final int[] characters, final int length,
- final int flags, final int frequency, final int parentAddress,
+ 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 FusionDictionaryBufferInterface buffer, final int oldNodeOrigin,
- final int oldGroupOrigin, final FormatOptions formatOptions) throws IOException {
+ final DictBuffer dictBuffer, final int oldPtNodeArrayOrigin,
+ final int oldPtNodeOrigin, final FormatOptions formatOptions) throws IOException {
int size = 0;
- final int newGroupOrigin = nodeOrigin + 1;
- final int[] writtenCharacters = Arrays.copyOfRange(characters, 0, length);
- final CharGroupInfo tmpInfo = new CharGroupInfo(newGroupOrigin, -1 /* endAddress */,
+ 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.computeGroupSize(tmpInfo, formatOptions);
- final CharGroupInfo newInfo = new CharGroupInfo(newGroupOrigin, newGroupOrigin + size,
+ size = BinaryDictIOUtils.computePtNodeSize(tmpInfo, formatOptions);
+ final PtNodeInfo newInfo = new PtNodeInfo(newPtNodeOrigin, newPtNodeOrigin + size,
flags, writtenCharacters, frequency, parentAddress,
- nodeOrigin + 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE, shortcutTargets,
+ fileEndAddress + 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE, shortcutTargets,
bigrams);
- moveCharGroup(destination, buffer, newInfo, oldNodeOrigin, oldGroupOrigin, formatOptions);
+ movePtNode(destination, dictBuffer, newInfo, oldPtNodeArrayOrigin, oldPtNodeOrigin,
+ formatOptions);
return 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE;
}
/**
* Insert a word into a binary dictionary.
*
- * @param buffer
- * @param destination
- * @param word
- * @param frequency
- * @param bigramStrings
- * @param shortcuts
- * @throws IOException
- * @throws UnsupportedFormatException
+ * @param dictDecoder the dict decoder.
+ * @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 FusionDictionaryBufferInterface buffer,
+ public static void insertWord(final Ver3DictDecoder dictDecoder,
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 = new ArrayList<PendingAttribute>();
+ final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
if (bigramStrings != null) {
for (final WeightedString bigram : bigramStrings) {
- int position = BinaryDictIOUtils.getTerminalPosition(buffer, bigram.mWord);
+ int position = dictDecoder.getTerminalPosition(bigram.mWord);
if (position == FormatSpec.NOT_VALID_WORD) {
// TODO: figure out what is the correct thing to do here.
} else {
@@ -268,27 +277,27 @@ public final class DynamicBinaryDictIOUtils {
final boolean hasShortcuts = shortcuts != null && !shortcuts.isEmpty();
// find the insert position of the word.
- if (buffer.position() != 0) buffer.position(0);
- final FileHeader header = BinaryDictDecoder.readHeader(buffer);
+ if (dictBuffer.position() != 0) dictBuffer.position(0);
+ final FileHeader fileHeader = dictDecoder.readHeader();
- int wordPos = 0, address = buffer.position(), nodeOriginAddress = buffer.position();
+ 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 = buffer.position();
+ nodeOriginAddress = dictBuffer.position();
int nodeParentAddress = -1;
- final int charGroupCount = BinaryDictDecoder.readCharGroupCount(buffer);
- boolean foundNextGroup = false;
+ final int ptNodeCount = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer);
+ boolean foundNextNode = false;
- for (int i = 0; i < charGroupCount; ++i) {
- address = buffer.position();
- final CharGroupInfo currentInfo = BinaryDictDecoder.readCharGroup(buffer,
- buffer.position(), header.mFormatOptions);
- final boolean isMovedGroup = BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags,
- header.mFormatOptions);
- if (isMovedGroup) continue;
+ for (int i = 0; i < ptNodeCount; ++i) {
+ address = dictBuffer.position();
+ final PtNodeInfo currentInfo = dictDecoder.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;
@@ -304,26 +313,26 @@ public final class DynamicBinaryDictIOUtils {
* after
* abc - d - ef
*/
- final int newNodeAddress = buffer.limit();
- final int flags = BinaryDictEncoder.makeCharGroupFlags(p > 1,
+ final int newNodeAddress = dictBuffer.limit();
+ final int flags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1,
isTerminal, 0, hasShortcuts, hasBigrams, false /* isNotAWord */,
- false /* isBlackListEntry */, header.mFormatOptions);
- int written = moveGroup(newNodeAddress, currentInfo.mCharacters, p, flags,
+ false /* isBlackListEntry */, fileHeader.mFormatOptions);
+ int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p, flags,
frequency, nodeParentAddress, shortcuts, bigrams, destination,
- buffer, nodeOriginAddress, address, header.mFormatOptions);
+ dictBuffer, nodeOriginAddress, address, fileHeader.mFormatOptions);
final int[] characters2 = Arrays.copyOfRange(currentInfo.mCharacters, p,
currentInfo.mCharacters.length);
if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
- updateParentAddresses(buffer, currentInfo.mChildrenAddress,
- newNodeAddress + written + 1, header.mFormatOptions);
+ updateParentAddresses(dictBuffer, currentInfo.mChildrenAddress,
+ newNodeAddress + written + 1, fileHeader.mFormatOptions);
}
- final CharGroupInfo newInfo2 = new CharGroupInfo(
+ final PtNodeInfo newInfo2 = new PtNodeInfo(
newNodeAddress + written + 1, -1 /* endAddress */,
currentInfo.mFlags, characters2, currentInfo.mFrequency,
newNodeAddress + 1, currentInfo.mChildrenAddress,
currentInfo.mShortcutTargets, currentInfo.mBigrams);
- BinaryDictIOUtils.writeNode(destination, new CharGroupInfo[] { newInfo2 });
+ BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo2 });
return;
} else if (codePoints[wordPos + p] != currentInfo.mCharacters[p]) {
if (p > 0) {
@@ -340,54 +349,54 @@ public final class DynamicBinaryDictIOUtils {
* - c
*/
- final int newNodeAddress = buffer.limit();
+ final int newNodeAddress = dictBuffer.limit();
final int childrenAddress = currentInfo.mChildrenAddress;
// move prefix
- final int prefixFlags = BinaryDictEncoder.makeCharGroupFlags(p > 1,
+ final int prefixFlags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1,
false /* isTerminal */, 0 /* childrenAddressSize*/,
false /* hasShortcut */, false /* hasBigrams */,
false /* isNotAWord */, false /* isBlackListEntry */,
- header.mFormatOptions);
- int written = moveGroup(newNodeAddress, currentInfo.mCharacters, p,
+ fileHeader.mFormatOptions);
+ int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p,
prefixFlags, -1 /* frequency */, nodeParentAddress, null, null,
- destination, buffer, nodeOriginAddress, address,
- header.mFormatOptions);
+ destination, dictBuffer, nodeOriginAddress, address,
+ fileHeader.mFormatOptions);
final int[] suffixCharacters = Arrays.copyOfRange(
currentInfo.mCharacters, p, currentInfo.mCharacters.length);
if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
- updateParentAddresses(buffer, currentInfo.mChildrenAddress,
- newNodeAddress + written + 1, header.mFormatOptions);
+ updateParentAddresses(dictBuffer, currentInfo.mChildrenAddress,
+ newNodeAddress + written + 1, fileHeader.mFormatOptions);
}
- final int suffixFlags = BinaryDictEncoder.makeCharGroupFlags(
+ 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, header.mFormatOptions);
- final CharGroupInfo suffixInfo = new CharGroupInfo(
+ 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.computeGroupSize(suffixInfo,
- header.mFormatOptions) + 1;
+ written += BinaryDictIOUtils.computePtNodeSize(suffixInfo,
+ fileHeader.mFormatOptions) + 1;
final int[] newCharacters = Arrays.copyOfRange(codePoints, wordPos + p,
codePoints.length);
- final int flags = BinaryDictEncoder.makeCharGroupFlags(
+ final int flags = BinaryDictEncoderUtils.makePtNodeFlags(
newCharacters.length > 1, isTerminal,
0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
- isNotAWord, isBlackListEntry, header.mFormatOptions);
- final CharGroupInfo newInfo = new CharGroupInfo(
+ 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.writeNode(destination,
- new CharGroupInfo[] { suffixInfo, newInfo });
+ BinaryDictIOUtils.writeNodes(destination,
+ new PtNodeInfo[] { suffixInfo, newInfo });
return;
}
matched = false;
@@ -398,25 +407,25 @@ public final class DynamicBinaryDictIOUtils {
if (matched) {
if (wordPos + currentInfo.mCharacters.length == wordLen) {
// the word exists in the dictionary.
- // only update group.
- final int newNodeAddress = buffer.limit();
+ // only update the PtNode.
+ final int newNodeAddress = dictBuffer.limit();
final boolean hasMultipleChars = currentInfo.mCharacters.length > 1;
- final int flags = BinaryDictEncoder.makeCharGroupFlags(hasMultipleChars,
+ final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars,
isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
- isNotAWord, isBlackListEntry, header.mFormatOptions);
- final CharGroupInfo newInfo = new CharGroupInfo(newNodeAddress + 1,
+ isNotAWord, isBlackListEntry, fileHeader.mFormatOptions);
+ final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1,
-1 /* endAddress */, flags, currentInfo.mCharacters, frequency,
nodeParentAddress, currentInfo.mChildrenAddress, shortcuts,
bigrams);
- moveCharGroup(destination, buffer, newInfo, nodeOriginAddress, address,
- header.mFormatOptions);
+ movePtNode(destination, dictBuffer, 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 node and link to the node from this group.
+ * make new PtNode and link to the PtNode from this PtNode.
*
* before
* ab - cd
@@ -426,32 +435,32 @@ public final class DynamicBinaryDictIOUtils {
* after
* ab - cd - e
*/
- final int newNodeAddress = buffer.limit();
- updateChildrenAddress(buffer, address, newNodeAddress,
- header.mFormatOptions);
- final int newGroupAddress = newNodeAddress + 1;
+ final int newNodeArrayAddress = dictBuffer.limit();
+ updateChildrenAddress(dictBuffer, address, newNodeArrayAddress,
+ fileHeader.mFormatOptions);
+ final int newNodeAddress = newNodeArrayAddress + 1;
final boolean hasMultipleChars = (wordLen - wordPos) > 1;
- final int flags = BinaryDictEncoder.makeCharGroupFlags(hasMultipleChars,
+ final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars,
isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
- isNotAWord, isBlackListEntry, header.mFormatOptions);
+ isNotAWord, isBlackListEntry, fileHeader.mFormatOptions);
final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen);
- final CharGroupInfo newInfo = new CharGroupInfo(newGroupAddress, -1, flags,
+ final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress, -1, flags,
characters, frequency, address, FormatSpec.NO_CHILDREN_ADDRESS,
shortcuts, bigrams);
- BinaryDictIOUtils.writeNode(destination, new CharGroupInfo[] { newInfo });
+ BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo });
return;
}
- buffer.position(currentInfo.mChildrenAddress);
- foundNextGroup = true;
+ dictBuffer.position(currentInfo.mChildrenAddress);
+ foundNextNode = true;
break;
}
}
- if (foundNextGroup) continue;
+ if (foundNextNode) continue;
// reached the end of the array.
- final int linkAddressPosition = buffer.position();
- int nextLink = buffer.readUnsignedInt24();
+ final int linkAddressPosition = dictBuffer.position();
+ int nextLink = dictBuffer.readUnsignedInt24();
if ((nextLink & FormatSpec.MSB24) != 0) {
nextLink = -(nextLink & FormatSpec.SINT24_MAX);
}
@@ -471,22 +480,22 @@ public final class DynamicBinaryDictIOUtils {
*/
// change the forward link address.
- final int newNodeAddress = buffer.limit();
- buffer.position(linkAddressPosition);
- BinaryDictIOUtils.writeSInt24ToBuffer(buffer, newNodeAddress);
+ final int newNodeAddress = dictBuffer.limit();
+ dictBuffer.position(linkAddressPosition);
+ BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeAddress);
final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen);
- final int flags = BinaryDictEncoder.makeCharGroupFlags(characters.length > 1,
+ final int flags = BinaryDictEncoderUtils.makePtNodeFlags(characters.length > 1,
isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams,
- isNotAWord, isBlackListEntry, header.mFormatOptions);
- final CharGroupInfo newInfo = new CharGroupInfo(newNodeAddress + 1,
+ isNotAWord, isBlackListEntry, fileHeader.mFormatOptions);
+ final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1,
-1 /* endAddress */, flags, characters, frequency, nodeParentAddress,
FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams);
- BinaryDictIOUtils.writeNode(destination, new CharGroupInfo[]{ newInfo });
+ BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[]{ newInfo });
return;
} else {
depth--;
- buffer.position(nextLink);
+ 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 9af66ed4c..849bff050 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -18,8 +18,11 @@ package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
+import java.io.File;
+
/**
* Dictionary File Format Specification.
*/
@@ -60,21 +63,21 @@ public final class FormatSpec {
*/
/*
- * Array of Node(FusionDictionary.Node) layout is as follows:
+ * Node array (FusionDictionary.PtNodeArray) layout is as follows:
*
- * g |
- * r | the number of groups, 1 or 2 bytes.
- * o | 1 byte = bbbbbbbb match
- * u | case 1xxxxxxx => xxxxxxx << 8 + next byte
- * p | otherwise => bbbbbbbb
- * c |
- * ount
+ * n |
+ * o | the number of PtNodes, 1 or 2 bytes.
+ * d | 1 byte = bbbbbbbb match
+ * e | case 1xxxxxxx => xxxxxxx << 8 + next byte
+ * c | otherwise => bbbbbbbb
+ * o |
+ * unt
*
- * g |
- * r | sequence of groups,
- * o | the layout of each group is described below.
- * u |
- * ps
+ * n |
+ * o | sequence of PtNodes,
+ * d | the layout of each PtNode is described below.
+ * e |
+ * s
*
* f |
* o | IF SUPPORTS_DYNAMIC_UPDATE (defined in the file header)
@@ -86,19 +89,19 @@ public final class FormatSpec {
* linkaddress
*/
- /* Node(CharGroup) layout is as follows:
+ /* Node (FusionDictionary.PtNode) layout is as follows:
* | IF !SUPPORTS_DYNAMIC_UPDATE
- * | addressType xx : mask with MASK_GROUP_ADDRESS_TYPE
- * | 2 bits, 00 = no children : FLAG_GROUP_ADDRESS_TYPE_NOADDRESS
- * f | 01 = 1 byte : FLAG_GROUP_ADDRESS_TYPE_ONEBYTE
- * l | 10 = 2 bytes : FLAG_GROUP_ADDRESS_TYPE_TWOBYTES
- * a | 11 = 3 bytes : FLAG_GROUP_ADDRESS_TYPE_THREEBYTES
+ * | 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_GROUP_ADDRESS_TYPE_THREEBYTES
- * | 01 = yes : FLAG_IS_MOVED
+ * 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
+ * | 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
@@ -112,11 +115,13 @@ public final class FormatSpec {
* 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 |
- * ddress
+ * 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.
+ * d |
+ * ress
*
* c | IF FLAG_HAS_MULTIPLE_CHARS
- * h | char, char, char, char n * (1 or 3 bytes) : use CharGroupInfo for i/o helpers
+ * h | char, char, char, char n * (1 or 3 bytes) : use PtNodeInfo for i/o helpers
* a | end 1 byte, = 0
* r | ELSE
* s | char 1 or 3 bytes
@@ -127,17 +132,23 @@ public final class FormatSpec {
* e | frequency 1 byte
* q |
*
- * c | IF 00 = FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = addressType
- * h | // nothing
- * i | ELSIF 01 = FLAG_GROUP_ADDRESS_TYPE_ONEBYTE == addressType
- * l | children address, 1 byte
- * d | ELSIF 10 = FLAG_GROUP_ADDRESS_TYPE_TWOBYTES == addressType
- * r | children address, 2 bytes
- * e | ELSE // 11 = FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = addressType
- * n | children address, 3 bytes
- * A | END
- * d
- * dress
+ * 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.
*
* | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS
* | shortcut string list
@@ -156,40 +167,43 @@ public final class FormatSpec {
* characters which should never happen anyway (and still work, but take 3 bytes).
*
* bigram address list is:
- * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_ATTRIBUTE_HAS_NEXT
- * | addressSign = 1 bit, : FLAG_ATTRIBUTE_OFFSET_NEGATIVE
+ * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT
+ * | addressSign = 1 bit, : FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE
* | 1 = must take -address, 0 = must take +address
- * | xx : mask with MASK_ATTRIBUTE_ADDRESS_TYPE
- * | addressFormat = 2 bits, 00 = unused : FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE
- * | 01 = 1 byte : FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE
- * | 10 = 2 bytes : FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES
- * | 11 = 3 bytes : FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES
- * | 4 bits : frequency : mask with FLAG_ATTRIBUTE_FREQUENCY
- * <address> | IF (01 == FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE == addressFormat)
+ * | xx : mask with MASK_BIGRAM_ATTR_ADDRESS_TYPE
+ * | addressFormat = 2 bits, 00 = unused : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE
+ * | 01 = 1 byte : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE
+ * | 10 = 2 bytes : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES
+ * | 11 = 3 bytes : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES
+ * | 4 bits : frequency : mask with FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY
+ * <address> | IF (01 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE == addressFormat)
* | read 1 byte, add top 4 bits
- * | ELSIF (10 == FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES == addressFormat)
+ * | ELSIF (10 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES == addressFormat)
* | read 2 bytes, add top 4 bits
- * | ELSE // 11 == FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES == addressFormat
+ * | ELSE // 11 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES == addressFormat
* | read 3 bytes, add top 4 bits
* | END
- * | if (FLAG_ATTRIBUTE_OFFSET_NEGATIVE) then address = -address
- * if (FLAG_ATTRIBUTE_HAS_NEXT) goto bigram_and_shortcut_address_list_is
+ * | if (FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE) then address = -address
+ * if (FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT) goto bigram_and_shortcut_address_list_is
*
* shortcut string list is:
- * <byte size> = GROUP_SHORTCUT_LIST_SIZE_SIZE bytes, big-endian: size of the list, in bytes.
- * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_ATTRIBUTE_HAS_NEXT
+ * <byte size> = PTNODE_SHORTCUT_LIST_SIZE_SIZE bytes, big-endian: size of the list, in bytes.
+ * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT
* | reserved = 3 bits, must be 0
- * | 4 bits : frequency : mask with FLAG_ATTRIBUTE_FREQUENCY
+ * | 4 bits : frequency : mask with FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY
* <shortcut> = | string of characters at the char format described above, with the terminator
* | used to signal the end of the string.
- * if (FLAG_ATTRIBUTE_HAS_NEXT goto flags
+ * if (FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT goto flags
*/
public static final int MAGIC_NUMBER = 0x9BC13AFE;
static final int MINIMUM_SUPPORTED_VERSION = 2;
- static final int MAXIMUM_SUPPORTED_VERSION = 3;
+ 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;
@@ -206,11 +220,11 @@ public final class FormatSpec {
static final int FORWARD_LINK_ADDRESS_SIZE = 3;
// These flags are used only in the static dictionary.
- static final int MASK_GROUP_ADDRESS_TYPE = 0xC0;
- static final int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00;
- static final int FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40;
- static final int FLAG_GROUP_ADDRESS_TYPE_TWOBYTES = 0x80;
- static final int FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = 0xC0;
+ static final int MASK_CHILDREN_ADDRESS_TYPE = 0xC0;
+ static final int FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS = 0x00;
+ static final int FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE = 0x40;
+ static final int FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES = 0x80;
+ static final int FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES = 0xC0;
static final int FLAG_HAS_MULTIPLE_CHARS = 0x20;
@@ -227,32 +241,42 @@ public final class FormatSpec {
static final int FLAG_IS_NOT_MOVED = 0x80 | FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE;
static final int FLAG_IS_DELETED = 0x80;
- static final int FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
- static final int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
- static final int MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30;
- static final int FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
- static final int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
- static final int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
- static final int FLAG_ATTRIBUTE_FREQUENCY = 0x0F;
+ static final int FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT = 0x80;
+ static final int FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE = 0x40;
+ static final int MASK_BIGRAM_ATTR_ADDRESS_TYPE = 0x30;
+ static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE = 0x10;
+ static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES = 0x20;
+ static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES = 0x30;
+ static final int FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY = 0x0F;
+
+ static final int PTNODE_CHARACTERS_TERMINATOR = 0x1F;
- static final int GROUP_CHARACTERS_TERMINATOR = 0x1F;
+ static final int PTNODE_TERMINATOR_SIZE = 1;
+ static final int PTNODE_FLAGS_SIZE = 1;
+ static final int PTNODE_FREQUENCY_SIZE = 1;
+ static final int PTNODE_TERMINAL_ID_SIZE = 4;
+ static final int PTNODE_MAX_ADDRESS_SIZE = 3;
+ static final int PTNODE_ATTRIBUTE_FLAGS_SIZE = 1;
+ static final int PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE = 3;
+ static final int PTNODE_SHORTCUT_LIST_SIZE_SIZE = 2;
- static final int GROUP_TERMINATOR_SIZE = 1;
- static final int GROUP_FLAGS_SIZE = 1;
- static final int GROUP_FREQUENCY_SIZE = 1;
- static final int GROUP_MAX_ADDRESS_SIZE = 3;
- static final int GROUP_ATTRIBUTE_FLAGS_SIZE = 1;
- static final int GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE = 3;
- static final int GROUP_SHORTCUT_LIST_SIZE_SIZE = 2;
+ // These values are used only by version 4 or later.
+ static final String TRIE_FILE_EXTENSION = ".trie";
+ static final String FREQ_FILE_EXTENSION = ".freq";
+ // tat = Terminal Address Table
+ static final String TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat";
+ static final int FREQUENCY_AND_FLAGS_SIZE = 2;
+ static final int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3;
static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE;
static final int NO_PARENT_ADDRESS = 0;
static final int NO_FORWARD_LINK_ADDRESS = 0;
static final int INVALID_CHARACTER = -1;
- static final int MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT = 0x7F; // 127
- static final int MAX_CHARGROUPS_IN_A_NODE = 0x7FFF; // 32767
- static final int MAX_BIGRAMS_IN_A_GROUP = 10000;
+ static final int MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT = 0x7F; // 127
+ static final int MAX_PTNODES_IN_A_PT_NODE_ARRAY = 0x7FFF; // 32767
+ static final int MAX_BIGRAMS_IN_A_PTNODE = 10000;
+ static final int MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE = 0xFFFF;
static final int MAX_TERMINAL_FREQUENCY = 255;
static final int MAX_BIGRAM_FREQUENCY = 15;
@@ -276,6 +300,7 @@ public final class FormatSpec {
public static final class FormatOptions {
public final int mVersion;
public final boolean mSupportsDynamicUpdate;
+ public final boolean mHasTerminalId;
@UsedForTesting
public FormatOptions(final int version) {
this(version, false);
@@ -289,6 +314,7 @@ public final class FormatSpec {
+ FIRST_VERSION_WITH_DYNAMIC_UPDATE + " and ulterior.");
}
mSupportsDynamicUpdate = supportsDynamicUpdate;
+ mHasTerminalId = (version >= FIRST_VERSION_WITH_TERMINAL_ID);
}
}
@@ -299,6 +325,12 @@ public final class FormatSpec {
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";
+
private static final String DICTIONARY_VERSION_ATTRIBUTE = "version";
private static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale";
private static final String DICTIONARY_ID_ATTRIBUTE = "dictionary";
@@ -333,6 +365,36 @@ public final class FormatSpec {
}
}
+ /**
+ * Returns new dictionary decoder.
+ *
+ * @param dictFile the dictionary file.
+ * @param bufferType The type of buffer, as one of USE_* in DictDecoder.
+ * @return new dictionary decoder if the dictionary file exists, otherwise null.
+ */
+ public static DictDecoder getDictDecoder(final File dictFile, final int bufferType) {
+ if (dictFile.isDirectory()) {
+ return new Ver4DictDecoder(dictFile, bufferType);
+ } else if (dictFile.isFile()) {
+ return new Ver3DictDecoder(dictFile, bufferType);
+ }
+ return null;
+ }
+
+ public static DictDecoder getDictDecoder(final File dictFile,
+ final DictionaryBufferFactory factory) {
+ if (dictFile.isDirectory()) {
+ return new Ver4DictDecoder(dictFile, factory);
+ } else if (dictFile.isFile()) {
+ return new Ver3DictDecoder(dictFile, factory);
+ }
+ return null;
+ }
+
+ public static DictDecoder getDictDecoder(final File dictFile) {
+ return getDictDecoder(dictFile, DictDecoder.USE_READONLY_BYTEBUFFER);
+ }
+
private FormatSpec() {
// This utility class is not publicly instantiable.
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 118dc22b8..be653feec 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -37,15 +37,15 @@ public final class FusionDictionary implements Iterable<Word> {
private static int CHARACTER_NOT_FOUND_INDEX = -1;
/**
- * A node of the dictionary, containing several CharGroups.
+ * A node array of the dictionary, containing several PtNodes.
*
- * A node is but an ordered array of CharGroups, which essentially contain all the
+ * A PtNodeArray is but an ordered array of PtNodes, which essentially contain all the
* real information.
* This class also contains fields to cache size and address, to help with binary
* generation.
*/
- public static final class Node {
- ArrayList<CharGroup> mData;
+ public static final class PtNodeArray {
+ ArrayList<PtNode> mData;
// To help with binary generation
int mCachedSize = Integer.MIN_VALUE;
// mCachedAddressBefore/AfterUpdate are helpers for binary dictionary generation. They
@@ -57,10 +57,10 @@ public final class FusionDictionary implements Iterable<Word> {
int mCachedAddressAfterUpdate = Integer.MIN_VALUE;
int mCachedParentAddress = 0;
- public Node() {
- mData = new ArrayList<CharGroup>();
+ public PtNodeArray() {
+ mData = new ArrayList<PtNode>();
}
- public Node(ArrayList<CharGroup> data) {
+ public PtNodeArray(ArrayList<PtNode> data) {
mData = data;
}
}
@@ -93,24 +93,26 @@ public final class FusionDictionary implements Iterable<Word> {
}
/**
- * A group of characters, with a frequency, shortcut targets, bigrams, and children.
+ * PtNode is a group of characters, with a frequency, shortcut targets, bigrams, and children
+ * (Pt means Patricia Trie).
*
- * This is the central class of the in-memory representation. A CharGroup is what can
+ * 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 CharGroup essentially represents one or several characters in the middle
- * of the trie trie; as such, it can be a terminal, and it can have children.
- * In this in-memory representation, whether the CharGroup is a terminal or not is represented
+ * 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.
*/
- public static final class CharGroup {
+ public static final class PtNode {
public 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.
- Node mChildren;
+ int mTerminalId; // NOT_A_TERMINAL == mTerminalId indicates this is not a terminal.
+ PtNodeArray mChildren;
boolean mIsNotAWord; // Only a shortcut
boolean mIsBlacklistEntry;
// mCachedSize and mCachedAddressBefore/AfterUpdate are helpers for binary dictionary
@@ -119,15 +121,16 @@ public final class FusionDictionary implements Iterable<Word> {
// same time. Updating will update the AfterUpdate value, and the code will move them
// to BeforeUpdate before the next update pass.
// The update process does not need two versions of mCachedSize.
- int mCachedSize; // The size, in bytes, of this char group.
- int mCachedAddressBeforeUpdate; // The address of this char group (before update)
- int mCachedAddressAfterUpdate; // The address of this char group (after update)
+ int mCachedSize; // The size, in bytes, of this PtNode.
+ int mCachedAddressBeforeUpdate; // The address of this PtNode (before update)
+ int mCachedAddressAfterUpdate; // The address of this PtNode (after update)
- public CharGroup(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
+ public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams, final int frequency,
final boolean isNotAWord, final boolean isBlacklistEntry) {
mChars = chars;
mFrequency = frequency;
+ mTerminalId = frequency;
mShortcutTargets = shortcutTargets;
mBigrams = bigrams;
mChildren = null;
@@ -135,9 +138,10 @@ public final class FusionDictionary implements Iterable<Word> {
mIsBlacklistEntry = isBlacklistEntry;
}
- public CharGroup(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
+ public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams, final int frequency,
- final boolean isNotAWord, final boolean isBlacklistEntry, final Node children) {
+ final boolean isNotAWord, final boolean isBlacklistEntry,
+ final PtNodeArray children) {
mChars = chars;
mFrequency = frequency;
mShortcutTargets = shortcutTargets;
@@ -147,13 +151,17 @@ public final class FusionDictionary implements Iterable<Word> {
mIsBlacklistEntry = isBlacklistEntry;
}
- public void addChild(CharGroup n) {
+ public void addChild(PtNode n) {
if (null == mChildren) {
- mChildren = new Node();
+ mChildren = new PtNodeArray();
}
mChildren.mData.add(n);
}
+ public int getTerminalId() {
+ return mTerminalId;
+ }
+
public boolean isTerminal() {
return NOT_A_TERMINAL != mFrequency;
}
@@ -244,7 +252,7 @@ public final class FusionDictionary implements Iterable<Word> {
}
/**
- * Updates the CharGroup with the given properties. Adds the shortcut and bigram lists to
+ * Updates the PtNode with the given properties. Adds the shortcut and bigram lists to
* the existing ones if any. Note: unigram, bigram, and shortcut frequencies are only
* updated if they are higher than the existing ones.
*/
@@ -344,10 +352,10 @@ public final class FusionDictionary implements Iterable<Word> {
}
public final DictionaryOptions mOptions;
- public final Node mRoot;
+ public final PtNodeArray mRootNodeArray;
- public FusionDictionary(final Node root, final DictionaryOptions options) {
- mRoot = root;
+ public FusionDictionary(final PtNodeArray rootNodeArray, final DictionaryOptions options) {
+ mRootNodeArray = rootNodeArray;
mOptions = options;
}
@@ -406,13 +414,13 @@ public final class FusionDictionary implements Iterable<Word> {
}
/**
- * Sanity check for a node.
+ * Sanity check for a PtNode array.
*
- * This method checks that all CharGroups in a node are ordered as expected.
+ * This method checks that all PtNodes in a node array are ordered as expected.
* If they are, nothing happens. If they aren't, an exception is thrown.
*/
- private void checkStack(Node node) {
- ArrayList<CharGroup> stack = node.mData;
+ private void checkStack(PtNodeArray ptNodeArray) {
+ ArrayList<PtNode> stack = ptNodeArray.mData;
int lastValue = -1;
for (int i = 0; i < stack.size(); ++i) {
int currentValue = stack.get(i).mChars[0];
@@ -431,18 +439,18 @@ public final class FusionDictionary implements Iterable<Word> {
* @param frequency the bigram frequency
*/
public void setBigram(final String word1, final String word2, final int frequency) {
- CharGroup charGroup = findWordInTree(mRoot, word1);
- if (charGroup != null) {
- final CharGroup charGroup2 = findWordInTree(mRoot, word2);
- if (charGroup2 == null) {
+ PtNode ptNode = findWordInTree(mRootNodeArray, word1);
+ if (ptNode != null) {
+ final PtNode ptNode2 = findWordInTree(mRootNodeArray, word2);
+ if (ptNode2 == null) {
add(getCodePoints(word2), 0, null, false /* isNotAWord */,
false /* isBlacklistEntry */);
- // The chargroup for the first word may have moved by the above insertion,
+ // 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 charGroup.
- charGroup = findWordInTree(mRoot, word1);
+ // a cutting point until now. In this case, we need to refresh ptNode.
+ ptNode = findWordInTree(mRootNodeArray, word1);
}
- charGroup.addBigram(word2, frequency);
+ ptNode.addBigram(word2, frequency);
} else {
throw new RuntimeException("First word of bigram not found");
}
@@ -469,92 +477,91 @@ public final class FusionDictionary implements Iterable<Word> {
return;
}
- Node currentNode = mRoot;
+ PtNodeArray currentNodeArray = mRootNodeArray;
int charIndex = 0;
- CharGroup currentGroup = null;
+ PtNode currentPtNode = null;
int differentCharIndex = 0; // Set by the loop to the index of the char that differs
- int nodeIndex = findIndexOfChar(mRoot, word[charIndex]);
+ int nodeIndex = findIndexOfChar(mRootNodeArray, word[charIndex]);
while (CHARACTER_NOT_FOUND_INDEX != nodeIndex) {
- currentGroup = currentNode.mData.get(nodeIndex);
- differentCharIndex = compareArrays(currentGroup.mChars, word, charIndex);
+ currentPtNode = currentNodeArray.mData.get(nodeIndex);
+ differentCharIndex = compareCharArrays(currentPtNode.mChars, word, charIndex);
if (ARRAYS_ARE_EQUAL != differentCharIndex
- && differentCharIndex < currentGroup.mChars.length) break;
- if (null == currentGroup.mChildren) break;
- charIndex += currentGroup.mChars.length;
+ && differentCharIndex < currentPtNode.mChars.length) break;
+ if (null == currentPtNode.mChildren) break;
+ charIndex += currentPtNode.mChars.length;
if (charIndex >= word.length) break;
- currentNode = currentGroup.mChildren;
- nodeIndex = findIndexOfChar(currentNode, word[charIndex]);
+ currentNodeArray = currentPtNode.mChildren;
+ nodeIndex = findIndexOfChar(currentNodeArray, word[charIndex]);
}
if (CHARACTER_NOT_FOUND_INDEX == nodeIndex) {
// No node at this point to accept the word. Create one.
- final int insertionIndex = findInsertionIndex(currentNode, word[charIndex]);
- final CharGroup newGroup = new CharGroup(
- Arrays.copyOfRange(word, charIndex, word.length),
+ final int insertionIndex = findInsertionIndex(currentNodeArray, word[charIndex]);
+ final PtNode newPtNode = new PtNode(Arrays.copyOfRange(word, charIndex, word.length),
shortcutTargets, null /* bigrams */, frequency, isNotAWord, isBlacklistEntry);
- currentNode.mData.add(insertionIndex, newGroup);
- if (DBG) checkStack(currentNode);
+ currentNodeArray.mData.add(insertionIndex, newPtNode);
+ if (DBG) checkStack(currentNodeArray);
} else {
// There is a word with a common prefix.
- if (differentCharIndex == currentGroup.mChars.length) {
+ if (differentCharIndex == currentPtNode.mChars.length) {
if (charIndex + differentCharIndex >= word.length) {
// 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 CharNode was not a terminal,
+ // 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
- currentGroup.update(frequency, shortcutTargets, null, isNotAWord,
+ currentPtNode.update(frequency, 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 CharGroup newNode = new CharGroup(
+ final PtNode newNode = new PtNode(
Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length),
shortcutTargets, null /* bigrams */, frequency, isNotAWord,
isBlacklistEntry);
- currentGroup.mChildren = new Node();
- currentGroup.mChildren.mData.add(newNode);
+ currentPtNode.mChildren = new PtNodeArray();
+ currentPtNode.mChildren.mData.add(newNode);
}
} else {
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.
- currentGroup.update(frequency, shortcutTargets, null,
- currentGroup.mIsNotAWord && isNotAWord,
- currentGroup.mIsBlacklistEntry || isBlacklistEntry);
+ currentPtNode.update(frequency, shortcutTargets, null,
+ currentPtNode.mIsNotAWord && isNotAWord,
+ currentPtNode.mIsBlacklistEntry || isBlacklistEntry);
} else {
// Partial prefix match only. We have to replace the current node with a node
// containing the current prefix and create two new ones for the tails.
- Node newChildren = new Node();
- final CharGroup newOldWord = new CharGroup(
- Arrays.copyOfRange(currentGroup.mChars, differentCharIndex,
- currentGroup.mChars.length), currentGroup.mShortcutTargets,
- currentGroup.mBigrams, currentGroup.mFrequency,
- currentGroup.mIsNotAWord, currentGroup.mIsBlacklistEntry,
- currentGroup.mChildren);
+ PtNodeArray newChildren = new PtNodeArray();
+ final PtNode newOldWord = new PtNode(
+ Arrays.copyOfRange(currentPtNode.mChars, differentCharIndex,
+ currentPtNode.mChars.length), currentPtNode.mShortcutTargets,
+ currentPtNode.mBigrams, currentPtNode.mFrequency,
+ currentPtNode.mIsNotAWord, currentPtNode.mIsBlacklistEntry,
+ currentPtNode.mChildren);
newChildren.mData.add(newOldWord);
- final CharGroup newParent;
+ final PtNode newParent;
if (charIndex + differentCharIndex >= word.length) {
- newParent = new CharGroup(
- Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex),
+ newParent = new PtNode(
+ Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
shortcutTargets, null /* bigrams */, frequency,
isNotAWord, isBlacklistEntry, newChildren);
} else {
- newParent = new CharGroup(
- Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex),
+ newParent = new PtNode(
+ Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
null /* shortcutTargets */, null /* bigrams */, -1,
false /* isNotAWord */, false /* isBlacklistEntry */, newChildren);
- final CharGroup newWord = new CharGroup(Arrays.copyOfRange(word,
+ final PtNode newWord = new PtNode(Arrays.copyOfRange(word,
charIndex + differentCharIndex, word.length),
shortcutTargets, null /* bigrams */, frequency,
isNotAWord, isBlacklistEntry);
final int addIndex = word[charIndex + differentCharIndex]
- > currentGroup.mChars[differentCharIndex] ? 1 : 0;
+ > currentPtNode.mChars[differentCharIndex] ? 1 : 0;
newChildren.mData.add(addIndex, newWord);
}
- currentNode.mData.set(nodeIndex, newParent);
+ currentNodeArray.mData.set(nodeIndex, newParent);
}
- if (DBG) checkStack(currentNode);
+ if (DBG) checkStack(currentNodeArray);
}
}
}
@@ -576,7 +583,7 @@ public final class FusionDictionary implements Iterable<Word> {
* @param dstOffset the offset in the right-hand side string.
* @return the index at which the strings differ, or ARRAYS_ARE_EQUAL = 0 if they don't.
*/
- private static int compareArrays(final int[] src, final int[] dst, int dstOffset) {
+ private static int compareCharArrays(final int[] src, final int[] dst, int dstOffset) {
// We do NOT test the first char, because we come from a method that already
// tested it.
for (int i = 1; i < src.length; ++i) {
@@ -588,43 +595,43 @@ public final class FusionDictionary implements Iterable<Word> {
}
/**
- * Helper class that compares and sorts two chargroups according to their
+ * Helper class that compares and sorts two PtNodes according to their
* first element only. I repeat: ONLY the first element is considered, the rest
* is ignored.
* This comparator imposes orderings that are inconsistent with equals.
*/
- static private final class CharGroupComparator implements java.util.Comparator<CharGroup> {
+ static private final class PtNodeComparator implements java.util.Comparator<PtNode> {
@Override
- public int compare(CharGroup c1, CharGroup c2) {
- if (c1.mChars[0] == c2.mChars[0]) return 0;
- return c1.mChars[0] < c2.mChars[0] ? -1 : 1;
+ public int compare(PtNode p1, PtNode p2) {
+ if (p1.mChars[0] == p2.mChars[0]) return 0;
+ return p1.mChars[0] < p2.mChars[0] ? -1 : 1;
}
}
- final static private CharGroupComparator CHARGROUP_COMPARATOR = new CharGroupComparator();
+ final static private PtNodeComparator PTNODE_COMPARATOR = new PtNodeComparator();
/**
- * Finds the insertion index of a character within a node.
+ * Finds the insertion index of a character within a node array.
*/
- private static int findInsertionIndex(final Node node, int character) {
- final ArrayList<CharGroup> data = node.mData;
- final CharGroup reference = new CharGroup(new int[] { character },
+ 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 */);
- int result = Collections.binarySearch(data, reference, CHARGROUP_COMPARATOR);
+ int result = Collections.binarySearch(data, reference, PTNODE_COMPARATOR);
return result >= 0 ? result : -result - 1;
}
/**
- * Find the index of a char in a node, if it exists.
+ * Find the index of a char in a node array, if it exists.
*
- * @param node the node to search in.
+ * @param nodeArray the node array to search in.
* @param character the character to search for.
* @return the position of the character if it's there, or CHARACTER_NOT_FOUND_INDEX = -1 else.
*/
- private static int findIndexOfChar(final Node node, int character) {
- final int insertionIndex = findInsertionIndex(node, character);
- if (node.mData.size() <= insertionIndex) return CHARACTER_NOT_FOUND_INDEX;
- return character == node.mData.get(insertionIndex).mChars[0] ? insertionIndex
+ private static int findIndexOfChar(final PtNodeArray nodeArray, int character) {
+ final int insertionIndex = findInsertionIndex(nodeArray, character);
+ if (nodeArray.mData.size() <= insertionIndex) return CHARACTER_NOT_FOUND_INDEX;
+ return character == nodeArray.mData.get(insertionIndex).mChars[0] ? insertionIndex
: CHARACTER_NOT_FOUND_INDEX;
}
@@ -632,35 +639,37 @@ public final class FusionDictionary implements Iterable<Word> {
* Helper method to find a word in a given branch.
*/
@SuppressWarnings("unused")
- public static CharGroup findWordInTree(Node node, final String string) {
+ public static PtNode findWordInTree(PtNodeArray nodeArray, final String string) {
int index = 0;
final StringBuilder checker = DBG ? new StringBuilder() : null;
final int[] codePoints = getCodePoints(string);
- CharGroup currentGroup;
+ PtNode currentPtNode;
do {
- int indexOfGroup = findIndexOfChar(node, codePoints[index]);
+ int indexOfGroup = findIndexOfChar(nodeArray, codePoints[index]);
if (CHARACTER_NOT_FOUND_INDEX == indexOfGroup) return null;
- currentGroup = node.mData.get(indexOfGroup);
+ currentPtNode = nodeArray.mData.get(indexOfGroup);
- if (codePoints.length - index < currentGroup.mChars.length) return null;
+ if (codePoints.length - index < currentPtNode.mChars.length) return null;
int newIndex = index;
- while (newIndex < codePoints.length && newIndex - index < currentGroup.mChars.length) {
- if (currentGroup.mChars[newIndex - index] != codePoints[newIndex]) return null;
+ while (newIndex < codePoints.length && newIndex - index < currentPtNode.mChars.length) {
+ if (currentPtNode.mChars[newIndex - index] != codePoints[newIndex]) return null;
newIndex++;
}
index = newIndex;
- if (DBG) checker.append(new String(currentGroup.mChars, 0, currentGroup.mChars.length));
+ if (DBG) {
+ checker.append(new String(currentPtNode.mChars, 0, currentPtNode.mChars.length));
+ }
if (index < codePoints.length) {
- node = currentGroup.mChildren;
+ nodeArray = currentPtNode.mChildren;
}
- } while (null != node && index < codePoints.length);
+ } while (null != nodeArray && index < codePoints.length);
if (index < codePoints.length) return null;
- if (!currentGroup.isTerminal()) return null;
+ if (!currentPtNode.isTerminal()) return null;
if (DBG && !string.equals(checker.toString())) return null;
- return currentGroup;
+ return currentPtNode;
}
/**
@@ -670,22 +679,22 @@ public final class FusionDictionary implements Iterable<Word> {
if (null == s || "".equals(s)) {
throw new RuntimeException("Can't search for a null or empty string");
}
- return null != findWordInTree(mRoot, s);
+ return null != findWordInTree(mRootNodeArray, s);
}
/**
- * Recursively count the number of character groups in a given branch of the trie.
+ * Recursively count the number of PtNodes in a given branch of the trie.
*
- * @param node the parent node.
- * @return the number of char groups in all the branch under this node.
+ * @param nodeArray the parent node.
+ * @return the number of PtNodes in all the branch under this node.
*/
- public static int countCharGroups(final Node node) {
- final int nodeSize = node.mData.size();
+ public static int countPtNodes(final PtNodeArray nodeArray) {
+ final int nodeSize = nodeArray.mData.size();
int size = nodeSize;
for (int i = nodeSize - 1; i >= 0; --i) {
- CharGroup group = node.mData.get(i);
- if (null != group.mChildren)
- size += countCharGroups(group.mChildren);
+ PtNode ptNode = nodeArray.mData.get(i);
+ if (null != ptNode.mChildren)
+ size += countPtNodes(ptNode.mChildren);
}
return size;
}
@@ -693,15 +702,15 @@ public final class FusionDictionary implements Iterable<Word> {
/**
* Recursively count the number of nodes in a given branch of the trie.
*
- * @param node the node to count.
+ * @param nodeArray the node array to count.
* @return the number of nodes in this branch.
*/
- public static int countNodes(final Node node) {
+ public static int countNodeArrays(final PtNodeArray nodeArray) {
int size = 1;
- for (int i = node.mData.size() - 1; i >= 0; --i) {
- CharGroup group = node.mData.get(i);
- if (null != group.mChildren)
- size += countNodes(group.mChildren);
+ 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;
}
@@ -709,12 +718,12 @@ public final class FusionDictionary implements Iterable<Word> {
// 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 Node node) {
- if (null == node) return false;
- for (int i = node.mData.size() - 1; i >= 0; --i) {
- CharGroup group = node.mData.get(i);
- if (null != group.mBigrams) return true;
- if (hasBigramsInternal(group.mChildren)) return true;
+ 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;
}
@@ -729,7 +738,7 @@ public final class FusionDictionary implements Iterable<Word> {
// find a more efficient way of doing this, without compromising too much on memory
// and ease of use.
public boolean hasBigrams() {
- return hasBigramsInternal(mRoot);
+ return hasBigramsInternal(mRootNodeArray);
}
// Historically, the tails of the words were going to be merged to save space.
@@ -747,16 +756,16 @@ public final class FusionDictionary implements Iterable<Word> {
MakedictLog.i("Do not merge tails");
return;
-// MakedictLog.i("Merging nodes. Number of nodes : " + countNodes(root));
-// MakedictLog.i("Number of groups : " + countCharGroups(root));
+// MakedictLog.i("Merging PtNodes. Number of PtNodes : " + countPtNodes(root));
+// MakedictLog.i("Number of PtNodes : " + countPtNodes(root));
//
-// final HashMap<String, ArrayList<Node>> repository =
-// new HashMap<String, ArrayList<Node>>();
+// 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<Node> a : repository.values()) {
+// for (ArrayList<PtNodeArray> a : repository.values()) {
// size += a.size();
// }
// MakedictLog.i("Number of nodes after merge : " + (1 + size));
@@ -764,58 +773,58 @@ public final class FusionDictionary implements Iterable<Word> {
}
// The following methods are used by the deactivated mergeTails()
-// private static boolean isEqual(Node a, Node b) {
+// 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) {
-// CharGroup aGroup = a.data.get(i);
-// CharGroup bGroup = b.data.get(i);
-// if (aGroup.frequency != bGroup.frequency) return false;
-// if (aGroup.alternates == null && bGroup.alternates != null) return false;
-// if (aGroup.alternates != null && !aGroup.equals(bGroup.alternates)) return false;
-// if (!Arrays.equals(aGroup.chars, bGroup.chars)) return false;
-// if (!isEqual(aGroup.children, bGroup.children)) return false;
+// 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<Node>> mergeTailsInner(
-// final HashMap<String, ArrayList<Node>> map, final Node node) {
-// final ArrayList<CharGroup> branches = node.data;
+// 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) {
-// CharGroup group = branches.get(i);
-// if (null != group.children) {
-// String pseudoHash = getPseudoHash(group.children);
-// ArrayList<Node> similarList = map.get(pseudoHash);
+// 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<Node>();
+// similarList = new ArrayList<PtNodeArray>();
// map.put(pseudoHash, similarList);
// }
// boolean merged = false;
-// for (Node similar : similarList) {
-// if (isEqual(group.children, similar)) {
-// group.children = similar;
+// for (PtNodeArray similar : similarList) {
+// if (isEqual(ptNode.children, similar)) {
+// ptNode.children = similar;
// merged = true;
// break;
// }
// }
// if (!merged) {
-// similarList.add(group.children);
+// similarList.add(ptNode.children);
// }
-// mergeTailsInner(map, group.children);
+// mergeTailsInner(map, ptNode.children);
// }
// }
// return map;
// }
-// private static String getPseudoHash(final Node node) {
+// private static String getPseudoHash(final PtNodeArray nodeArray) {
// StringBuilder s = new StringBuilder();
-// for (CharGroup g : node.data) {
-// s.append(g.frequency);
-// for (int ch : g.chars) {
+// for (PtNode ptNode : nodeArray.data) {
+// s.append(ptNode.frequency);
+// for (int ch : ptNode.chars) {
// s.append(Character.toChars(ch));
// }
// }
@@ -829,20 +838,20 @@ public final class FusionDictionary implements Iterable<Word> {
*/
public static final class DictionaryIterator implements Iterator<Word> {
private static final class Position {
- public Iterator<CharGroup> pos;
+ public Iterator<PtNode> pos;
public int length;
- public Position(ArrayList<CharGroup> groups) {
- pos = groups.iterator();
+ public Position(ArrayList<PtNode> ptNodes) {
+ pos = ptNodes.iterator();
length = 0;
}
}
final StringBuilder mCurrentString;
final LinkedList<Position> mPositions;
- public DictionaryIterator(ArrayList<CharGroup> root) {
+ public DictionaryIterator(ArrayList<PtNode> ptRoot) {
mCurrentString = new StringBuilder();
mPositions = new LinkedList<Position>();
- final Position rootPos = new Position(root);
+ final Position rootPos = new Position(ptRoot);
mPositions.add(rootPos);
}
@@ -863,20 +872,20 @@ public final class FusionDictionary implements Iterable<Word> {
do {
if (currentPos.pos.hasNext()) {
- final CharGroup currentGroup = currentPos.pos.next();
+ final PtNode currentPtNode = currentPos.pos.next();
currentPos.length = mCurrentString.length();
- for (int i : currentGroup.mChars) {
+ for (int i : currentPtNode.mChars) {
mCurrentString.append(Character.toChars(i));
}
- if (null != currentGroup.mChildren) {
- currentPos = new Position(currentGroup.mChildren.mData);
+ if (null != currentPtNode.mChildren) {
+ currentPos = new Position(currentPtNode.mChildren.mData);
currentPos.length = mCurrentString.length();
mPositions.addLast(currentPos);
}
- if (currentGroup.mFrequency >= 0) {
- return new Word(mCurrentString.toString(), currentGroup.mFrequency,
- currentGroup.mShortcutTargets, currentGroup.mBigrams,
- currentGroup.mIsNotAWord, currentGroup.mIsBlacklistEntry);
+ if (currentPtNode.mFrequency >= 0) {
+ return new Word(mCurrentString.toString(), currentPtNode.mFrequency,
+ currentPtNode.mShortcutTargets, currentPtNode.mBigrams,
+ currentPtNode.mIsNotAWord, currentPtNode.mIsBlacklistEntry);
}
} else {
mPositions.removeLast();
@@ -901,6 +910,6 @@ public final class FusionDictionary implements Iterable<Word> {
*/
@Override
public Iterator<Word> iterator() {
- return new DictionaryIterator(mRoot.mData);
+ return new DictionaryIterator(mRootNodeArray.mData);
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java b/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
index b3617443e..188de7a0f 100644
--- a/java/src/com/android/inputmethod/latin/makedict/CharGroupInfo.java
+++ b/java/src/com/android/inputmethod/latin/makedict/PtNodeInfo.java
@@ -21,9 +21,9 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import java.util.ArrayList;
/**
- * Raw char group info straight out of a file. This will contain numbers for addresses.
+ * Raw PtNode info straight out of a file. This will contain numbers for addresses.
*/
-public final class CharGroupInfo {
+public final class PtNodeInfo {
public final int mOriginalAddress;
public final int mEndAddress;
@@ -35,7 +35,7 @@ public final class CharGroupInfo {
public final ArrayList<WeightedString> mShortcutTargets;
public final ArrayList<PendingAttribute> mBigrams;
- public CharGroupInfo(final int originalAddress, final int endAddress, final int flags,
+ public PtNodeInfo(final int originalAddress, final int endAddress, final int flags,
final int[] characters, final int frequency, final int parentAddress,
final int childrenAddress, final ArrayList<WeightedString> shortcutTargets,
final ArrayList<PendingAttribute> bigrams) {
diff --git a/java/src/com/android/inputmethod/latin/makedict/SparseTable.java b/java/src/com/android/inputmethod/latin/makedict/SparseTable.java
new file mode 100644
index 000000000..0b9cf91d2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/SparseTable.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+
+import java.io.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 mContentsTable 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<Integer> mContentTable;
+
+ private final int mBlockSize;
+ public static final int NOT_EXIST = -1;
+
+ @UsedForTesting
+ public SparseTable(final int initialCapacity, final int blockSize) {
+ mBlockSize = blockSize;
+ final int lookupTableSize = initialCapacity / mBlockSize
+ + (initialCapacity % mBlockSize > 0 ? 1 : 0);
+ mLookupTable = new ArrayList<Integer>(Collections.nCopies(lookupTableSize, NOT_EXIST));
+ mContentTable = new ArrayList<Integer>();
+ }
+
+ @UsedForTesting
+ public SparseTable(final int[] lookupTable, final int[] contentTable, final int blockSize) {
+ mBlockSize = blockSize;
+ mLookupTable = new ArrayList<Integer>(lookupTable.length);
+ for (int i = 0; i < lookupTable.length; ++i) {
+ mLookupTable.add(lookupTable[i]);
+ }
+ mContentTable = new ArrayList<Integer>(contentTable.length);
+ for (int i = 0; i < contentTable.length; ++i) {
+ mContentTable.add(contentTable[i]);
+ }
+ }
+
+ /**
+ * 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 void convertByteArrayToIntegerArray(final byte[] byteArray,
+ final ArrayList<Integer> integerArray) {
+ 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);
+ }
+ }
+
+ @UsedForTesting
+ public SparseTable(final byte[] lookupTable, final byte[] contentTable, final int blockSize) {
+ mBlockSize = blockSize;
+ mLookupTable = new ArrayList<Integer>(lookupTable.length / 4);
+ mContentTable = new ArrayList<Integer>(contentTable.length / 4);
+ convertByteArrayToIntegerArray(lookupTable, mLookupTable);
+ convertByteArrayToIntegerArray(contentTable, mContentTable);
+ }
+
+ @UsedForTesting
+ public int get(final int index) {
+ if (index < 0 || index / mBlockSize >= mLookupTable.size()
+ || mLookupTable.get(index / mBlockSize) == NOT_EXIST) {
+ return NOT_EXIST;
+ }
+ return mContentTable.get(mLookupTable.get(index / mBlockSize) + (index % mBlockSize));
+ }
+
+ @UsedForTesting
+ public void set(final int index, final int value) {
+ if (mLookupTable.get(index / mBlockSize) == NOT_EXIST) {
+ mLookupTable.set(index / mBlockSize, mContentTable.size());
+ for (int i = 0; i < mBlockSize; ++i) {
+ mContentTable.add(NOT_EXIST);
+ }
+ }
+ mContentTable.set(mLookupTable.get(index / mBlockSize) + (index % mBlockSize), value);
+ }
+
+ public void remove(final int index) {
+ set(index, NOT_EXIST);
+ }
+
+ @UsedForTesting
+ public int size() {
+ return mLookupTable.size() * mBlockSize;
+ }
+
+ @UsedForTesting
+ /* package */ int getContentTableSize() {
+ return mContentTable.size();
+ }
+
+ @UsedForTesting
+ /* package */ int getLookupTableSize() {
+ return mLookupTable.size();
+ }
+
+ public boolean contains(final int index) {
+ return get(index) != NOT_EXIST;
+ }
+
+ @UsedForTesting
+ public void write(final OutputStream lookupOutStream, final OutputStream contentOutStream)
+ throws IOException {
+ for (final int index : mLookupTable) {
+ BinaryDictEncoderUtils.writeUIntToStream(lookupOutStream, index, 4);
+ }
+
+ for (final int index : mContentTable) {
+ BinaryDictEncoderUtils.writeUIntToStream(contentOutStream, index, 4);
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java
new file mode 100644
index 000000000..848277cd4
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java
@@ -0,0 +1,234 @@
+/*
+ * 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 DictDecoder {
+ 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 DictDecoder.PtNodeReader {
+ private static int readFrequency(final DictBuffer dictBuffer) {
+ return dictBuffer.readUnsignedByte();
+ }
+ }
+
+ private final File mDictionaryBinaryFile;
+ private final DictionaryBufferFactory mBufferFactory;
+ private 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) {
+ MakedictLog.d("too many 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;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
new file mode 100644
index 000000000..76f0f4052
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+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 3 binary dictionary.
+ */
+public class Ver3DictEncoder implements DictEncoder {
+
+ private final File mDictFile;
+ private OutputStream mOutStream;
+ private byte[] mBuffer;
+ private int mPosition;
+
+ public Ver3DictEncoder(final File dictFile) {
+ mDictFile = dictFile;
+ mOutStream = null;
+ mBuffer = null;
+ }
+
+ // 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) {
+ mDictFile = null;
+ mOutStream = outStream;
+ }
+
+ private void openStream() throws FileNotFoundException {
+ mOutStream = new FileOutputStream(mDictFile);
+ }
+
+ private void close() throws IOException {
+ if (mOutStream != null) {
+ mOutStream.close();
+ mOutStream = null;
+ }
+ }
+
+ @Override
+ public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
+ throws IOException, UnsupportedFormatException {
+ if (formatOptions.mVersion > FormatSpec.VERSION3) {
+ throw new UnsupportedFormatException(
+ "The given format options has wrong version number : "
+ + formatOptions.mVersion);
+ }
+
+ if (mOutStream == null) {
+ openStream();
+ }
+ BinaryDictEncoderUtils.writeDictionaryHeader(mOutStream, dict, formatOptions);
+
+ // Addresses are limited to 3 bytes, but since addresses can be relative to each node
+ // array, the structure itself is not limited to 16MB. However, if it is over 16MB deciding
+ // the order of the PtNode arrays becomes a quite complicated problem, because though the
+ // dictionary itself does not have a size limit, each node array must still be within 16MB
+ // of all its children and parents. As long as this is ensured, the dictionary file may
+ // grow to any size.
+
+ // Leave the choice of the optimal node order to the flattenTree function.
+ MakedictLog.i("Flattening the tree...");
+ ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray);
+
+ MakedictLog.i("Computing addresses...");
+ BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions);
+ MakedictLog.i("Checking PtNode array...");
+ if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes);
+
+ // Create a buffer that matches the final dictionary size.
+ final PtNodeArray lastNodeArray = flatNodes.get(flatNodes.size() - 1);
+ final int bufferSize = lastNodeArray.mCachedAddressAfterUpdate + lastNodeArray.mCachedSize;
+ mBuffer = new byte[bufferSize];
+
+ MakedictLog.i("Writing file...");
+
+ for (PtNodeArray nodeArray : flatNodes) {
+ BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions);
+ }
+ if (MakedictLog.DBG) BinaryDictEncoderUtils.showStatistics(flatNodes);
+ mOutStream.write(mBuffer, 0, mPosition);
+
+ MakedictLog.i("Done");
+ close();
+ }
+
+ @Override
+ public void setPosition(final int position) {
+ if (mBuffer == null || position < 0 || position >= mBuffer.length) return;
+ mPosition = position;
+ }
+
+ @Override
+ public int getPosition() {
+ return mPosition;
+ }
+
+ @Override
+ public void writePtNodeCount(final int ptNodeCount) {
+ final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount);
+ if (countSize != 1 && countSize != 2) {
+ throw new RuntimeException("Strange size from getGroupCountSize : " + countSize);
+ }
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, ptNodeCount,
+ countSize);
+ }
+
+ private void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
+ final FormatOptions formatOptions) {
+ final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition,
+ BinaryDictEncoderUtils.makePtNodeFlags(ptNode, mPosition, childrenPos,
+ formatOptions),
+ 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) {
+ mBuffer[mPosition++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR;
+ }
+ }
+
+ private void writeFrequency(final int frequency) {
+ if (frequency >= 0) {
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, frequency,
+ FormatSpec.PTNODE_FREQUENCY_SIZE);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ /**
+ * Write a shortcut attributes list to mBuffer.
+ *
+ * @param shortcuts the shortcut attributes list.
+ */
+ private void writeShortcuts(final ArrayList<WeightedString> shortcuts) {
+ if (null == shortcuts || shortcuts.isEmpty()) return;
+
+ final int indexOfShortcutByteSize = mPosition;
+ mPosition += FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
+ final Iterator<WeightedString> shortcutIterator = shortcuts.iterator();
+ while (shortcutIterator.hasNext()) {
+ final WeightedString target = shortcutIterator.next();
+ final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags(
+ shortcutIterator.hasNext(),
+ target.mFrequency);
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, shortcutFlags,
+ FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
+ final int shortcutShift = CharEncoding.writeString(mBuffer, mPosition, target.mWord);
+ mPosition += shortcutShift;
+ }
+ final int shortcutByteSize = mPosition - indexOfShortcutByteSize;
+ if (shortcutByteSize > FormatSpec.MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE) {
+ throw new RuntimeException("Shortcut list too large");
+ }
+ BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, indexOfShortcutByteSize, shortcutByteSize,
+ FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE);
+ }
+
+ /**
+ * Write a bigram attributes list to mBuffer.
+ *
+ * @param bigrams the bigram attributes list.
+ * @param dict the dictionary the node array is a part of (for relative offsets).
+ */
+ private void writeBigrams(final ArrayList<WeightedString> bigrams,
+ final FusionDictionary dict) {
+ if (bigrams == null) return;
+
+ final Iterator<WeightedString> bigramIterator = bigrams.iterator();
+ while (bigramIterator.hasNext()) {
+ final WeightedString bigram = bigramIterator.next();
+ final PtNode target =
+ FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord);
+ final int addressOfBigram = target.mCachedAddressAfterUpdate;
+ final int unigramFrequencyForThisWord = target.mFrequency;
+ final int offset = addressOfBigram
+ - (mPosition + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
+ final int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(),
+ offset, bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord);
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, bigramFlags,
+ FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
+ mPosition += BinaryDictEncoderUtils.writeChildrenPosition(mBuffer, mPosition,
+ Math.abs(offset));
+ }
+ }
+
+ @Override
+ public void writeForwardLinkAddress(final int forwardLinkAddress) {
+ mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, forwardLinkAddress,
+ FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
+ }
+
+ @Override
+ public void writePtNode(final PtNode ptNode, final int parentPosition,
+ final FormatOptions formatOptions, final FusionDictionary dict) {
+ writePtNodeFlags(ptNode, parentPosition, formatOptions);
+ writeParentPosition(parentPosition, ptNode, formatOptions);
+ writeCharacters(ptNode.mChars, ptNode.hasSeveralChars());
+ writeFrequency(ptNode.mFrequency);
+ writeChildrenPosition(ptNode, formatOptions);
+ writeShortcuts(ptNode.mShortcutTargets);
+ writeBigrams(ptNode.mBigrams, dict);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
new file mode 100644
index 000000000..4c8ff8ea4
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
@@ -0,0 +1,266 @@
+/*
+ * 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 android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * An implementation of binary dictionary decoder for version 4 binary dictionary.
+ */
+@UsedForTesting
+public class Ver4DictDecoder extends DictDecoder {
+ 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 final File mDictDirectory;
+ private final DictionaryBufferFactory mBufferFactory;
+ private DictBuffer mDictBuffer;
+ private DictBuffer mFrequencyBuffer;
+ private DictBuffer mTerminalAddressTableBuffer;
+
+ @UsedForTesting
+ /* package */ Ver4DictDecoder(final File dictDirectory, final int factoryFlag) {
+ mDictDirectory = dictDirectory;
+ mDictBuffer = mFrequencyBuffer = null;
+
+ if ((factoryFlag & MASK_DICTBUFFER) == USE_READONLY_BYTEBUFFER) {
+ mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory();
+ } else if ((factoryFlag & MASK_DICTBUFFER) == USE_BYTEARRAY) {
+ mBufferFactory = new DictionaryBufferFromByteArrayFactory();
+ } else if ((factoryFlag & MASK_DICTBUFFER) == USE_WRITABLE_BYTEBUFFER) {
+ mBufferFactory = new DictionaryBufferFromWritableByteBufferFactory();
+ } else {
+ mBufferFactory = new DictionaryBufferFromReadOnlyByteBufferFactory();
+ }
+ }
+
+ @UsedForTesting
+ /* package */ Ver4DictDecoder(final File dictDirectory, final DictionaryBufferFactory factory) {
+ mDictDirectory = dictDirectory;
+ mBufferFactory = factory;
+ mDictBuffer = mFrequencyBuffer = null;
+ }
+
+ private File getFile(final int fileType) {
+ if (fileType == FILETYPE_TRIE) {
+ return new File(mDictDirectory,
+ mDictDirectory.getName() + FormatSpec.TRIE_FILE_EXTENSION);
+ } else if (fileType == FILETYPE_FREQUENCY) {
+ return new File(mDictDirectory,
+ mDictDirectory.getName() + FormatSpec.FREQ_FILE_EXTENSION);
+ } else if (fileType == FILETYPE_TERMINAL_ADDRESS_TABLE) {
+ return new File(mDictDirectory,
+ mDictDirectory.getName() + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION);
+ } else {
+ throw new RuntimeException("Unsupported kind of file : " + fileType);
+ }
+ }
+
+ @Override
+ public void openDictBuffer() throws FileNotFoundException, IOException {
+ final String filename = mDictDirectory.getName();
+ mDictBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_TRIE));
+ mFrequencyBuffer = mBufferFactory.getDictionaryBuffer(getFile(FILETYPE_FREQUENCY));
+ mTerminalAddressTableBuffer = mBufferFactory.getDictionaryBuffer(
+ getFile(FILETYPE_TERMINAL_ADDRESS_TABLE));
+ }
+
+ @Override
+ public boolean isDictBufferOpen() {
+ return mDictBuffer != null;
+ }
+
+ /* package */ DictBuffer getDictBuffer() {
+ return mDictBuffer;
+ }
+
+ @Override
+ public FileHeader readHeader() throws IOException, UnsupportedFormatException {
+ if (mDictBuffer == null) {
+ openDictBuffer();
+ }
+ final FileHeader header = super.readHeader(mDictBuffer);
+ final int version = header.mFormatOptions.mVersion;
+ if (version != 4) {
+ throw new UnsupportedFormatException("File header has a wrong version : " + version);
+ }
+ return header;
+ }
+
+ protected static class PtNodeReader extends DictDecoder.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();
+ }
+ }
+
+ // 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;
+ 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) {
+ MakedictLog.d("too many bigrams in a node.");
+ }
+ } else {
+ bigrams = null;
+ }
+ return new PtNodeInfo(ptNodePos, addressPointer, flags, characters, frequency,
+ parentAddress, childrenAddress, shortcutTargets, bigrams);
+ }
+
+ private void deleteDictFiles() {
+ final File[] files = mDictDirectory.listFiles();
+ for (int i = 0; i < files.length; ++i) {
+ files[i].delete();
+ }
+ }
+
+ @Override
+ public FusionDictionary readDictionaryBinary(final FusionDictionary dict,
+ final boolean deleteDictIfBroken)
+ throws FileNotFoundException, IOException, UnsupportedFormatException {
+ if (mDictBuffer == null) {
+ openDictBuffer();
+ }
+ try {
+ return BinaryDictDecoderUtils.readDictionaryBinary(this, dict);
+ } catch (IOException e) {
+ Log.e(TAG, "The dictionary " + mDictDirectory.getName() + " is broken.", e);
+ if (deleteDictIfBroken) {
+ deleteDictFiles();
+ }
+ throw e;
+ } catch (UnsupportedFormatException e) {
+ Log.e(TAG, "The dictionary " + mDictDirectory.getName() + " is broken.", e);
+ if (deleteDictIfBroken) {
+ deleteDictFiles();
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public void setPosition(int newPos) {
+ mDictBuffer.position(newPos);
+ }
+
+ @Override
+ public int getPosition() {
+ return mDictBuffer.position();
+ }
+
+ @Override
+ public int readPtNodeCount() {
+ return BinaryDictDecoderUtils.readPtNodeCount(mDictBuffer);
+ }
+
+ @Override
+ public boolean readAndFollowForwardLink() {
+ final int nextAddress = mDictBuffer.readUnsignedInt24();
+ if (nextAddress >= 0 && nextAddress < mDictBuffer.limit()) {
+ mDictBuffer.position(nextAddress);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean hasNextPtNodeArray() {
+ return mDictBuffer.position() != FormatSpec.NO_FORWARD_LINK_ADDRESS;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
new file mode 100644
index 000000000..4fb89671f
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
@@ -0,0 +1,294 @@
+/*
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * An implementation of DictEncoder for version 4 binary dictionary.
+ */
+@UsedForTesting
+public class Ver4DictEncoder implements DictEncoder {
+ private final File mDictPlacedDir;
+ private byte[] mTrieBuf;
+ private int mTriePos;
+ private int mHeaderSize;
+ private OutputStream mTrieOutStream;
+ private OutputStream mFreqOutStream;
+ private OutputStream mTerminalAddressTableOutStream;
+
+ @UsedForTesting
+ public Ver4DictEncoder(final File dictPlacedDir) {
+ mDictPlacedDir = dictPlacedDir;
+ }
+
+ private void openStreams(final FormatOptions formatOptions, final DictionaryOptions dictOptions)
+ throws FileNotFoundException, IOException {
+ final FileHeader header = new FileHeader(0, dictOptions, formatOptions);
+ final String filename = header.getId() + "." + header.getVersion();
+ final File mDictDir = new File(mDictPlacedDir, filename);
+ final File trieFile = new File(mDictDir, filename + FormatSpec.TRIE_FILE_EXTENSION);
+ final File freqFile = new File(mDictDir, filename + FormatSpec.FREQ_FILE_EXTENSION);
+ final File terminalAddressTableFile = new File(mDictDir,
+ filename + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION);
+ if (!mDictDir.isDirectory()) {
+ if (mDictDir.exists()) mDictDir.delete();
+ mDictDir.mkdirs();
+ }
+ if (!trieFile.exists()) trieFile.createNewFile();
+ if (!freqFile.exists()) freqFile.createNewFile();
+ if (!terminalAddressTableFile.exists()) terminalAddressTableFile.createNewFile();
+ mTrieOutStream = new FileOutputStream(trieFile);
+ mFreqOutStream = new FileOutputStream(freqFile);
+ mTerminalAddressTableOutStream = new FileOutputStream(terminalAddressTableFile);
+ }
+
+ private void close() throws IOException {
+ try {
+ if (mTrieOutStream != null) {
+ mTrieOutStream.close();
+ }
+ if (mFreqOutStream != null) {
+ mFreqOutStream.close();
+ }
+ if (mTerminalAddressTableOutStream != null) {
+ mTerminalAddressTableOutStream.close();
+ }
+ } finally {
+ mTrieOutStream = null;
+ mFreqOutStream = null;
+ mTerminalAddressTableOutStream = null;
+ }
+ }
+
+ @Override
+ public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
+ throws IOException, UnsupportedFormatException {
+ if (formatOptions.mVersion != FormatSpec.VERSION4) {
+ throw new UnsupportedFormatException("File header has a wrong version number : "
+ + formatOptions.mVersion);
+ }
+ if (!mDictPlacedDir.isDirectory()) {
+ throw new UnsupportedFormatException("Given path is not a directory.");
+ }
+
+ if (mTrieOutStream == null) {
+ openStreams(formatOptions, dict.mOptions);
+ }
+
+ mHeaderSize = BinaryDictEncoderUtils.writeDictionaryHeader(mTrieOutStream, dict,
+ formatOptions);
+
+ MakedictLog.i("Flattening the tree...");
+ ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray);
+ int terminalCount = 0;
+ for (final PtNodeArray array : flatNodes) {
+ for (final PtNode node : array.mData) {
+ if (node.isTerminal()) node.mTerminalId = terminalCount++;
+ }
+ }
+
+ MakedictLog.i("Computing addresses...");
+ BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions);
+ if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes);
+
+ writeTerminalData(flatNodes, terminalCount);
+
+ final PtNodeArray lastNodeArray = flatNodes.get(flatNodes.size() - 1);
+ final int bufferSize = lastNodeArray.mCachedAddressAfterUpdate + lastNodeArray.mCachedSize;
+ mTrieBuf = new byte[bufferSize];
+
+ MakedictLog.i("Writing file...");
+ for (PtNodeArray nodeArray : flatNodes) {
+ BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions);
+ }
+ if (MakedictLog.DBG) {
+ BinaryDictEncoderUtils.showStatistics(flatNodes);
+ MakedictLog.i("has " + terminalCount + " terminals.");
+ }
+ mTrieOutStream.write(mTrieBuf);
+
+ MakedictLog.i("Done");
+ close();
+ }
+
+ @Override
+ public void setPosition(int position) {
+ if (mTrieBuf == null || position < 0 || position >- mTrieBuf.length) return;
+ mTriePos = position;
+ }
+
+ @Override
+ public int getPosition() {
+ return mTriePos;
+ }
+
+ @Override
+ public void writePtNodeCount(int ptNodeCount) {
+ final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount);
+ // ptNodeCount must fit on one byte or two bytes.
+ // Please see comments in FormatSpec
+ if (countSize != 1 && countSize != 2) {
+ throw new RuntimeException("Strange size from getPtNodeCountSize : " + countSize);
+ }
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, ptNodeCount,
+ countSize);
+ }
+
+ private void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
+ final FormatOptions formatOptions) {
+ final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos,
+ BinaryDictEncoderUtils.makePtNodeFlags(ptNode, mTriePos, 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 writeShortcuts(ArrayList<WeightedString> shortcuts) {
+ if (null == shortcuts || shortcuts.isEmpty()) return;
+
+ final int indexOfShortcutByteSize = mTriePos;
+ mTriePos += FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
+ final Iterator<WeightedString> shortcutIterator = shortcuts.iterator();
+ while (shortcutIterator.hasNext()) {
+ final WeightedString target = shortcutIterator.next();
+ final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags(
+ shortcutIterator.hasNext(),
+ target.mFrequency);
+ mTrieBuf[mTriePos++] = (byte)shortcutFlags;
+ final int shortcutShift = CharEncoding.writeString(mTrieBuf, mTriePos,
+ target.mWord);
+ mTriePos += shortcutShift;
+ }
+ final int shortcutByteSize = mTriePos - indexOfShortcutByteSize;
+ if (shortcutByteSize > FormatSpec.MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE) {
+ throw new RuntimeException("Shortcut list too large : " + shortcutByteSize);
+ }
+ BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, indexOfShortcutByteSize,
+ shortcutByteSize, FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE);
+ }
+
+ private void writeBigrams(ArrayList<WeightedString> bigrams, FusionDictionary dict) {
+ if (bigrams == null) return;
+
+ final Iterator<WeightedString> bigramIterator = bigrams.iterator();
+ while (bigramIterator.hasNext()) {
+ final WeightedString bigram = bigramIterator.next();
+ final PtNode target =
+ FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord);
+ final int addressOfBigram = target.mCachedAddressAfterUpdate;
+ final int unigramFrequencyForThisWord = target.mFrequency;
+ final int offset = addressOfBigram
+ - (mTriePos + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
+ int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(),
+ offset, bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord);
+ mTrieBuf[mTriePos++] = (byte) bigramFlags;
+ mTriePos += BinaryDictEncoderUtils.writeChildrenPosition(mTrieBuf,
+ mTriePos, Math.abs(offset));
+ }
+ }
+
+ @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, parentPosition, formatOptions);
+ writeParentPosition(parentPosition, ptNode, formatOptions);
+ writeCharacters(ptNode.mChars, ptNode.hasSeveralChars());
+ if (ptNode.isTerminal()) {
+ writeTerminalId(ptNode.mTerminalId);
+ }
+ writeChildrenPosition(ptNode, formatOptions);
+ writeShortcuts(ptNode.mShortcutTargets);
+ writeBigrams(ptNode.mBigrams, dict);
+ }
+
+ 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);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
new file mode 100644
index 000000000..66517a800
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
@@ -0,0 +1,231 @@
+/*
+ * 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 android.content.SharedPreferences;
+import android.util.Log;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.Constants;
+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 java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is a base class of a dictionary that supports decaying for the personalized language
+ * model.
+ */
+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;
+
+ /** Any pair being typed or picked */
+ public static final int FREQUENCY_FOR_TYPED = 2;
+
+ /** Locale for which this user history dictionary is storing words */
+ private final String mLocale;
+
+ private final String mFileName;
+
+ 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);
+ mLocale = locale;
+ mFileName = fileName;
+ mPrefs = sp;
+ if (mLocale != null && mLocale.length() > 1) {
+ asyncLoadDictionaryToMemory();
+ reloadDictionaryIfRequired();
+ }
+ }
+
+ @Override
+ public void close() {
+ if (!ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE) {
+ closeBinaryDictionary();
+ }
+ // Flush pending writes.
+ // TODO: Remove after this class become to use a dynamic binary dictionary.
+ asyncFlashAllBinaryDictionary();
+ Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale);
+ }
+
+ @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);
+ return attributeMap;
+ }
+
+ @Override
+ protected boolean hasContentChanged() {
+ return false;
+ }
+
+ @Override
+ protected boolean needsToReloadBeforeWriting() {
+ return false;
+ }
+
+ /**
+ * Return whether the passed charsequence is in the dictionary.
+ */
+ @Override
+ public boolean isValidWord(final String word) {
+ // Words included only in the user history should be treated as not in dictionary words.
+ return false;
+ }
+
+ /**
+ * Pair will be added to the personalization prediction dictionary.
+ *
+ * The first word may be null. That means we don't know the context, in other words,
+ * it's only a unigram. The first word may also be an empty string : this means start
+ * context, as in beginning of a sentence for example.
+ * The second word may not be null (a NullPointerException would be thrown).
+ */
+ public void addToPersonalizationPredictionDictionary(
+ final String word0, final String word1, final boolean isValid) {
+ if (word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
+ (word0 != null && word0.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
+ return;
+ }
+ addWordDynamically(word1, null /* the "shortcut" parameter is null */, FREQUENCY_FOR_TYPED,
+ false /* isNotAWord */);
+ // Do not insert a word as a bigram of itself
+ if (word1.equals(word0)) {
+ return;
+ }
+ if (null != word0) {
+ addBigramDynamically(word0, word1, FREQUENCY_FOR_TYPED, isValid);
+ }
+ }
+
+ public void cancelAddingUserHistory(final String word0, final String word1) {
+ removeBigramDynamically(word0, word1);
+ }
+
+ @Override
+ protected void loadDictionaryAsync() {
+ final int[] profTotalCount = { 0 };
+ final String locale = getLocale();
+ if (DBG_STRESS_TEST) {
+ try {
+ Log.w(TAG, "Start stress in loading: " + locale);
+ Thread.sleep(15000);
+ Log.w(TAG, "End stress in loading");
+ } catch (InterruptedException e) {
+ }
+ }
+ final long last = Settings.readLastUserHistoryWriteTime(mPrefs, locale);
+ final long now = System.currentTimeMillis();
+ final ExpandableBinaryDictionary dictionary = this;
+ final OnAddWordListener listener = new OnAddWordListener() {
+ @Override
+ public void setUnigram(final String word, final String shortcutTarget,
+ final int frequency) {
+ if (DBG_SAVE_RESTORE) {
+ Log.d(TAG, "load unigram: " + word + "," + frequency);
+ }
+ addWord(word, shortcutTarget, frequency, 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);
+ }
+
+ public void clearAndFlushDictionary() {
+ // Clear the node structure on memory
+ clear();
+ // Then flush the cleared state of the dictionary on disk.
+ asyncFlashAllBinaryDictionary();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java
new file mode 100644
index 000000000..0af028a9e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/DynamicPersonalizationDictionaryWriter.java
@@ -0,0 +1,183 @@
+/*
+ * 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;
+
+// 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.
+ */
+ @Override
+ public void addUnigramWord(final String word, final String shortcutTarget, final int frequency,
+ final boolean isNotAWord) {
+ if (mBigramList.size() > mMaxHistoryBigrams * 2) {
+ // Too many entries: just stop adding new vocabrary and wait next refresh.
+ return;
+ }
+ mExpandableDictionary.addWord(word, shortcutTarget, frequency);
+ 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 vocabrary 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)
+ 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 isInDictionaryForTests(final String word) {
+ // TODO: Use native method to determine whether the word is in dictionary or not
+ return mBigramList.containsKey(word);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
deleted file mode 100644
index 065e00e4a..000000000
--- a/java/src/com/android/inputmethod/latin/personalization/DynamicPredictionDictionaryBase.java
+++ /dev/null
@@ -1,402 +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 android.content.SharedPreferences;
-import android.os.AsyncTask;
-import android.util.Log;
-
-import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.ExpandableDictionary;
-import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.WordComposer;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
-import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
-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.BigramDictionaryInterface;
-import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener;
-import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
-import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * This class is a base class of a dictionary for the personalized prediction language model.
- */
-public abstract class DynamicPredictionDictionaryBase extends ExpandableDictionary {
-
- private static final String TAG = DynamicPredictionDictionaryBase.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 FormatOptions VERSION3 = new FormatOptions(3,
- true /* supportsDynamicUpdate */);
-
- /** Any pair being typed or picked */
- private static final int FREQUENCY_FOR_TYPED = 2;
-
- /** Maximum number of pairs. Pruning will start when databases goes above this number. */
- private static final int MAX_HISTORY_BIGRAMS = 10000;
-
- /** Locale for which this user history dictionary is storing words */
- private final String mLocale;
-
- private final UserHistoryDictionaryBigramList mBigramList =
- new UserHistoryDictionaryBigramList();
- private final ReentrantLock mBigramListLock = new ReentrantLock();
- 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 */ DynamicPredictionDictionaryBase(final Context context, final String locale,
- final SharedPreferences sp, final String dictionaryType) {
- super(context, dictionaryType);
- mLocale = locale;
- mPrefs = sp;
- if (mLocale != null && mLocale.length() > 1) {
- loadDictionary();
- }
- }
-
- @Override
- public void close() {
- flushPendingWrites();
- // Don't close the database as locale changes will require it to be reopened anyway
- // Also, the database is written to somewhat frequently, so it needs to be kept alive
- // throughout the life of the process.
- // mOpenHelper.close();
- // Ignore close because we cache PersonalizationPredictionDictionary for each language.
- // See getInstance() above.
- // super.close();
- }
-
- @Override
- protected ArrayList<SuggestedWordInfo> getWordsInner(final WordComposer composer,
- final String prevWord, final ProximityInfo proximityInfo) {
- // Inhibit suggestions (not predictions) for user history for now. Removing this method
- // is enough to use it through the standard ExpandableDictionary way.
- return null;
- }
-
- /**
- * Return whether the passed charsequence is in the dictionary.
- */
- @Override
- public synchronized boolean isValidWord(final String word) {
- // TODO: figure out what is the correct thing to do here.
- return false;
- }
-
- /**
- * Pair will be added to the personalization prediction dictionary.
- *
- * The first word may be null. That means we don't know the context, in other words,
- * it's only a unigram. The first word may also be an empty string : this means start
- * context, as in beginning of a sentence for example.
- * The second word may not be null (a NullPointerException would be thrown).
- */
- public int addToPersonalizationPredictionDictionary(
- final String word1, final String word2, final boolean isValid) {
- if (word2.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
- (word1 != null && word1.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
- return -1;
- }
- if (mBigramListLock.tryLock()) {
- try {
- super.addWord(
- word2, null /* the "shortcut" parameter is null */, FREQUENCY_FOR_TYPED);
- mBigramList.addBigram(null, word2, (byte)FREQUENCY_FOR_TYPED);
- // Do not insert a word as a bigram of itself
- if (word2.equals(word1)) {
- return 0;
- }
- final int freq;
- if (null == word1) {
- freq = FREQUENCY_FOR_TYPED;
- } else {
- freq = super.setBigramAndGetFrequency(
- word1, word2, new ForgettingCurveParams(isValid));
- }
- mBigramList.addBigram(word1, word2);
- return freq;
- } finally {
- mBigramListLock.unlock();
- }
- }
- return -1;
- }
-
- public boolean cancelAddingUserHistory(final String word1, final String word2) {
- if (mBigramListLock.tryLock()) {
- try {
- if (mBigramList.removeBigram(word1, word2)) {
- return super.removeBigram(word1, word2);
- }
- } finally {
- mBigramListLock.unlock();
- }
- }
- return false;
- }
-
- /**
- * Schedules a background thread to write any pending words to the database.
- */
- private void flushPendingWrites() {
- // Create a background thread to write the pending entries
- new UpdateBinaryTask(mBigramList, mLocale, this, mPrefs, getContext()).execute();
- }
-
- @Override
- public final void loadDictionaryAsync() {
- // This must be run on non-main thread
- mBigramListLock.lock();
- try {
- loadDictionaryAsyncLocked();
- } finally {
- mBigramListLock.unlock();
- }
- }
-
- private void loadDictionaryAsyncLocked() {
- 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 boolean initializing = last == 0;
- final long now = System.currentTimeMillis();
- final String fileName = getDictionaryFileName();
- final ExpandableDictionary dictionary = this;
- final OnAddWordListener listener = new OnAddWordListener() {
- @Override
- public void setUnigram(final String word, final String shortcutTarget,
- final int frequency) {
- if (DBG_SAVE_RESTORE) {
- Log.d(TAG, "load unigram: " + word + "," + frequency);
- }
- dictionary.addWord(word, shortcutTarget, frequency);
- ++profTotalCount[0];
- addToBigramListLocked(null, word, (byte)frequency);
- }
-
- @Override
- public void setBigram(final String word1, final String word2, final int frequency) {
- if (word1.length() < Constants.DICTIONARY_MAX_WORD_LENGTH
- && word2.length() < Constants.DICTIONARY_MAX_WORD_LENGTH) {
- if (DBG_SAVE_RESTORE) {
- Log.d(TAG, "load bigram: " + word1 + "," + word2 + "," + frequency);
- }
- ++profTotalCount[0];
- dictionary.setBigramAndGetFrequency(
- word1, word2, initializing ? new ForgettingCurveParams(true)
- : new ForgettingCurveParams(frequency, now, last));
- }
- addToBigramListLocked(word1, word2, (byte)frequency);
- }
- };
-
- // Load the dictionary from binary file
- final BinaryDictReader reader = new BinaryDictReader(
- new File(getContext().getFilesDir(), fileName));
- try {
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
- UserHistoryDictIOUtils.readDictionaryBinary(reader, listener);
- } catch (FileNotFoundException e) {
- // This is an expected condition: we don't have a user history dictionary for this
- // language yet. It will be created sometime later.
- } catch (IOException e) {
- Log.e(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 abstract String getDictionaryFileName();
-
- protected String getLocale() {
- return mLocale;
- }
-
- private void addToBigramListLocked(String word0, String word1, byte fcValue) {
- mBigramList.addBigram(word0, word1, fcValue);
- }
-
- /**
- * Async task to write pending words to the binarydicts.
- */
- private static final class UpdateBinaryTask extends AsyncTask<Void, Void, Void>
- implements BigramDictionaryInterface {
- private final UserHistoryDictionaryBigramList mBigramList;
- private final boolean mAddLevel0Bigrams;
- private final String mLocale;
- private final DynamicPredictionDictionaryBase mDynamicPredictionDictionary;
- private final SharedPreferences mPrefs;
- private final Context mContext;
-
- public UpdateBinaryTask(final UserHistoryDictionaryBigramList pendingWrites,
- final String locale, final DynamicPredictionDictionaryBase dict,
- final SharedPreferences prefs, final Context context) {
- mBigramList = pendingWrites;
- mLocale = locale;
- mDynamicPredictionDictionary = dict;
- mPrefs = prefs;
- mContext = context;
- mAddLevel0Bigrams = mBigramList.size() <= MAX_HISTORY_BIGRAMS;
- }
-
- @Override
- protected Void doInBackground(final Void... v) {
- if (mDynamicPredictionDictionary.mIsTest) {
- // If mIsTest == true, wait until the lock is released.
- mDynamicPredictionDictionary.mBigramListLock.lock();
- try {
- doWriteTaskLocked();
- } finally {
- mDynamicPredictionDictionary.mBigramListLock.unlock();
- }
- } else if (mDynamicPredictionDictionary.mBigramListLock.tryLock()) {
- try {
- doWriteTaskLocked();
- } finally {
- mDynamicPredictionDictionary.mBigramListLock.unlock();
- }
- }
- return null;
- }
-
- private void doWriteTaskLocked() {
- if (DBG_STRESS_TEST) {
- try {
- Log.w(TAG, "Start stress in closing: " + mLocale);
- Thread.sleep(15000);
- Log.w(TAG, "End stress in closing");
- } catch (InterruptedException e) {
- Log.e(TAG, "In stress test", e);
- }
- }
-
- final long now = PROFILE_SAVE_RESTORE ? System.currentTimeMillis() : 0;
- final String fileName =
- mDynamicPredictionDictionary.getDictionaryFileName();
- final File file = new File(mContext.getFilesDir(), fileName);
- FileOutputStream out = null;
-
- try {
- out = new FileOutputStream(file);
- UserHistoryDictIOUtils.writeDictionaryBinary(out, this, mBigramList, VERSION3);
- out.flush();
- out.close();
- } catch (IOException e) {
- Log.e(TAG, "IO Exception while writing file", e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
-
- // Save the timestamp after we finish writing the binary dictionary.
- Settings.writeLastUserHistoryWriteTime(mPrefs, mLocale);
- if (PROFILE_SAVE_RESTORE) {
- final long diff = System.currentTimeMillis() - now;
- Log.w(TAG, "PROF: Write User HistoryDictionary: " + mLocale + ", " + diff + "ms.");
- }
- }
-
- @Override
- public int getFrequency(final String word1, final String word2) {
- final int freq;
- if (word1 == null) { // unigram
- freq = FREQUENCY_FOR_TYPED;
- final byte prevFc = mBigramList.getBigrams(word1).get(word2);
- } else { // bigram
- final NextWord nw =
- mDynamicPredictionDictionary.getBigramWord(word1, word2);
- if (nw != null) {
- final ForgettingCurveParams fcp = nw.getFcParams();
- final byte prevFc = mBigramList.getBigrams(word1).get(word2);
- final byte fc = fcp.getFc();
- final boolean isValid = fcp.isValid();
- if (prevFc > 0 && prevFc == fc) {
- freq = fc & 0xFF;
- } else if (UserHistoryForgettingCurveUtils.
- needsToSave(fc, isValid, mAddLevel0Bigrams)) {
- freq = fc & 0xFF;
- } else {
- // Delete this entry
- freq = -1;
- }
- } else {
- // Delete this entry
- freq = -1;
- }
- }
- return freq;
- }
- }
-
- @UsedForTesting
- /* package for test */ void forceAddWordForTest(
- final String word1, final String word2, final boolean isValid) {
- mBigramListLock.lock();
- try {
- addToPersonalizationPredictionDictionary(word1, word2, isValid);
- } finally {
- mBigramListLock.unlock();
- }
- }
-
- public void registerUpdateSession(PersonalizationDictionaryUpdateSession session) {
- session.setPredictionDictionary(mLocale, this);
- mSessions.add(session);
- session.onDictionaryReady();
- }
-
- public void unRegisterUpdateSession(PersonalizationDictionaryUpdateSession session) {
- mSessions.remove(session);
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
index e38a235e9..f257165cb 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
@@ -18,26 +18,32 @@ 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;
/**
* 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";
-
- public static void registerUpdateListener(PersonalizationDictionaryUpdateSession listener) {
- // TODO: Implement
- }
+ private final ArrayList<PersonalizationDictionaryUpdateSession> mSessions =
+ CollectionUtils.newArrayList();
/** Locale for which this user history dictionary is storing words */
private final String mLocale;
- // Singleton
- private PersonalizationDictionary(final Context context, final String locale) {
- super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_PERSONALIZATION);
+ 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();
}
@Override
@@ -47,15 +53,21 @@ public class PersonalizationDictionary extends ExpandableBinaryDictionary {
@Override
protected boolean hasContentChanged() {
- // TODO: Implement
return false;
}
@Override
protected boolean needsToReloadBeforeWriting() {
- // TODO: Implement
return false;
}
- // TODO: Implement
+ 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/PersonalizationDictionarySessionRegister.java
index 534d3c518..c1833ff14 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegister.java
@@ -25,4 +25,13 @@ public class PersonalizationDictionarySessionRegister {
public static void onConfigurationChanged(final Context context, final Configuration conf) {
}
+
+ public static void onUpdateData(Context context, String type) {
+ }
+
+ public static void onRemoveData(Context context, String type) {
+ }
+
+ public static void onDestroy(Context context) {
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
index a755f90d5..c616a296c 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdateSession.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin.personalization;
+import android.content.Context;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -43,36 +45,68 @@ public abstract class PersonalizationDictionaryUpdateSession {
}
// TODO: Use a dynamic binary dictionary instead
- public WeakReference<DynamicPredictionDictionaryBase> mPredictionDictionary;
- public String mLocale;
+ public WeakReference<PersonalizationDictionary> mDictionary;
+ public WeakReference<DecayingExpandableBinaryDictionaryBase> mPredictionDictionary;
+ public final String mSystemLocale;
+ public PersonalizationDictionaryUpdateSession(String locale) {
+ mSystemLocale = locale;
+ }
public abstract void onDictionaryReady();
- public void setPredictionDictionary(String locale, DynamicPredictionDictionaryBase dictionary) {
- mPredictionDictionary = new WeakReference<DynamicPredictionDictionaryBase>(dictionary);
- mLocale = locale;
+ 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 DynamicPredictionDictionaryBase getPredictionDictionary() {
+ 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 DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+ 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() {
+ 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 DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+ final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary();
if (dictionary == null) {
return;
}
@@ -80,9 +114,10 @@ public abstract class PersonalizationDictionaryUpdateSession {
}
// Bulk import
+ // TODO: Support multi locale to add bigram
public void addBigramsToPersonalizationDictionary(
final ArrayList<PersonalizationLanguageModelParam> lmParams) {
- final DynamicPredictionDictionaryBase dictionary = getPredictionDictionary();
+ final DecayingExpandableBinaryDictionaryBase dictionary = getPredictionDictionary();
if (dictionary == null) {
return;
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index b4fd25024..5f702ee3f 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -26,16 +26,20 @@ import android.util.Log;
import java.lang.ref.SoftReference;
import java.util.concurrent.ConcurrentHashMap;
-public class PersonalizationDictionaryHelper {
- private static final String TAG = PersonalizationDictionaryHelper.class.getSimpleName();
+public class PersonalizationHelper {
+ private static final String TAG = PersonalizationHelper.class.getSimpleName();
private static final boolean DEBUG = false;
private static final ConcurrentHashMap<String, SoftReference<UserHistoryPredictionDictionary>>
sLangUserHistoryDictCache = CollectionUtils.newConcurrentHashMap();
+ private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>>
+ sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap();
+
private static final ConcurrentHashMap<String,
SoftReference<PersonalizationPredictionDictionary>>
- sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap();
+ sLangPersonalizationPredictionDictCache =
+ CollectionUtils.newConcurrentHashMap();
public static UserHistoryPredictionDictionary getUserHistoryPredictionDictionary(
final Context context, final String locale, final SharedPreferences sp) {
@@ -48,6 +52,7 @@ public class PersonalizationDictionaryHelper {
if (DEBUG) {
Log.w(TAG, "Use cached UserHistoryPredictionDictionary for " + locale);
}
+ dict.reloadDictionaryIfRequired();
return dict;
}
}
@@ -60,20 +65,45 @@ public class PersonalizationDictionaryHelper {
}
public static void registerPersonalizationDictionaryUpdateSession(final Context context,
- final PersonalizationDictionaryUpdateSession session) {
- final PersonalizationPredictionDictionary dictionary =
- getPersonalizationPredictionDictionary(context,
- context.getResources().getConfiguration().locale.toString(),
+ 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 PersonalizationPredictionDictionary getPersonalizationPredictionDictionary(
+ public static PersonalizationDictionary getPersonalizationDictionary(
final Context context, final String locale, final SharedPreferences sp) {
synchronized (sLangPersonalizationDictCache) {
if (sLangPersonalizationDictCache.containsKey(locale)) {
- final SoftReference<PersonalizationPredictionDictionary> ref =
+ final SoftReference<PersonalizationDictionary> ref =
sLangPersonalizationDictCache.get(locale);
+ final PersonalizationDictionary dict = ref == null ? null : ref.get();
+ if (dict != null) {
+ if (DEBUG) {
+ Log.w(TAG, "Use cached PersonalizationDictCache for " + locale);
+ }
+ return dict;
+ }
+ }
+ final PersonalizationDictionary dict =
+ new PersonalizationDictionary(context, locale, sp);
+ sLangPersonalizationDictCache.put(
+ locale, 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) {
@@ -84,7 +114,7 @@ public class PersonalizationDictionaryHelper {
}
final PersonalizationPredictionDictionary dict =
new PersonalizationPredictionDictionary(context, locale, sp);
- sLangPersonalizationDictCache.put(
+ sLangPersonalizationPredictionDictCache.put(
locale, new SoftReference<PersonalizationPredictionDictionary>(dict));
return dict;
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java
index 955bd2762..432954453 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationPredictionDictionary.java
@@ -17,20 +17,21 @@
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 DynamicPredictionDictionaryBase {
+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);
+ super(context, locale, sp, Dictionary.TYPE_PERSONALIZATION_PREDICTION_IN_JAVA,
+ getDictionaryFileName(locale));
}
- @Override
- protected String getDictionaryFileName() {
- return NAME + "." + getLocale() + ".dict";
+ private static String getDictionaryFileName(final String locale) {
+ return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
}
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
index 9f289e9ff..55a90ee51 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryBigramList.java
@@ -45,6 +45,7 @@ public final class UserHistoryDictionaryBigramList {
/**
* Called when the user typed a word.
*/
+ @UsedForTesting
public void addBigram(String word1, String word2) {
addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE);
}
@@ -53,7 +54,7 @@ public final class UserHistoryDictionaryBigramList {
* Called when loaded from the SQL DB.
*/
public void addBigram(String word1, String word2, byte fcValue) {
- if (DynamicPredictionDictionaryBase.DBG_SAVE_RESTORE) {
+ if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) {
Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue);
}
final HashMap<String, Byte> map;
@@ -73,7 +74,7 @@ public final class UserHistoryDictionaryBigramList {
* Called when inserted to the SQL DB.
*/
public void updateBigram(String word1, String word2, byte fcValue) {
- if (DynamicPredictionDictionaryBase.DBG_SAVE_RESTORE) {
+ if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) {
Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue);
}
final HashMap<String, Byte> map;
@@ -96,6 +97,10 @@ public final class UserHistoryDictionaryBigramList {
return mBigramMap.isEmpty();
}
+ public boolean containsKey(String word) {
+ return mBigramMap.containsKey(word);
+ }
+
public Set<String> keySet() {
return mBigramMap.keySet();
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryPredictionDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryPredictionDictionary.java
index d11784454..38e308a4e 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryPredictionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryPredictionDictionary.java
@@ -17,6 +17,7 @@
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;
@@ -25,15 +26,15 @@ import android.content.SharedPreferences;
* 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 UserHistoryPredictionDictionary extends DynamicPredictionDictionaryBase {
- private static final String NAME = UserHistoryPredictionDictionary.class.getSimpleName();
+public class UserHistoryPredictionDictionary extends DecayingExpandableBinaryDictionaryBase {
+ /* package for tests */ static final String NAME =
+ UserHistoryPredictionDictionary.class.getSimpleName();
/* package */ UserHistoryPredictionDictionary(final Context context, final String locale,
final SharedPreferences sp) {
- super(context, locale, sp, Dictionary.TYPE_USER_HISTORY);
+ super(context, locale, sp, Dictionary.TYPE_USER_HISTORY, getDictionaryFileName(locale));
}
- @Override
- protected String getDictionaryFileName() {
- return NAME + "." + getLocale() + ".dict";
+ private static String getDictionaryFileName(final String locale) {
+ return NAME + "." + locale + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java b/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
index 139f5e290..6543003e8 100644
--- a/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
+++ b/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
@@ -40,8 +40,4 @@ public class AdditionalFeaturesSettingUtils {
final SharedPreferences prefs, final int[] additionalFeaturesPreferences) {
// do nothing.
}
-
- public static int[] getAdditionalNativeSuggestOptions() {
- return Settings.getInstance().getCurrent().mAdditionalFeaturesSettingValues;
- }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index b1cd88729..1b592b565 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -39,6 +39,8 @@ 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";
private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary";
private static final boolean SHOW_STATISTICS_LOGGING = false;
diff --git a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java b/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
index 878c505bd..cd726c969 100644
--- a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
+++ b/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
@@ -34,6 +34,9 @@ public class NativeSuggestOptions {
}
public void setAdditionalFeaturesOptions(final int[] additionalOptions) {
+ if (additionalOptions == null) {
+ return;
+ }
for (int i = 0; i < additionalOptions.length; i++) {
setIntegerOption(OPTIONS_SIZE + i, additionalOptions[i]);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index d432087d3..1a0fecc62 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -27,10 +27,10 @@ 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.DebugLogUtils;
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.Locale;
@@ -44,7 +44,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_VIBRATE_ON = "vibrate_on";
public static final String PREF_SOUND_ON = "sound_on";
public static final String PREF_POPUP_ON = "popup_on";
- public static final String PREF_VOICE_MODE = "voice_mode";
+ // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead.
+ public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode";
+ public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key";
public static final String PREF_CORRECTION_SETTINGS = "correction_settings";
public static final String PREF_EDIT_PERSONAL_DICTIONARY = "edit_personal_dictionary";
public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key";
@@ -79,6 +81,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT =
"pref_gesture_floating_preview_text";
public static final String PREF_SHOW_SETUP_WIZARD_ICON = "pref_show_setup_wizard_icon";
+ public static final String PREF_PHRASE_GESTURE_ENABLED = "pref_gesture_space_aware";
public static final String PREF_INPUT_LANGUAGE = "input_language";
public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
@@ -90,9 +93,15 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY =
"pref_suppress_language_switch_key";
+ private static final String PREF_LAST_USED_PERSONALIZATION_TOKEN =
+ "pref_last_used_personalization_token";
public static final String PREF_SEND_FEEDBACK = "send_feedback";
public static final String PREF_ABOUT_KEYBOARD = "about_keyboard";
+ // Emoji
+ public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
+ public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
+
private Resources mRes;
private SharedPreferences mPrefs;
private SettingsValues mSettingsValues;
@@ -212,6 +221,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
&& prefs.getBoolean(Settings.PREF_GESTURE_INPUT, true);
}
+ public static boolean readPhraseGestureEnabled(final SharedPreferences prefs,
+ final Resources res) {
+ return prefs.getBoolean(Settings.PREF_PHRASE_GESTURE_ENABLED,
+ res.getBoolean(R.bool.config_default_phrase_gesture_enabled));
+ }
+
public static boolean readFromBuildConfigIfToShowKeyPreviewPopupSettingsOption(
final Resources res) {
return res.getBoolean(R.bool.config_enable_show_option_of_key_preview_popup);
@@ -343,4 +358,40 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
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();
+ }
+
+ public byte[] readLastUsedPersonalizationToken() {
+ final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null);
+ return StringUtils.hexStringToByteArray(tokenStr);
+ }
+
+ public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) {
+ prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply();
+ }
+
+ public static String readEmojiRecentKeys(final SharedPreferences prefs) {
+ return prefs.getString(PREF_EMOJI_RECENT_KEYS, "");
+ }
+
+ public static void writeEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category, final int id) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ prefs.edit().putInt(key, id).apply();
+ }
+
+ public static int readEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ return prefs.getInt(key, 0);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 1677e1828..cb7dda655 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -61,7 +61,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment
DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS
|| Build.VERSION.SDK_INT <= 18 /* Build.VERSION.JELLY_BEAN_MR2 */;
- private ListPreference mVoicePreference;
+ private CheckBoxPreference mVoiceInputKeyPreference;
private ListPreference mShowCorrectionSuggestionsPreference;
private ListPreference mAutoCorrectionThresholdPreference;
private ListPreference mKeyPreviewPopupDismissDelay;
@@ -107,7 +107,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment
SubtypeLocaleUtils.init(context);
AudioAndHapticFeedbackManager.init(context);
- mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE);
+ mVoiceInputKeyPreference =
+ (CheckBoxPreference) findPreference(Settings.PREF_VOICE_INPUT_KEY);
mShowCorrectionSuggestionsPreference =
(ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING);
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
@@ -166,7 +167,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final boolean showVoiceKeyOption = res.getBoolean(
R.bool.config_enable_show_voice_key_option);
if (!showVoiceKeyOption) {
- generalSettings.removePreference(mVoicePreference);
+ generalSettings.removePreference(mVoiceInputKeyPreference);
}
final PreferenceGroup advancedSettings =
@@ -243,10 +244,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment
public void onResume() {
super.onResume();
final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
- if (isShortcutImeEnabled) {
- updateVoiceModeSummary();
- } else {
- getPreferenceScreen().removePreference(mVoicePreference);
+ if (!isShortcutImeEnabled) {
+ getPreferenceScreen().removePreference(mVoiceInputKeyPreference);
}
final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
final CheckBoxPreference showSetupWizardIcon =
@@ -287,7 +286,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment
LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity());
}
ensureConsistencyOfAutoCorrectionSettings();
- updateVoiceModeSummary();
updateShowCorrectionSuggestionsSummary();
updateKeyPreviewPopupDelaySummary();
refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
@@ -330,12 +328,6 @@ public final class SettingsFragment extends InputMethodSettingsFragment
lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]);
}
- private void updateVoiceModeSummary() {
- mVoicePreference.setSummary(
- getResources().getStringArray(R.array.voice_input_modes_summary)
- [mVoicePreference.findIndexOfValue(mVoicePreference.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 195f9f8ef..ee322e91b 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -57,13 +57,14 @@ public final class SettingsValues {
public final SuggestedWords mSuggestPuncList;
public final String mWordSeparators;
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 String mVoiceMode;
+ private final boolean mShowsVoiceInputKey;
public final boolean mIncludesOtherImesInLanguageSwitchList;
public final boolean mShowsLanguageSwitchKey;
public final boolean mUseContactsDict;
@@ -75,6 +76,7 @@ public final class SettingsValues {
public final boolean mGestureTrailEnabled;
public final boolean mGestureFloatingPreviewTextEnabled;
public final boolean mSlidingKeyInputPreviewEnabled;
+ public final boolean mPhraseGestureEnabled;
public final int mKeyLongpressTimeout;
public final Locale mLocale;
@@ -89,8 +91,8 @@ public final class SettingsValues {
public final float mAutoCorrectionThreshold;
public final boolean mCorrectionEnabled;
public final int mSuggestionVisibility;
- private final boolean mVoiceKeyEnabled;
- private final boolean mVoiceKeyOnMain;
+ public final boolean mBoostPersonalizationDictionaryForDebug;
+ public final boolean mUseOnlyPersonalizationDictionaryForDebug;
// Setting values for additional features
public final int[] mAdditionalFeaturesSettingValues =
@@ -118,6 +120,7 @@ public final class SettingsValues {
mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
mWordSeparators = res.getString(R.string.symbols_word_separators);
mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
+ mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
// Store the input attributes
if (null == inputAttributes) {
@@ -133,9 +136,7 @@ public final class SettingsValues {
mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res);
mSlidingKeyInputPreviewEnabled = prefs.getBoolean(
Settings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
- final String voiceModeMain = res.getString(R.string.voice_mode_main);
- final String voiceModeOff = res.getString(R.string.voice_mode_off);
- mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain);
+ mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res);
final String autoCorrectionThresholdRawValue = prefs.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
res.getString(R.string.auto_correction_threshold_mode_index_modest));
@@ -155,12 +156,11 @@ public final class SettingsValues {
mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res);
mAutoCorrectionThreshold = readAutoCorrectionThreshold(res,
autoCorrectionThresholdRawValue);
- mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
- mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
mGestureFloatingPreviewTextEnabled = prefs.getBoolean(
Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true);
+ mPhraseGestureEnabled = Settings.readPhraseGestureEnabled(prefs, res);
mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect;
final String showSuggestionsSetting = prefs.getString(
Settings.PREF_SHOW_SUGGESTIONS_SETTING,
@@ -169,6 +169,10 @@ public final class SettingsValues {
AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray(
prefs, mAdditionalFeaturesSettingValues);
mIsInternal = Settings.isInternal(prefs);
+ mBoostPersonalizationDictionaryForDebug =
+ Settings.readBoostPersonalizationDictionaryForDebug(prefs);
+ mUseOnlyPersonalizationDictionaryForDebug =
+ Settings.readUseOnlyPersonalizationDictionaryForDebug(prefs);
}
// Only for tests
@@ -186,13 +190,14 @@ public final class SettingsValues {
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;
- mVoiceMode = "0";
+ mShowsVoiceInputKey = true;
mIncludesOtherImesInLanguageSwitchList = false;
mShowsLanguageSwitchKey = true;
mUseContactsDict = true;
@@ -205,14 +210,15 @@ public final class SettingsValues {
mKeypressSoundVolume = 1;
mKeyPreviewPopupDismissDelay = 70;
mAutoCorrectionThreshold = 1;
- mVoiceKeyEnabled = true;
- mVoiceKeyOnMain = true;
mGestureInputEnabled = true;
mGestureTrailEnabled = true;
mGestureFloatingPreviewTextEnabled = true;
+ mPhraseGestureEnabled = true;
mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect;
mSuggestionVisibility = 0;
mIsInternal = false;
+ mBoostPersonalizationDictionaryForDebug = false;
+ mUseOnlyPersonalizationDictionaryForDebug = false;
}
@UsedForTesting
@@ -263,14 +269,10 @@ public final class SettingsValues {
public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) {
final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
final int inputType = (editorInfo != null) ? editorInfo.inputType : 0;
- return shortcutImeEnabled && mVoiceKeyEnabled
+ return shortcutImeEnabled && mShowsVoiceInputKey
&& !InputTypeUtils.isPasswordInputType(inputType);
}
- public boolean isVoiceKeyOnMain() {
- return mVoiceKeyOnMain;
- }
-
public boolean isLanguageSwitchKeyEnabled() {
if (!mShowsLanguageSwitchKey) {
return false;
@@ -295,7 +297,9 @@ public final class SettingsValues {
// TODO: Stop using KeySpceParser.getLabel().
puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
- Dictionary.TYPE_HARDCODED));
+ Dictionary.DICTIONARY_HARDCODED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
}
return new SuggestedWords(puncList,
@@ -360,4 +364,18 @@ 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();
+ }
+ return prefs.getBoolean(Settings.PREF_VOICE_INPUT_KEY, true);
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 6719e98da..69f9a467f 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -301,12 +301,14 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
// TODO: make a spell checker option to block offensive words or not
final ArrayList<SuggestedWordInfo> suggestions =
dictInfo.mDictionary.getSuggestions(composer, prevWord,
- dictInfo.getProximityInfo(),
- true /* blockOffensiveWords */);
- for (final SuggestedWordInfo suggestion : suggestions) {
- final String suggestionStr = suggestion.mWord;
- suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
- suggestionStr.length(), suggestion.mScore);
+ dictInfo.getProximityInfo(), true /* blockOffensiveWords */,
+ null /* additionalFeaturesOptions */);
+ if (suggestions != null) {
+ for (final SuggestedWordInfo suggestion : suggestions) {
+ final String suggestionStr = suggestion.mWord;
+ suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
+ suggestionStr.length(), suggestion.mScore);
+ }
}
isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType);
} finally {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index ac8f68781..a0aed2829 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -52,7 +52,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo,
- final boolean blockOffensiveWords) {
+ final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return noSuggestions;
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index d585b5c7f..0ebe37782 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -34,7 +34,7 @@ public final class MoreSuggestionsView extends MoreKeysKeyboardView {
private static final String TAG = MoreSuggestionsView.class.getSimpleName();
public MoreSuggestionsView(final Context context, final AttributeSet attrs) {
- this(context, attrs, R.attr.moreSuggestionsViewStyle);
+ this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
}
public MoreSuggestionsView(final Context context, final AttributeSet attrs,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index bcf64a8e8..8d2689a7d 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -122,27 +122,15 @@ final class SuggestionStripLayoutHelper {
mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height);
final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle);
+ R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripView);
mSuggestionStripOption = a.getInt(
R.styleable.SuggestionStripView_suggestionStripOption, 0);
- final float alphaValidTypedWord = ResourceUtils.getFraction(a,
- R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f);
- final float alphaTypedWord = ResourceUtils.getFraction(a,
- R.styleable.SuggestionStripView_alphaTypedWord, 1.0f);
- final float alphaAutoCorrect = ResourceUtils.getFraction(a,
- R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f);
- final float alphaSuggested = ResourceUtils.getFraction(a,
- R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
mAlphaObsoleted = ResourceUtils.getFraction(a,
- R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
- mColorValidTypedWord = applyAlpha(a.getColor(
- R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord);
- mColorTypedWord = applyAlpha(a.getColor(
- R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord);
- mColorAutoCorrect = applyAlpha(a.getColor(
- R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect);
- mColorSuggested = applyAlpha(a.getColor(
- R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested);
+ R.styleable.SuggestionStripView_alphaObsoleted, 1.0f);
+ mColorValidTypedWord = a.getColor(R.styleable.SuggestionStripView_colorValidTypedWord, 0);
+ mColorTypedWord = a.getColor(R.styleable.SuggestionStripView_colorTypedWord, 0);
+ mColorAutoCorrect = a.getColor(R.styleable.SuggestionStripView_colorAutoCorrect, 0);
+ mColorSuggested = a.getColor(R.styleable.SuggestionStripView_colorSuggested, 0);
mSuggestionsCountInStrip = a.getInt(
R.styleable.SuggestionStripView_suggestionsCountInStrip,
DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
@@ -177,9 +165,20 @@ final class SuggestionStripLayoutHelper {
return mMaxMoreSuggestionsRow;
}
- public void setMoreSuggestionsHeight(final int remainingHeight) {
+ private int getMoreSuggestionsHeight() {
+ return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
+ }
+
+ public int setMoreSuggestionsHeight(final int remainingHeight) {
+ final int currentHeight = getMoreSuggestionsHeight();
+ if (currentHeight <= remainingHeight) {
+ return currentHeight;
+ }
+
mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
/ mMoreSuggestionsRowHeight;
+ final int newHeight = getMoreSuggestionsHeight();
+ return newHeight;
}
private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index badc942b9..75f17c559 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -135,8 +135,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
}
}
- public void setMoreSuggestionsHeight(final int remainingHeight) {
- mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
+ public int setMoreSuggestionsHeight(final int remainingHeight) {
+ return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
}
public boolean isShowingAddToDictionaryHint() {
diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
index 215faa0c7..44b201642 100644
--- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
@@ -25,6 +25,7 @@ import android.os.Build;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import java.util.ArrayList;
@@ -60,9 +61,10 @@ public final class AdditionalSubtypeUtils {
StringUtils.appendToCommaSplittableTextIfNotExists(
IS_ADDITIONAL_SUBTYPE, layoutDisplayNameExtraValue);
final int nameId = SubtypeLocaleUtils.getSubtypeNameId(localeString, keyboardLayoutSetName);
- return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard,
- localeString, KEYBOARD_MODE,
- layoutExtraValue + "," + additionalSubtypeExtraValue, false, false);
+ return new InputMethodSubtype(nameId, R.drawable.ic_ime_switcher_dark,
+ localeString, KEYBOARD_MODE, layoutExtraValue + "," + additionalSubtypeExtraValue
+ + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
+ + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE, false, false);
}
public static String getPrefSubtype(final InputMethodSubtype subtype) {
diff --git a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
new file mode 100644
index 000000000..c2e97a36f
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
@@ -0,0 +1,71 @@
+/*
+ * 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.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class is a holder of a result of asynchronous computation.
+ *
+ * @param <E> the type of the result.
+ */
+public class AsyncResultHolder<E> {
+
+ private final Object mLock = new Object();
+
+ private E mResult;
+ private final CountDownLatch mLatch;
+
+ public AsyncResultHolder() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Sets the result value to this holder.
+ *
+ * @param result the value which is set.
+ */
+ public void set(final E result) {
+ synchronized(mLock) {
+ if (mLatch.getCount() > 0) {
+ mResult = result;
+ mLatch.countDown();
+ }
+ }
+ }
+
+ /**
+ * Gets the result value held in this holder.
+ * 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.
+ */
+ public E get(final E defaultValue, final long timeOut) {
+ try {
+ if(mLatch.await(timeOut, TimeUnit.MILLISECONDS)) {
+ return mResult;
+ } else {
+ return defaultValue;
+ }
+ } catch (InterruptedException e) {
+ return defaultValue;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java b/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
index d93b61451..2028298f2 100644
--- a/java/src/com/android/inputmethod/latin/utils/ByteArrayWrapper.java
+++ b/java/src/com/android/inputmethod/latin/utils/ByteArrayDictBuffer.java
@@ -16,17 +16,17 @@
package com.android.inputmethod.latin.utils;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
/**
* This class provides an implementation for the FusionDictionary buffer interface that is backed
* by a simpled byte array. It allows to create a binary dictionary in memory.
*/
-public final class ByteArrayWrapper implements FusionDictionaryBufferInterface {
+public final class ByteArrayDictBuffer implements DictBuffer {
private byte[] mBuffer;
private int mPosition;
- public ByteArrayWrapper(final byte[] buffer) {
+ public ByteArrayDictBuffer(final byte[] buffer) {
mBuffer = buffer;
mPosition = 0;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
index 2f91c5743..60b24d5d5 100644
--- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
@@ -60,6 +60,11 @@ public final class CapsModeUtils {
|| WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode;
}
+ private static boolean isPeriod(final int codePoint) {
+ // TODO: make this a resource.
+ return codePoint == Constants.CODE_PERIOD || codePoint == Constants.CODE_ARMENIAN_PERIOD;
+ }
+
/**
* Determine what caps mode should be in effect at the current offset in
* the text. Only the mode bits set in <var>reqModes</var> will be
@@ -190,7 +195,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 (c != Constants.CODE_PERIOD || j <= 0) {
+ if (!isPeriod(c) || j <= 0) {
return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes;
}
@@ -240,7 +245,7 @@ public final class CapsModeUtils {
case WORD:
if (Character.isLetter(c)) {
state = WORD;
- } else if (c == Constants.CODE_PERIOD) {
+ } else if (isPeriod(c)) {
state = PERIOD;
} else {
return caps;
@@ -256,7 +261,7 @@ public final class CapsModeUtils {
case LETTER:
if (Character.isLetter(c)) {
state = LETTER;
- } else if (c == Constants.CODE_PERIOD) {
+ } else if (isPeriod(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 98f0d8b68..cc25102ce 100644
--- a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.utils;
import android.util.SparseArray;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -94,6 +95,10 @@ public final class CollectionUtils {
return new CopyOnWriteArrayList<E>(array);
}
+ public static <E> ArrayDeque<E> newArrayDeque() {
+ return new ArrayDeque<E>();
+ }
+
public static <E> SparseArray<E> newSparseArray() {
return new SparseArray<E>();
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
index c4ead0ad1..ac654fa65 100644
--- a/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DebugLogUtils.java
@@ -65,12 +65,12 @@ public final class DebugLogUtils {
/**
* Get the stack trace contained in an exception as a human-readable string.
- * @param e the exception
+ * @param t the throwable
* @return the human-readable stack trace
*/
- public static String getStackTrace(final Exception e) {
+ public static String getStackTrace(final Throwable t) {
final StringBuilder sb = new StringBuilder();
- final StackTraceElement[] frames = e.getStackTrace();
+ final StackTraceElement[] frames = t.getStackTrace();
for (int j = 0; j < frames.length; ++j) {
sb.append(frames[j].toString() + "\n");
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 34eccd65b..021bf0825 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -27,10 +27,8 @@ import com.android.inputmethod.latin.BinaryDictionaryGetter;
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.UnsupportedFormatException;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
@@ -281,13 +279,7 @@ public class DictionaryInfoUtils {
}
public static FileHeader getDictionaryFileHeaderOrNull(final File file) {
- try {
- return BinaryDictIOUtils.getDictionaryFileHeader(file, 0, file.length());
- } catch (UnsupportedFormatException e) {
- return null;
- } catch (IOException e) {
- return null;
- }
+ return BinaryDictIOUtils.getDictionaryFileHeaderOrNull(file, 0, file.length());
}
private static DictionaryInfo createDictionaryInfoFromFileAddress(
diff --git a/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
deleted file mode 100644
index 1fc7eccc6..000000000
--- a/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
+++ /dev/null
@@ -1,108 +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.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.latin.RichInputConnection;
-
-import java.util.Locale;
-
-/**
- * Holder class for data about a word already committed but that may still be edited.
- *
- * When the user chooses to add a word to the user dictionary by pressing the appropriate
- * suggestion, a dialog is presented to give a chance to edit the word before it is actually
- * registered as a user dictionary word. If the word is actually modified, the IME needs to
- * go back and replace the word that was committed with the amended version.
- * The word we need to replace with will only be known after it's actually committed, so
- * the IME needs to take a note of what it has to replace and where it is.
- * This class encapsulates this data.
- */
-public final class PositionalInfoForUserDictPendingAddition {
- final private String mOriginalWord;
- final private int mCursorPos; // Position of the cursor after the word
- final private EditorInfo mEditorInfo; // On what binding this has been added
- final private int mCapitalizedMode;
- private String mActualWordBeingAdded;
-
- public PositionalInfoForUserDictPendingAddition(final String word, final int cursorPos,
- final EditorInfo editorInfo, final int capitalizedMode) {
- mOriginalWord = word;
- mCursorPos = cursorPos;
- mEditorInfo = editorInfo;
- mCapitalizedMode = capitalizedMode;
- }
-
- public void setActualWordBeingAdded(final String actualWordBeingAdded) {
- mActualWordBeingAdded = actualWordBeingAdded;
- }
-
- /**
- * Try to replace the string at the remembered position with the actual word being added.
- *
- * After the user validated the word being added, the IME has to replace the old version
- * (which has been committed in the text view) with the amended version if it's different.
- * This method tries to do that, but may fail because the IME is not yet ready to do so -
- * for example, it is still waiting for the new string, or it is waiting to return to the text
- * view in which the amendment should be made. In these cases, we should keep the data
- * and wait until all conditions are met.
- * This method returns true if the replacement has been successfully made and this data
- * can be forgotten; it returns false if the replacement can't be made yet and we need to
- * keep this until a later time.
- * The IME knows about the actual word being added through a callback called by the
- * user dictionary facility of the device. When this callback comes, the keyboard may still
- * be connected to the edition dialog, or it may have already returned to the original text
- * field. Replacement has to work in both cases.
- * Accordingly, this method is called at two different points in time : upon getting the
- * event that a new word was added to the user dictionary, and upon starting up in a
- * new text field.
- * @param connection The RichInputConnection through which to contact the editor.
- * @param editorInfo Information pertaining to the editor we are currently in.
- * @param currentCursorPosition The current cursor position, for checking purposes.
- * @param locale The locale for changing case, if necessary
- * @return true if the edit has been successfully made, false if we need to try again later
- */
- public boolean tryReplaceWithActualWord(final RichInputConnection connection,
- final EditorInfo editorInfo, final int currentCursorPosition, final Locale locale) {
- // If we still don't know the actual word being added, we need to try again later.
- if (null == mActualWordBeingAdded) return false;
- // The entered text and the registered text were the same anyway : we can
- // return success right away even if focus has not returned yet to the text field we
- // want to amend.
- if (mActualWordBeingAdded.equals(mOriginalWord)) return true;
- // Not the same text field : we need to try again later. This happens when the addition
- // is reported by the user dictionary provider before the focus has moved back to the
- // original text view, so the IME is still in the text view of the dialog and has no way to
- // edit the original text view at this time.
- if (!mEditorInfo.packageName.equals(editorInfo.packageName)
- || mEditorInfo.fieldId != editorInfo.fieldId) {
- return false;
- }
- // Same text field, but not the same cursor position : we give up, so we return success
- // so that it won't be tried again
- if (currentCursorPosition != mCursorPos) return true;
- // We have made all the checks : do the replacement and report success
- // If this was auto-capitalized, we need to restore the case before committing
- final String wordWithCaseFixed = CapsModeUtils.applyAutoCapsMode(mActualWordBeingAdded,
- mCapitalizedMode, locale);
- connection.setComposingRegion(currentCursorPosition - mOriginalWord.length(),
- currentCursorPosition);
- connection.commitText(wordWithCaseFixed, wordWithCaseFixed.length());
- return true;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
new file mode 100644
index 000000000..5dc0b5893
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
@@ -0,0 +1,147 @@
+/*
+ * 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.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * An object that executes submitted tasks using a thread.
+ */
+public class PrioritizedSerialExecutor {
+ public static final String TAG = PrioritizedSerialExecutor.class.getSimpleName();
+
+ private final Object mLock = new Object();
+
+ // The default value of capacities of task queues.
+ private static final int TASK_QUEUE_CAPACITY = 1000;
+ private final Queue<Runnable> mTasks;
+ private final Queue<Runnable> mPrioritizedTasks;
+ private boolean mIsShutdown;
+
+ // The task which is running now.
+ private Runnable mActive;
+
+ public PrioritizedSerialExecutor() {
+ mTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+ mPrioritizedTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+ mIsShutdown = false;
+ }
+
+ /**
+ * Clears all queued tasks.
+ */
+ public void clearAllTasks() {
+ synchronized(mLock) {
+ mTasks.clear();
+ mPrioritizedTasks.clear();
+ }
+ }
+
+ /**
+ * Enqueues the given task into the task queue.
+ * @param r the enqueued task
+ */
+ public void execute(final Runnable r) {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ mTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+ }
+ }
+
+ /**
+ * Enqueues the given task into the prioritized task queue.
+ * @param r the enqueued task
+ */
+ public void executePrioritized(final Runnable r) {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ mPrioritizedTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+ }
+ }
+
+ private boolean fetchNextTasks() {
+ synchronized(mLock) {
+ mActive = mPrioritizedTasks.poll();
+ if (mActive == null) {
+ mActive = mTasks.poll();
+ }
+ return mActive != null;
+ }
+ }
+
+ private void scheduleNext() {
+ synchronized(mLock) {
+ if (!fetchNextTasks()) {
+ return;
+ }
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ do {
+ synchronized(mLock) {
+ if (mActive != null) {
+ mActive.run();
+ }
+ }
+ } while (fetchNextTasks());
+ } finally {
+ scheduleNext();
+ }
+ }
+ }).start();
+ }
+ }
+
+ public void remove(final Runnable r) {
+ synchronized(mLock) {
+ mTasks.remove(r);
+ mPrioritizedTasks.remove(r);
+ }
+ }
+
+ public void replaceAndExecute(final Runnable oldTask, final Runnable newTask) {
+ synchronized(mLock) {
+ if (oldTask != null) remove(oldTask);
+ execute(newTask);
+ }
+ }
+
+ public void shutdown() {
+ synchronized(mLock) {
+ mIsShutdown = true;
+ }
+ }
+
+ public boolean isTerminated() {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ return false;
+ }
+ return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
index 4c7739a7a..7c6fe93ac 100644
--- a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
@@ -132,6 +132,15 @@ public final class ResizableIntArray {
}
}
+ /**
+ * Shift to the left by elementCount, discarding elementCount pointers at the start.
+ * @param elementCount how many elements to shift.
+ */
+ public void shift(final int elementCount) {
+ System.arraycopy(mArray, elementCount, mArray, 0, mLength - elementCount);
+ mLength -= elementCount;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java
new file mode 100644
index 000000000..b51fd9377
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java
@@ -0,0 +1,110 @@
+/*
+ * 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.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.TextUtils;
+import android.text.style.SuggestionSpan;
+
+public final class SpannableStringUtils {
+ /**
+ * Copies the spans from the region <code>start...end</code> in
+ * <code>source</code> to the region
+ * <code>destoff...destoff+end-start</code> in <code>dest</code>.
+ * Spans in <code>source</code> that begin before <code>start</code>
+ * or end after <code>end</code> but overlap this range are trimmed
+ * as if they began at <code>start</code> or ended at <code>end</code>.
+ * Only SuggestionSpans that don't have the SPAN_PARAGRAPH span are copied.
+ *
+ * This code is almost entirely taken from {@link TextUtils#copySpansFrom}, except for the
+ * kind of span that is copied.
+ *
+ * @throws IndexOutOfBoundsException if any of the copied spans
+ * are out of range in <code>dest</code>.
+ */
+ public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end,
+ 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;
+
+ int st = source.getSpanStart(spans[i]);
+ int en = source.getSpanEnd(spans[i]);
+
+ if (st < start)
+ st = start;
+ if (en > end)
+ en = end;
+
+ dest.setSpan(spans[i], st - start + destoff, en - start + destoff,
+ fl);
+ }
+ }
+
+ /**
+ * Returns a CharSequence concatenating the specified CharSequences, retaining their
+ * SuggestionSpans that don't have the PARAGRAPH flag, but not other spans.
+ *
+ * This code is almost entirely taken from {@link TextUtils#concat(CharSequence...)}, except
+ * it calls copyNonParagraphSuggestionSpansFrom instead of {@link TextUtils#copySpansFrom}.
+ */
+ public static CharSequence concatWithNonParagraphSuggestionSpansOnly(CharSequence... text) {
+ if (text.length == 0) {
+ return "";
+ }
+
+ if (text.length == 1) {
+ return text[0];
+ }
+
+ boolean spanned = false;
+ for (int i = 0; i < text.length; i++) {
+ if (text[i] instanceof Spanned) {
+ spanned = true;
+ break;
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < text.length; i++) {
+ sb.append(text[i]);
+ }
+
+ if (!spanned) {
+ return sb.toString();
+ }
+
+ SpannableString ss = new SpannableString(sb);
+ int off = 0;
+ for (int i = 0; i < text.length; i++) {
+ int len = text[i].length();
+
+ if (text[i] instanceof Spanned) {
+ copyNonParagraphSuggestionSpansFrom((Spanned) text[i], 0, len, ss, off);
+ }
+
+ off += len;
+ }
+
+ return new SpannedString(ss);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 0b4838cfc..121aecf0f 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -16,16 +16,25 @@
package com.android.inputmethod.latin.utils;
-import android.text.TextUtils;
-
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.settings.SettingsValues;
+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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Locale;
public final class StringUtils {
+ private static final String TAG = StringUtils.class.getSimpleName();
public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case
public static final int CAPITALIZE_FIRST = 1; // First only
public static final int CAPITALIZE_ALL = 2; // All caps
@@ -357,4 +366,100 @@ public final class StringUtils {
}
return true;
}
+
+ @UsedForTesting
+ public static String byteArrayToHexString(byte[] bytes) {
+ if (bytes == null || bytes.length == 0) {
+ return "";
+ }
+ final StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Convert hex string to byte array. The string length must be an even number.
+ */
+ @UsedForTesting
+ public static byte[] hexStringToByteArray(String hexString) {
+ if (TextUtils.isEmpty(hexString)) {
+ return null;
+ }
+ final int N = hexString.length();
+ if (N % 2 != 0) {
+ throw new NumberFormatException("Input hex string length must be an even number."
+ + " Length = " + N);
+ }
+ final byte[] bytes = new byte[N / 2];
+ for (int i = 0; i < N; i += 2) {
+ bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ + Character.digit(hexString.charAt(i + 1), 16));
+ }
+ 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 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 "";
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 16728092d..102a41b4e 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -40,6 +40,7 @@ public final class SubtypeLocaleUtils {
// Special language code to represent "no language".
public static final String NO_LANGUAGE = "zz";
public static final String QWERTY = "qwerty";
+ public static final String EMOJI = "emoji";
public static final int UNKNOWN_KEYBOARD_LAYOUT = R.string.subtype_generic;
private static boolean sInitialized = false;
diff --git a/java/src/com/android/inputmethod/latin/utils/TextRange.java b/java/src/com/android/inputmethod/latin/utils/TextRange.java
index 5793e4170..48b443ddd 100644
--- a/java/src/com/android/inputmethod/latin/utils/TextRange.java
+++ b/java/src/com/android/inputmethod/latin/utils/TextRange.java
@@ -40,6 +40,10 @@ public final class TextRange {
return mWordAtCursorEndIndex - mCursorIndex;
}
+ public int length() {
+ return mWord.length();
+ }
+
/**
* Gets the suggestion spans that are put squarely on the word, with the exact start
* and end of the span matching the boundaries of the word.
diff --git a/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java
index 544e4d201..47ea1ea75 100644
--- a/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java
@@ -66,6 +66,11 @@ 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();
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
index aed07fd16..ea32a74ff 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
@@ -19,22 +19,22 @@ package com.android.inputmethod.latin.utils;
import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoder;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
+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.Node;
+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.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
/**
* Reads and writes Binary files for a UserHistoryDictionary.
@@ -44,6 +44,9 @@ import java.util.Map;
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 {
public void setUnigram(final String word, final String shortcutTarget, final int frequency);
@@ -58,12 +61,15 @@ public final class UserHistoryDictIOUtils {
/**
* Writes dictionary to file.
*/
- public static void writeDictionaryBinary(final OutputStream destination,
+ 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 {
- BinaryDictEncoder.writeDictionaryBinary(destination, fusionDict, formatOptions);
+ dictEncoder.writeDictionary(fusionDict, formatOptions);
Log.d(TAG, "end writing");
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
@@ -78,7 +84,7 @@ public final class UserHistoryDictIOUtils {
@UsedForTesting
static FusionDictionary constructFusionDictionary(
final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams) {
- final FusionDictionary fusionDict = new FusionDictionary(new Node(),
+ final FusionDictionary fusionDict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false,
false));
int profTotal = 0;
@@ -102,7 +108,7 @@ public final class UserHistoryDictIOUtils {
if (word1 == null) { // unigram
fusionDict.add(word2, freq, null, false /* isNotAWord */);
} else { // bigram
- if (FusionDictionary.findWordInTree(fusionDict.mRoot, word1) == null) {
+ if (FusionDictionary.findWordInTree(fusionDict.mRootNodeArray, word1) == null) {
fusionDict.add(word1, 2, null, false /* isNotAWord */);
}
fusionDict.setBigram(word1, word2, freq);
@@ -119,14 +125,13 @@ public final class UserHistoryDictIOUtils {
/**
* Reads dictionary from file.
*/
- public static void readDictionaryBinary(final BinaryDictReader reader,
+ public static void readDictionaryBinary(final DictDecoder dictDecoder,
final OnAddWordListener dict) {
- final Map<Integer, String> unigrams = CollectionUtils.newTreeMap();
- final Map<Integer, Integer> frequencies = CollectionUtils.newTreeMap();
- final Map<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, String> unigrams = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, Integer> frequencies = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams = CollectionUtils.newTreeMap();
try {
- BinaryDictIOUtils.readUnigramsAndBigramsBinary(reader, unigrams, frequencies,
- bigrams);
+ dictDecoder.readUnigramsAndBigramsBinary(unigrams, frequencies, bigrams);
} catch (IOException e) {
Log.e(TAG, "IO exception while reading file", e);
} catch (UnsupportedFormatException e) {
@@ -141,10 +146,11 @@ public final class UserHistoryDictIOUtils {
* Adds all unigrams and bigrams in maps to OnAddWordListener.
*/
@UsedForTesting
- static void addWordsFromWordMap(final Map<Integer, String> unigrams,
- final Map<Integer, Integer> frequencies,
- final Map<Integer, ArrayList<PendingAttribute>> bigrams, final OnAddWordListener to) {
- for (Map.Entry<Integer, String> entry : unigrams.entrySet()) {
+ 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, unigramFrequency);
@@ -157,7 +163,7 @@ public final class UserHistoryDictIOUtils {
continue;
}
to.setBigram(word1, word2,
- BinaryDictDecoder.reconstructBigramFrequency(unigramFrequency,
+ 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
index 713a45bda..1992b2f5d 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
@@ -23,7 +23,9 @@ 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 FC_FREQ_MAX = 127;
+ 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;
@@ -33,6 +35,14 @@ public final class UserHistoryForgettingCurveUtils {
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.
}
diff --git a/java/src/com/android/inputmethod/research/JsonUtils.java b/java/src/com/android/inputmethod/research/JsonUtils.java
index 977f843e9..2beebdfae 100644
--- a/java/src/com/android/inputmethod/research/JsonUtils.java
+++ b/java/src/com/android/inputmethod/research/JsonUtils.java
@@ -103,7 +103,7 @@ import java.util.Map;
jsonWriter.name("word").value(wordInfo.toString());
jsonWriter.name("score").value(wordInfo.mScore);
jsonWriter.name("kind").value(wordInfo.mKind);
- jsonWriter.name("sourceDict").value(wordInfo.mSourceDict);
+ jsonWriter.name("sourceDict").value(wordInfo.mSourceDict.mDictType);
jsonWriter.endObject();
}
jsonWriter.endArray();
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 3a3408266..da9c61103 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -1427,7 +1427,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
kid.navigateNext(), kid.navigatePrevious(), kid.mClobberSettingsKey,
isPasswordView, kid.mShortcutKeyEnabled, kid.mHasShortcutKey,
kid.mLanguageSwitchKeyEnabled, kid.isMultiLine(), keyboard.mOccupiedWidth,
- keyboard.mOccupiedHeight, keyboard.mKeys);
+ keyboard.mOccupiedHeight, keyboard.getKeys());
}
/**
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 9e7407abd..0594ddff0 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -43,7 +43,7 @@ LATIN_IME_JNI_SRC_FILES := \
com_android_inputmethod_keyboard_ProximityInfo.cpp \
com_android_inputmethod_latin_BinaryDictionary.cpp \
com_android_inputmethod_latin_DicTraverseSession.cpp \
- com_android_inputmethod_latin_makedict_BinaryDictDecoder.cpp \
+ com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \
jni_common.cpp
LATIN_IME_CORE_SRC_FILES := \
@@ -67,18 +67,26 @@ LATIN_IME_CORE_SRC_FILES := \
suggest/core/policy/weighting.cpp \
suggest/core/session/dic_traverse_session.cpp \
$(addprefix suggest/policyimpl/dictionary/, \
- bigram/bigram_list_reading_utils.cpp \
+ bigram/bigram_list_read_write_utils.cpp \
+ bigram/dynamic_bigram_list_policy.cpp \
header/header_policy.cpp \
- header/header_reading_utils.cpp \
+ header/header_read_write_utils.cpp \
shortcut/shortcut_list_reading_utils.cpp \
- utils/byte_array_utils.cpp \
- utils/format_utils.cpp \
dictionary_structure_with_buffer_policy_factory.cpp \
+ dynamic_patricia_trie_gc_event_listeners.cpp \
dynamic_patricia_trie_node_reader.cpp \
dynamic_patricia_trie_policy.cpp \
+ dynamic_patricia_trie_reading_helper.cpp \
dynamic_patricia_trie_reading_utils.cpp \
+ dynamic_patricia_trie_writing_helper.cpp \
+ dynamic_patricia_trie_writing_utils.cpp \
patricia_trie_policy.cpp \
patricia_trie_reading_utils.cpp) \
+ $(addprefix suggest/policyimpl/dictionary/utils/, \
+ buffer_with_extendable_buffer.cpp \
+ byte_array_utils.cpp \
+ dict_file_writing_utils.cpp \
+ format_utils.cpp) \
suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \
$(addprefix suggest/policyimpl/typing/, \
scoring_params.cpp \
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 86c2394d1..7761ec4d5 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -26,12 +26,55 @@
#include "suggest/core/dictionary/dictionary.h"
#include "suggest/core/suggest_options.h"
#include "suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h"
+#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
#include "utils/autocorrection_threshold_utils.h"
namespace latinime {
class ProximityInfo;
+// TODO: Move to makedict.
+static jboolean latinime_BinaryDictionary_createEmptyDictFile(JNIEnv *env, jclass clazz,
+ jstring filePath, jlong dictVersion, jobjectArray attributeKeyStringArray,
+ jobjectArray attributeValueStringArray) {
+ const jsize filePathUtf8Length = env->GetStringUTFLength(filePath);
+ char filePathChars[filePathUtf8Length + 1];
+ env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars);
+ filePathChars[filePathUtf8Length] = '\0';
+
+ const int keyCount = env->GetArrayLength(attributeKeyStringArray);
+ const int valueCount = env->GetArrayLength(attributeValueStringArray);
+ if (keyCount != valueCount) {
+ return false;
+ }
+
+ HeaderReadWriteUtils::AttributeMap attributeMap;
+ for (int i = 0; i < keyCount; i++) {
+ jstring keyString = static_cast<jstring>(
+ env->GetObjectArrayElement(attributeKeyStringArray, i));
+ const jsize keyUtf8Length = env->GetStringUTFLength(keyString);
+ char keyChars[keyUtf8Length + 1];
+ env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars);
+ keyChars[keyUtf8Length] = '\0';
+ HeaderReadWriteUtils::AttributeMap::key_type key;
+ HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key);
+
+ jstring valueString = static_cast<jstring>(
+ env->GetObjectArrayElement(attributeValueStringArray, i));
+ const jsize valueUtf8Length = env->GetStringUTFLength(valueString);
+ char valueChars[valueUtf8Length + 1];
+ env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars);
+ valueChars[valueUtf8Length] = '\0';
+ HeaderReadWriteUtils::AttributeMap::mapped_type value;
+ HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value);
+
+ attributeMap[key] = value;
+ }
+
+ return DictFileWritingUtils::createEmptyDictFile(filePathChars, static_cast<int>(dictVersion),
+ &attributeMap);
+}
+
static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring sourceDir,
jlong dictOffset, jlong dictSize, jboolean isUpdatable) {
PROF_OPEN;
@@ -46,8 +89,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
sourceDirChars[sourceDirUtf8Length] = '\0';
DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy =
DictionaryStructureWithBufferPolicyFactory::newDictionaryStructureWithBufferPolicy(
- sourceDirChars, static_cast<int>(sourceDirUtf8Length),
- static_cast<int>(dictOffset), static_cast<int>(dictSize),
+ sourceDirChars, static_cast<int>(dictOffset), static_cast<int>(dictSize),
isUpdatable == JNI_TRUE);
if (!dictionaryStructureWithBufferPolicy) {
return 0;
@@ -59,6 +101,35 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
return reinterpret_cast<jlong>(dictionary);
}
+static void latinime_BinaryDictionary_flush(JNIEnv *env, jclass clazz, jlong dict,
+ jstring filePath) {
+ Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+ if (!dictionary) return;
+ const jsize filePathUtf8Length = env->GetStringUTFLength(filePath);
+ char filePathChars[filePathUtf8Length + 1];
+ env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars);
+ filePathChars[filePathUtf8Length] = '\0';
+ dictionary->flush(filePathChars);
+}
+
+static bool latinime_BinaryDictionary_needsToRunGC(JNIEnv *env, jclass clazz,
+ jlong dict) {
+ Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+ if (!dictionary) return false;
+ return dictionary->needsToRunGC();
+}
+
+static void latinime_BinaryDictionary_flushWithGC(JNIEnv *env, jclass clazz, jlong dict,
+ jstring filePath) {
+ Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+ if (!dictionary) return;
+ const jsize filePathUtf8Length = env->GetStringUTFLength(filePath);
+ char filePathChars[filePathUtf8Length + 1];
+ env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars);
+ filePathChars[filePathUtf8Length] = '\0';
+ dictionary->flushWithGC(filePathChars);
+}
+
static void latinime_BinaryDictionary_close(JNIEnv *env, jclass clazz, jlong dict) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return;
@@ -70,7 +141,8 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j
jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray,
- jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray) {
+ jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray,
+ jintArray outputAutoCommitFirstWordConfidence) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return 0;
ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo);
@@ -159,8 +231,8 @@ static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz,
return dictionary->getProbability(codePoints, wordLength);
}
-static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jclass clazz, jlong dict,
- jintArray word0, jintArray word1) {
+static jint latinime_BinaryDictionary_getBigramProbability(JNIEnv *env, jclass clazz,
+ jlong dict, jintArray word0, jintArray word1) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return JNI_FALSE;
const jsize word0Length = env->GetArrayLength(word0);
@@ -169,7 +241,8 @@ static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jclass claz
int word1CodePoints[word1Length];
env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints);
env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints);
- return dictionary->isValidBigram(word0CodePoints, word0Length, word1CodePoints, word1Length);
+ return dictionary->getBigramProbability(word0CodePoints, word0Length, word1CodePoints,
+ word1Length);
}
static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jclass clazz,
@@ -204,6 +277,7 @@ static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz,
}
jsize wordLength = env->GetArrayLength(word);
int codePoints[wordLength];
+ env->GetIntArrayRegion(word, 0, wordLength, codePoints);
dictionary->addUnigramWord(codePoints, wordLength, probability);
}
@@ -215,8 +289,10 @@ static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz,
}
jsize word0Length = env->GetArrayLength(word0);
int word0CodePoints[word0Length];
+ env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints);
jsize word1Length = env->GetArrayLength(word1);
int word1CodePoints[word1Length];
+ env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints);
dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints,
word1Length, probability);
}
@@ -229,14 +305,31 @@ static void latinime_BinaryDictionary_removeBigramWords(JNIEnv *env, jclass claz
}
jsize word0Length = env->GetArrayLength(word0);
int word0CodePoints[word0Length];
+ env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints);
jsize word1Length = env->GetArrayLength(word1);
int word1CodePoints[word1Length];
+ env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints);
dictionary->removeBigramWords(word0CodePoints, word0Length, word1CodePoints,
word1Length);
}
+static int latinime_BinaryDictionary_calculateProbabilityNative(JNIEnv *env, jclass clazz,
+ jlong dict, jint unigramProbability, jint bigramProbability) {
+ Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
+ if (!dictionary) {
+ return NOT_A_PROBABILITY;
+ }
+ return dictionary->getDictionaryStructurePolicy()->getProbability(unigramProbability,
+ bigramProbability);
+}
+
static const JNINativeMethod sMethods[] = {
{
+ const_cast<char *>("createEmptyDictFileNative"),
+ const_cast<char *>("(Ljava/lang/String;J[Ljava/lang/String;[Ljava/lang/String;)Z"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_createEmptyDictFile)
+ },
+ {
const_cast<char *>("openNative"),
const_cast<char *>("(Ljava/lang/String;JJZ)J"),
reinterpret_cast<void *>(latinime_BinaryDictionary_open)
@@ -247,8 +340,23 @@ static const JNINativeMethod sMethods[] = {
reinterpret_cast<void *>(latinime_BinaryDictionary_close)
},
{
+ const_cast<char *>("flushNative"),
+ const_cast<char *>("(JLjava/lang/String;)V"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_flush)
+ },
+ {
+ const_cast<char *>("needsToRunGCNative"),
+ const_cast<char *>("(J)Z"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_needsToRunGC)
+ },
+ {
+ const_cast<char *>("flushWithGCNative"),
+ const_cast<char *>("(JLjava/lang/String;)V"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_flushWithGC)
+ },
+ {
const_cast<char *>("getSuggestionsNative"),
- const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I)I"),
+ const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"),
reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
},
{
@@ -257,9 +365,9 @@ static const JNINativeMethod sMethods[] = {
reinterpret_cast<void *>(latinime_BinaryDictionary_getProbability)
},
{
- const_cast<char *>("isValidBigramNative"),
- const_cast<char *>("(J[I[I)Z"),
- reinterpret_cast<void *>(latinime_BinaryDictionary_isValidBigram)
+ const_cast<char *>("getBigramProbabilityNative"),
+ const_cast<char *>("(J[I[I)I"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_getBigramProbability)
},
{
const_cast<char *>("calcNormalizedScoreNative"),
@@ -285,6 +393,11 @@ static const JNINativeMethod sMethods[] = {
const_cast<char *>("removeBigramWordsNative"),
const_cast<char *>("(J[I[I)V"),
reinterpret_cast<void *>(latinime_BinaryDictionary_removeBigramWords)
+ },
+ {
+ const_cast<char *>("calculateProbabilityNative"),
+ const_cast<char *>("(JII)I"),
+ reinterpret_cast<void *>(latinime_BinaryDictionary_calculateProbabilityNative)
}
};
diff --git a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
index 72e625836..386643332 100644
--- a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
+++ b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
@@ -25,8 +25,9 @@
namespace latinime {
class Dictionary;
-static jlong latinime_setDicTraverseSession(JNIEnv *env, jclass clazz, jstring localeJStr) {
- void *traverseSession = DicTraverseSession::getSessionInstance(env, localeJStr);
+static jlong latinime_setDicTraverseSession(JNIEnv *env, jclass clazz, jstring localeJStr,
+ jlong dictSize) {
+ void *traverseSession = DicTraverseSession::getSessionInstance(env, localeJStr, dictSize);
return reinterpret_cast<jlong>(traverseSession);
}
@@ -53,7 +54,7 @@ static void latinime_releaseDicTraverseSession(JNIEnv *env, jclass clazz, jlong
static const JNINativeMethod sMethods[] = {
{
const_cast<char *>("setDicTraverseSessionNative"),
- const_cast<char *>("(Ljava/lang/String;)J"),
+ const_cast<char *>("(Ljava/lang/String;J)J"),
reinterpret_cast<void *>(latinime_setDicTraverseSession)
},
{
diff --git a/native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.cpp b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp
index 457b226b6..15088b65a 100644
--- a/native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.cpp
+++ b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-#define LOG_TAG "LatinIME: jni: BinaryDictDecoder"
+#define LOG_TAG "LatinIME: jni: Ver3DictDecoder"
-#include "com_android_inputmethod_latin_makedict_BinaryDictDecoder.h"
+#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h"
#include "defines.h"
#include "jni.h"
#include "jni_common.h"
namespace latinime {
-static int latinime_BinaryDictDecoder_doNothing(JNIEnv *env, jclass clazz) {
+static int latinime_Ver3DictDecoder_doNothing(JNIEnv *env, jclass clazz) {
// This is a phony method for test - it does nothing. It just returns some value
// unlikely to be in memory by chance for testing purposes.
// TODO: remove this method.
@@ -35,13 +35,13 @@ static const JNINativeMethod sMethods[] = {
// TODO: remove this entry when we have one useful method in here
const_cast<char *>("doNothing"),
const_cast<char *>("()I"),
- reinterpret_cast<void *>(latinime_BinaryDictDecoder_doNothing)
+ reinterpret_cast<void *>(latinime_Ver3DictDecoder_doNothing)
},
};
-int register_BinaryDictDecoder(JNIEnv *env) {
+int register_Ver3DictDecoder(JNIEnv *env) {
const char *const kClassPathName =
- "com/android/inputmethod/latin/makedict/BinaryDictDecoder";
+ "com/android/inputmethod/latin/makedict/Ver3DictDecoder";
return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods));
}
} // namespace latinime
diff --git a/native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.h b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h
index 7f3cb67e6..07e80f1d8 100644
--- a/native/jni/com_android_inputmethod_latin_makedict_BinaryDictDecoder.h
+++ b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_BINARYDICTDECODER_H
-#define _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_BINARYDICTDECODER_H
+#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H
+#define _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H
#include "jni.h"
namespace latinime {
-int register_BinaryDictDecoder(JNIEnv *env);
+int register_Ver3DictDecoder(JNIEnv *env);
} // namespace latinime
-#endif // _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_BINARYDICTDECODER_H
+#endif // _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H
diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp
index d44be6705..3a8f4362d 100644
--- a/native/jni/jni_common.cpp
+++ b/native/jni/jni_common.cpp
@@ -23,7 +23,7 @@
#include "com_android_inputmethod_latin_BinaryDictionary.h"
#include "com_android_inputmethod_latin_DicTraverseSession.h"
#endif
-#include "com_android_inputmethod_latin_makedict_BinaryDictDecoder.h"
+#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h"
#include "defines.h"
/*
@@ -55,8 +55,8 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
return -1;
}
#endif
- if (!latinime::register_BinaryDictDecoder(env)) {
- AKLOGE("ERROR: BinaryDictDecoder native registration failed");
+ if (!latinime::register_Ver3DictDecoder(env)) {
+ AKLOGE("ERROR: Ver3DictDecoder native registration failed");
return -1;
}
/* success -- return valid version number */
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 34a646f80..89dfa39b3 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -292,7 +292,6 @@ static inline void prof_out(void) {
// of the binary dictionary where a {key,value} string pair scheme is used.
#define LARGEST_INT_DIGIT_COUNT 11
-#define NOT_A_VALID_WORD_POS (-99)
#define NOT_A_CODE_POINT (-1)
#define NOT_A_DISTANCE (-1)
#define NOT_A_COORDINATE (-1)
@@ -322,13 +321,6 @@ static inline void prof_out(void) {
#define MAX_POINTER_COUNT 1
#define MAX_POINTER_COUNT_G 2
-// Queue IDs and size for DicNodesCache
-#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_ACTIVE 0
-#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_NEXT_ACTIVE 1
-#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_TERMINAL 2
-#define DIC_NODES_CACHE_INITIAL_QUEUE_ID_CACHE_FOR_CONTINUOUS_SUGGESTION 3
-#define DIC_NODES_CACHE_PRIORITY_QUEUES_SIZE 4
-
template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; }
template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; }
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index cdd9f59aa..41ef9d2b2 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -112,7 +112,7 @@ class DicNode {
mIsUsed = true;
mIsCachedForNextSuggestion = false;
mDicNodeProperties.init(
- NOT_A_VALID_WORD_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
+ NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
NOT_A_PROBABILITY /* probability */, false /* isTerminal */,
true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */,
0 /* terminalDepth */);
@@ -125,7 +125,7 @@ class DicNode {
mIsUsed = true;
mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion;
mDicNodeProperties.init(
- NOT_A_VALID_WORD_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
+ NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
NOT_A_PROBABILITY /* probability */, false /* isTerminal */,
true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */,
0 /* terminalDepth */);
@@ -143,7 +143,7 @@ class DicNode {
dicNode->mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(),
dicNode->getOutputWordBuf(),
dicNode->mDicNodeProperties.getDepth(),
- dicNode->mDicNodeState.mDicNodeStatePrevWord.mPrevSpacePositions,
+ dicNode->mDicNodeState.mDicNodeStatePrevWord.getSecondWordFirstInputIndex(),
mDicNodeState.mDicNodeStateInput.getInputIndex(0) /* lastInputIndex */);
PROF_NODE_COPY(&dicNode->mProfiler, mProfiler);
}
@@ -234,7 +234,7 @@ class DicNode {
}
bool isFirstWord() const {
- return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_VALID_WORD_POS;
+ return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_DICT_POS;
}
bool isCompletion(const int inputSize) const {
@@ -321,8 +321,13 @@ class DicNode {
DUMP_WORD_AND_SCORE("OUTPUT");
}
- void outputSpacePositionsResult(int *spaceIndices) const {
- mDicNodeState.mDicNodeStatePrevWord.outputSpacePositions(spaceIndices);
+ int getSecondWordFirstInputIndex(const ProximityInfoState *const pInfoState) const {
+ const int inputIndex = mDicNodeState.mDicNodeStatePrevWord.getSecondWordFirstInputIndex();
+ if (inputIndex == NOT_AN_INDEX) {
+ return NOT_AN_INDEX;
+ } else {
+ return pInfoState->getInputIndexOfSampledPoint(inputIndex);
+ }
}
bool hasMultipleWords() const {
@@ -573,7 +578,11 @@ class DicNode {
}
}
- AK_FORCE_INLINE void updateInputIndexG(DicNode_InputStateG *inputStateG) {
+ AK_FORCE_INLINE void updateInputIndexG(const DicNode_InputStateG *const inputStateG) {
+ if (mDicNodeState.mDicNodeStatePrevWord.getPrevWordCount() == 1 && isFirstLetter()) {
+ mDicNodeState.mDicNodeStatePrevWord.setSecondWordFirstInputIndex(
+ inputStateG->mInputIndex);
+ }
mDicNodeState.mDicNodeStateInput.updateInputIndexG(inputStateG->mPointerId,
inputStateG->mInputIndex, inputStateG->mPrevCodePoint,
inputStateG->mTerminalDiffCost, inputStateG->mRawLength);
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h b/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h
index 2a486b804..7461f0cc6 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_priority_queue.h
@@ -24,20 +24,16 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_release_listener.h"
-// The biggest value among MAX_CACHE_DIC_NODE_SIZE, MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT, ...
-#define MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY 310
-
namespace latinime {
class DicNodePriorityQueue : public DicNodeReleaseListener {
public:
- AK_FORCE_INLINE DicNodePriorityQueue()
- : MAX_CAPACITY(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY),
- mMaxSize(MAX_DIC_NODE_PRIORITY_QUEUE_CAPACITY), mDicNodesBuf(), mUnusedNodeIndices(),
- mNextUnusedNodeId(0), mDicNodesQueue() {
- mDicNodesBuf.resize(MAX_CAPACITY + 1);
- mUnusedNodeIndices.resize(MAX_CAPACITY + 1);
- reset();
+ AK_FORCE_INLINE explicit DicNodePriorityQueue(const int capacity)
+ : mCapacity(capacity), mMaxSize(capacity), mDicNodesBuf(),
+ mUnusedNodeIndices(), mNextUnusedNodeId(0), mDicNodesQueue() {
+ mDicNodesBuf.resize(mCapacity + 1);
+ mUnusedNodeIndices.resize(mCapacity + 1);
+ clearAndResizeToCapacity();
}
// Non virtual inline destructor -- never inherit this class
@@ -52,11 +48,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}
AK_FORCE_INLINE void setMaxSize(const int maxSize) {
- mMaxSize = min(maxSize, MAX_CAPACITY);
+ ASSERT(maxSize <= mCapacity);
+ mMaxSize = min(maxSize, mCapacity);
}
- AK_FORCE_INLINE void reset() {
- clearAndResize(MAX_CAPACITY);
+ AK_FORCE_INLINE void clearAndResizeToCapacity() {
+ clearAndResize(mCapacity);
}
AK_FORCE_INLINE void clear() {
@@ -64,27 +61,19 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}
AK_FORCE_INLINE void clearAndResize(const int maxSize) {
+ ASSERT(maxSize <= mCapacity);
while (!mDicNodesQueue.empty()) {
mDicNodesQueue.pop();
}
setMaxSize(maxSize);
- for (int i = 0; i < MAX_CAPACITY + 1; ++i) {
+ for (int i = 0; i < mCapacity + 1; ++i) {
mDicNodesBuf[i].remove();
mDicNodesBuf[i].setReleaseListener(this);
- mUnusedNodeIndices[i] = i == MAX_CAPACITY ? NOT_A_NODE_ID : static_cast<int>(i) + 1;
+ mUnusedNodeIndices[i] = i == mCapacity ? NOT_A_NODE_ID : static_cast<int>(i) + 1;
}
mNextUnusedNodeId = 0;
}
- AK_FORCE_INLINE DicNode *newDicNode(DicNode *dicNode) {
- DicNode *newNode = searchEmptyDicNode();
- if (newNode) {
- DicNodeUtils::initByCopy(dicNode, newNode);
- return newNode;
- }
- return 0;
- }
-
// Copy
AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode) {
return copyPush(dicNode, mMaxSize);
@@ -111,12 +100,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}
mUnusedNodeIndices[index] = mNextUnusedNodeId;
mNextUnusedNodeId = index;
- ASSERT(index >= 0 && index < (MAX_CAPACITY + 1));
+ ASSERT(index >= 0 && index < (mCapacity + 1));
}
AK_FORCE_INLINE void dump() const {
AKLOGI("\n\n\n\n\n===========================");
- for (int i = 0; i < MAX_CAPACITY + 1; ++i) {
+ for (int i = 0; i < mCapacity + 1; ++i) {
if (mDicNodesBuf[i].isUsed()) {
mDicNodesBuf[i].dump("QUEUE: ");
}
@@ -125,7 +114,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}
private:
- DISALLOW_COPY_AND_ASSIGN(DicNodePriorityQueue);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodePriorityQueue);
static const int NOT_A_NODE_ID = -1;
AK_FORCE_INLINE static bool compareDicNode(DicNode *left, DicNode *right) {
@@ -139,7 +128,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
};
typedef std::priority_queue<DicNode *, std::vector<DicNode *>, DicNodeComparator> DicNodesQueue;
- const int MAX_CAPACITY;
+ const int mCapacity;
int mMaxSize;
std::vector<DicNode> mDicNodesBuf; // of each element of mDicNodesBuf respectively
std::vector<int> mUnusedNodeIndices;
@@ -163,13 +152,12 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
}
AK_FORCE_INLINE DicNode *searchEmptyDicNode() {
- // TODO: Currently O(n) but should be improved to O(1)
- if (MAX_CAPACITY == 0) {
+ if (mCapacity == 0) {
return 0;
}
if (mNextUnusedNodeId == NOT_A_NODE_ID) {
AKLOGI("No unused node found.");
- for (int i = 0; i < MAX_CAPACITY + 1; ++i) {
+ for (int i = 0; i < mCapacity + 1; ++i) {
AKLOGI("Dump node availability, %d, %d, %d",
i, mDicNodesBuf[i].isUsed(), mUnusedNodeIndices[i]);
}
@@ -185,7 +173,7 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
const int index = static_cast<int>(dicNode - &mDicNodesBuf[0]);
mNextUnusedNodeId = mUnusedNodeIndices[index];
mUnusedNodeIndices[index] = NOT_A_NODE_ID;
- ASSERT(index >= 0 && index < (MAX_CAPACITY + 1));
+ ASSERT(index >= 0 && index < (mCapacity + 1));
}
AK_FORCE_INLINE DicNode *pushPoolNodeWithMaxSize(DicNode *dicNode, const int maxSize) {
@@ -209,6 +197,15 @@ class DicNodePriorityQueue : public DicNodeReleaseListener {
AK_FORCE_INLINE DicNode *copyPush(DicNode *dicNode, const int maxSize) {
return pushPoolNodeWithMaxSize(newDicNode(dicNode), maxSize);
}
+
+ AK_FORCE_INLINE DicNode *newDicNode(DicNode *dicNode) {
+ DicNode *newNode = searchEmptyDicNode();
+ if (newNode) {
+ DicNodeUtils::initByCopy(dicNode, newNode);
+ }
+ return newNode;
+ }
+
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_PRIORITY_QUEUE_H
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
index bb54e608e..ec65114c7 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -21,7 +21,6 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/core/dictionary/multi_bigram_map.h"
-#include "suggest/core/dictionary/probability_utils.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
#include "utils/char_utils.h"
@@ -90,16 +89,18 @@ namespace latinime {
const int unigramProbability = node->getProbability();
const int wordPos = node->getPos();
const int prevWordPos = node->getPrevWordPos();
- if (NOT_A_VALID_WORD_POS == wordPos || NOT_A_VALID_WORD_POS == prevWordPos) {
+ if (NOT_A_DICT_POS == wordPos || NOT_A_DICT_POS == prevWordPos) {
// Note: Normally wordPos comes from the dictionary and should never equal
// NOT_A_VALID_WORD_POS.
- return ProbabilityUtils::backoff(unigramProbability);
+ return dictionaryStructurePolicy->getProbability(unigramProbability,
+ NOT_A_PROBABILITY);
}
if (multiBigramMap) {
return multiBigramMap->getBigramProbability(dictionaryStructurePolicy, prevWordPos,
wordPos, unigramProbability);
}
- return ProbabilityUtils::backoff(unigramProbability);
+ return dictionaryStructurePolicy->getProbability(unigramProbability,
+ NOT_A_PROBABILITY);
}
////////////////
diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
index c3d2a2e74..b6be47e90 100644
--- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.cpp
@@ -23,6 +23,11 @@
namespace latinime {
+// The biggest value among MAX_CACHE_DIC_NODE_SIZE, MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT, ...
+const int DicNodesCache::LARGE_PRIORITY_QUEUE_CAPACITY = 310;
+// Capacity for reducing memory footprint.
+const int DicNodesCache::SMALL_PRIORITY_QUEUE_CAPACITY = 100;
+
/**
* Truncates all of the dicNodes so that they start at the given commit point.
* Only called for multi-word typing input.
diff --git a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
index 7aab0906e..8493b6a8b 100644
--- a/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
+++ b/native/jni/src/suggest/core/dicnode/dic_nodes_cache.h
@@ -31,25 +31,32 @@ class DicNode;
*/
class DicNodesCache {
public:
- AK_FORCE_INLINE DicNodesCache()
- : mActiveDicNodes(&mDicNodePriorityQueues[DIC_NODES_CACHE_INITIAL_QUEUE_ID_ACTIVE]),
- mNextActiveDicNodes(&mDicNodePriorityQueues[
- DIC_NODES_CACHE_INITIAL_QUEUE_ID_NEXT_ACTIVE]),
- mTerminalDicNodes(&mDicNodePriorityQueues[DIC_NODES_CACHE_INITIAL_QUEUE_ID_TERMINAL]),
- mCachedDicNodesForContinuousSuggestion(&mDicNodePriorityQueues[
- DIC_NODES_CACHE_INITIAL_QUEUE_ID_CACHE_FOR_CONTINUOUS_SUGGESTION]),
- mInputIndex(0), mLastCachedInputIndex(0) {
- }
+ AK_FORCE_INLINE explicit DicNodesCache(const bool usesLargeCapacityCache)
+ : mUsesLargeCapacityCache(usesLargeCapacityCache),
+ mDicNodePriorityQueue0(getCacheCapacity()),
+ mDicNodePriorityQueue1(getCacheCapacity()),
+ mDicNodePriorityQueue2(getCacheCapacity()),
+ mDicNodePriorityQueueForTerminal(MAX_RESULTS),
+ mActiveDicNodes(&mDicNodePriorityQueue0),
+ mNextActiveDicNodes(&mDicNodePriorityQueue1),
+ mCachedDicNodesForContinuousSuggestion(&mDicNodePriorityQueue2),
+ mTerminalDicNodes(&mDicNodePriorityQueueForTerminal),
+ mInputIndex(0), mLastCachedInputIndex(0) {}
AK_FORCE_INLINE virtual ~DicNodesCache() {}
AK_FORCE_INLINE void reset(const int nextActiveSize, const int terminalSize) {
mInputIndex = 0;
mLastCachedInputIndex = 0;
- mActiveDicNodes->reset();
- mNextActiveDicNodes->clearAndResize(nextActiveSize);
+ // We want to use the max capacity for the current active dic node queue.
+ mActiveDicNodes->clearAndResizeToCapacity();
+ // nextActiveSize is used to limit the next iteration's active dic node size.
+ const int nextActiveSizeFittingToTheCapacity = min(nextActiveSize, getCacheCapacity());
+ mNextActiveDicNodes->clearAndResize(nextActiveSizeFittingToTheCapacity);
mTerminalDicNodes->clearAndResize(terminalSize);
- mCachedDicNodesForContinuousSuggestion->reset();
+ // We want to use the max capacity for the cached dic nodes that will be used for the
+ // continuous suggestion.
+ mCachedDicNodesForContinuousSuggestion->clearAndResizeToCapacity();
}
AK_FORCE_INLINE void continueSearch() {
@@ -157,21 +164,35 @@ class DicNodesCache {
return tmp;
}
+ AK_FORCE_INLINE int getCacheCapacity() const {
+ return mUsesLargeCapacityCache ?
+ LARGE_PRIORITY_QUEUE_CAPACITY : SMALL_PRIORITY_QUEUE_CAPACITY;
+ }
+
AK_FORCE_INLINE void resetTemporaryCaches() {
mActiveDicNodes->clear();
mNextActiveDicNodes->clear();
mTerminalDicNodes->clear();
}
- DicNodePriorityQueue mDicNodePriorityQueues[DIC_NODES_CACHE_PRIORITY_QUEUES_SIZE];
+ static const int LARGE_PRIORITY_QUEUE_CAPACITY;
+ static const int SMALL_PRIORITY_QUEUE_CAPACITY;
+
+ const bool mUsesLargeCapacityCache;
+ // Instances
+ DicNodePriorityQueue mDicNodePriorityQueue0;
+ DicNodePriorityQueue mDicNodePriorityQueue1;
+ DicNodePriorityQueue mDicNodePriorityQueue2;
+ DicNodePriorityQueue mDicNodePriorityQueueForTerminal;
+
// Active dicNodes currently being expanded.
DicNodePriorityQueue *mActiveDicNodes;
// Next dicNodes to be expanded.
DicNodePriorityQueue *mNextActiveDicNodes;
- // Current top terminal dicNodes.
- DicNodePriorityQueue *mTerminalDicNodes;
// Cached dicNodes used for continuous suggestion.
DicNodePriorityQueue *mCachedDicNodesForContinuousSuggestion;
+ // Current top terminal dicNodes.
+ DicNodePriorityQueue *mTerminalDicNodes;
int mInputIndex;
int mLastCachedInputIndex;
};
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
index 45c7f5cf9..74eb5dfe7 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_output.h
@@ -49,8 +49,10 @@ class DicNodeStateOutput {
void addMergedNodeCodePoints(const uint16_t mergedNodeCodePointCount,
const int *const mergedNodeCodePoints) {
if (mergedNodeCodePoints) {
+ const int additionalCodePointCount = min(static_cast<int>(mergedNodeCodePointCount),
+ MAX_WORD_LENGTH - mOutputtedCodePointCount);
memcpy(&mCodePointsBuf[mOutputtedCodePointCount], mergedNodeCodePoints,
- mergedNodeCodePointCount * sizeof(mCodePointsBuf[0]));
+ additionalCodePointCount * sizeof(mCodePointsBuf[0]));
mOutputtedCodePointCount = static_cast<uint16_t>(
mOutputtedCodePointCount + mergedNodeCodePointCount);
if (mOutputtedCodePointCount < MAX_WORD_LENGTH) {
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
index 5854f4f6e..b8986203d 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
@@ -22,6 +22,7 @@
#include "defines.h"
#include "suggest/core/dicnode/dic_node_utils.h"
+#include "suggest/core/layout/proximity_info_state.h"
namespace latinime {
@@ -29,9 +30,8 @@ class DicNodeStatePrevWord {
public:
AK_FORCE_INLINE DicNodeStatePrevWord()
: mPrevWordCount(0), mPrevWordLength(0), mPrevWordStart(0), mPrevWordProbability(0),
- mPrevWordNodePos(NOT_A_VALID_WORD_POS) {
+ mPrevWordNodePos(NOT_A_DICT_POS), mSecondWordFirstInputIndex(NOT_AN_INDEX) {
memset(mPrevWord, 0, sizeof(mPrevWord));
- memset(mPrevSpacePositions, 0, sizeof(mPrevSpacePositions));
}
virtual ~DicNodeStatePrevWord() {}
@@ -41,8 +41,8 @@ class DicNodeStatePrevWord {
mPrevWordCount = 0;
mPrevWordStart = 0;
mPrevWordProbability = -1;
- mPrevWordNodePos = NOT_A_VALID_WORD_POS;
- memset(mPrevSpacePositions, 0, sizeof(mPrevSpacePositions));
+ mPrevWordNodePos = NOT_A_DICT_POS;
+ mSecondWordFirstInputIndex = NOT_AN_INDEX;
}
void init(const int prevWordNodePos) {
@@ -51,7 +51,7 @@ class DicNodeStatePrevWord {
mPrevWordStart = 0;
mPrevWordProbability = -1;
mPrevWordNodePos = prevWordNodePos;
- memset(mPrevSpacePositions, 0, sizeof(mPrevSpacePositions));
+ mSecondWordFirstInputIndex = NOT_AN_INDEX;
}
// Init by copy
@@ -61,24 +61,26 @@ class DicNodeStatePrevWord {
mPrevWordStart = prevWord->mPrevWordStart;
mPrevWordProbability = prevWord->mPrevWordProbability;
mPrevWordNodePos = prevWord->mPrevWordNodePos;
+ mSecondWordFirstInputIndex = prevWord->mSecondWordFirstInputIndex;
memcpy(mPrevWord, prevWord->mPrevWord, prevWord->mPrevWordLength * sizeof(mPrevWord[0]));
- memcpy(mPrevSpacePositions, prevWord->mPrevSpacePositions, sizeof(mPrevSpacePositions));
}
void init(const int16_t prevWordCount, const int16_t prevWordProbability,
const int prevWordNodePos, const int *const src0, const int16_t length0,
- const int *const src1, const int16_t length1, const int *const prevSpacePositions,
- const int lastInputIndex) {
- mPrevWordCount = prevWordCount;
+ const int *const src1, const int16_t length1,
+ const int prevWordSecondWordFirstInputIndex, const int lastInputIndex) {
+ mPrevWordCount = min(prevWordCount, static_cast<int16_t>(MAX_RESULTS));
mPrevWordProbability = prevWordProbability;
mPrevWordNodePos = prevWordNodePos;
- const int twoWordsLen =
+ int twoWordsLen =
DicNodeUtils::appendTwoWords(src0, length0, src1, length1, mPrevWord);
+ if (twoWordsLen >= MAX_WORD_LENGTH) {
+ twoWordsLen = MAX_WORD_LENGTH - 1;
+ }
mPrevWord[twoWordsLen] = KEYCODE_SPACE;
mPrevWordStart = length0;
mPrevWordLength = static_cast<int16_t>(twoWordsLen + 1);
- memcpy(mPrevSpacePositions, prevSpacePositions, sizeof(mPrevSpacePositions));
- mPrevSpacePositions[mPrevWordCount - 1] = lastInputIndex;
+ mSecondWordFirstInputIndex = prevWordSecondWordFirstInputIndex;
}
void truncate(const int offset) {
@@ -93,11 +95,12 @@ class DicNodeStatePrevWord {
mPrevWordLength = newPrevWordLength;
}
- void outputSpacePositions(int *spaceIndices) const {
- // Convert uint16_t to int
- for (int i = 0; i < MAX_RESULTS; i++) {
- spaceIndices[i] = mPrevSpacePositions[i];
- }
+ void setSecondWordFirstInputIndex(const int inputIndex) {
+ mSecondWordFirstInputIndex = inputIndex;
+ }
+
+ int getSecondWordFirstInputIndex() const {
+ return mSecondWordFirstInputIndex;
}
// TODO: remove
@@ -113,10 +116,6 @@ class DicNodeStatePrevWord {
return mPrevWordStart;
}
- int16_t getPrevWordProbability() const {
- return mPrevWordProbability;
- }
-
int getPrevWordNodePos() const {
return mPrevWordNodePos;
}
@@ -139,8 +138,6 @@ class DicNodeStatePrevWord {
// TODO: Move to private
int mPrevWord[MAX_WORD_LENGTH];
- // TODO: Move to private
- int mPrevSpacePositions[MAX_RESULTS];
private:
// Caution!!!
@@ -151,6 +148,7 @@ class DicNodeStatePrevWord {
int16_t mPrevWordStart;
int16_t mPrevWordProbability;
int mPrevWordNodePos;
+ int mSecondWordFirstInputIndex;
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_STATE_PREVWORD_H
diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
index ebe76467a..71f4ef6ea 100644
--- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
@@ -23,7 +23,6 @@
#include "defines.h"
#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
#include "suggest/core/dictionary/dictionary.h"
-#include "suggest/core/dictionary/probability_utils.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
#include "utils/char_utils.h"
@@ -117,18 +116,24 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng
mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
- const int length = mDictionaryStructurePolicy->
+ if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
+ continue;
+ }
+ const int codePointCount = mDictionaryStructurePolicy->
getCodePointsAndProbabilityAndReturnCodePointCount(bigramsIt.getBigramPos(),
MAX_WORD_LENGTH, bigramBuffer, &unigramProbability);
+ if (codePointCount <= 0) {
+ continue;
+ }
// Due to space constraints, the probability for bigrams is approximate - the lower the
// unigram probability, the worse the precision. The theoritical maximum error in
// resulting probability is 8 - although in the practice it's never bigger than 3 or 4
// in very bad cases. This means that sometimes, we'll see some bigrams interverted
// here, but it can't get too bad.
- const int probability = ProbabilityUtils::computeProbabilityForBigram(
+ const int probability = mDictionaryStructurePolicy->getProbability(
unigramProbability, bigramsIt.getProbability());
- addWordBigram(bigramBuffer, length, probability, outBigramProbability, outBigramCodePoints,
- outputTypes);
+ addWordBigram(bigramBuffer, codePointCount, probability, outBigramProbability,
+ outBigramCodePoints, outputTypes);
++bigramCount;
}
return min(bigramCount, MAX_RESULTS);
@@ -141,28 +146,30 @@ int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const in
if (0 >= prevWordLength) return NOT_A_DICT_POS;
int pos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(prevWord, prevWordLength,
forceLowerCaseSearch);
- if (NOT_A_VALID_WORD_POS == pos) return NOT_A_DICT_POS;
- return mDictionaryStructurePolicy->getBigramsPositionOfNode(pos);
+ if (NOT_A_DICT_POS == pos) return NOT_A_DICT_POS;
+ return mDictionaryStructurePolicy->getBigramsPositionOfPtNode(pos);
}
-bool BigramDictionary::isValidBigram(const int *word0, int length0, const int *word1,
+int BigramDictionary::getBigramProbability(const int *word0, int length0, const int *word1,
int length1) const {
int pos = getBigramListPositionForWord(word0, length0, false /* forceLowerCaseSearch */);
// getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
- if (NOT_A_DICT_POS == pos) return false;
+ if (NOT_A_DICT_POS == pos) return NOT_A_PROBABILITY;
int nextWordPos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(word1, length1,
false /* forceLowerCaseSearch */);
- if (NOT_A_VALID_WORD_POS == nextWordPos) return false;
+ if (NOT_A_DICT_POS == nextWordPos) return NOT_A_PROBABILITY;
BinaryDictionaryBigramsIterator bigramsIt(
mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
if (bigramsIt.getBigramPos() == nextWordPos) {
- return true;
+ return mDictionaryStructurePolicy->getProbability(
+ mDictionaryStructurePolicy->getUnigramProbabilityOfPtNode(nextWordPos),
+ bigramsIt.getProbability());
}
}
- return false;
+ return NOT_A_PROBABILITY;
}
// TODO: Move functions related to bigram to here
diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h
index 99b964c49..8af7ee75d 100644
--- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.h
@@ -29,7 +29,7 @@ class BigramDictionary {
int getPredictions(const int *word, int length, int *outBigramCodePoints,
int *outBigramProbability, int *outputTypes) const;
- bool isValidBigram(const int *word1, int length1, const int *word2, int length2) const;
+ int getBigramProbability(const int *word1, int length1, const int *word2, int length2) const;
~BigramDictionary();
private:
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 8418a608a..ec1b63a12 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -87,14 +87,15 @@ int Dictionary::getBigrams(const int *word, int length, int *outWords, int *freq
int Dictionary::getProbability(const int *word, int length) const {
int pos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(word, length,
false /* forceLowerCaseSearch */);
- if (NOT_A_VALID_WORD_POS == pos) {
+ if (NOT_A_DICT_POS == pos) {
return NOT_A_PROBABILITY;
}
- return getDictionaryStructurePolicy()->getUnigramProbability(pos);
+ return getDictionaryStructurePolicy()->getUnigramProbabilityOfPtNode(pos);
}
-bool Dictionary::isValidBigram(const int *word0, int length0, const int *word1, int length1) const {
- return mBigramDictionary->isValidBigram(word0, length0, word1, length1);
+int Dictionary::getBigramProbability(const int *word0, int length0, const int *word1,
+ int length1) const {
+ return mBigramDictionary->getBigramProbability(word0, length0, word1, length1);
}
void Dictionary::addUnigramWord(const int *const word, const int length, const int probability) {
@@ -112,6 +113,18 @@ void Dictionary::removeBigramWords(const int *const word0, const int length0,
mDictionaryStructureWithBufferPolicy->removeBigramWords(word0, length0, word1, length1);
}
+void Dictionary::flush(const char *const filePath) {
+ mDictionaryStructureWithBufferPolicy->flush(filePath);
+}
+
+void Dictionary::flushWithGC(const char *const filePath) {
+ mDictionaryStructureWithBufferPolicy->flushWithGC(filePath);
+}
+
+bool Dictionary::needsToRunGC() {
+ return mDictionaryStructureWithBufferPolicy->needsToRunGC();
+}
+
void Dictionary::logDictionaryInfo(JNIEnv *const env) const {
const int BUFFER_SIZE = 16;
int dictionaryIdCodePointBuffer[BUFFER_SIZE];
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 0afe5a54b..974447468 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -67,7 +67,7 @@ class Dictionary {
int getProbability(const int *word, int length) const;
- bool isValidBigram(const int *word0, int length0, const int *word1, int length1) const;
+ int getBigramProbability(const int *word0, int length0, const int *word1, int length1) const;
void addUnigramWord(const int *const word, const int length, const int probability);
@@ -77,6 +77,12 @@ class Dictionary {
void removeBigramWords(const int *const word0, const int length0, const int *const word1,
const int length1);
+ void flush(const char *const filePath);
+
+ void flushWithGC(const char *const filePath);
+
+ bool needsToRunGC();
+
const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const {
return mDictionaryStructureWithBufferPolicy;
}
diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
index 97d4cd161..4633c07b0 100644
--- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
+++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
@@ -22,7 +22,6 @@
#include "defines.h"
#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
#include "suggest/core/dictionary/bloom_filter.h"
-#include "suggest/core/dictionary/probability_utils.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
#include "utils/hash_map_compat.h"
@@ -43,11 +42,12 @@ class MultiBigramMap {
hash_map_compat<int, BigramMap>::const_iterator mapPosition =
mBigramMaps.find(wordPosition);
if (mapPosition != mBigramMaps.end()) {
- return mapPosition->second.getBigramProbability(nextWordPosition, unigramProbability);
+ return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition,
+ unigramProbability);
}
if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) {
addBigramsForWordPosition(structurePolicy, wordPosition);
- return mBigramMaps[wordPosition].getBigramProbability(
+ return mBigramMaps[wordPosition].getBigramProbability(structurePolicy,
nextWordPosition, unigramProbability);
}
return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition,
@@ -68,28 +68,31 @@ class MultiBigramMap {
void init(const DictionaryStructureWithBufferPolicy *const structurePolicy,
const int nodePos) {
- const int bigramsListPos = structurePolicy->getBigramsPositionOfNode(nodePos);
+ const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos);
BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(),
bigramsListPos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
+ if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
+ continue;
+ }
mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability();
mBloomFilter.setInFilter(bigramsIt.getBigramPos());
}
}
AK_FORCE_INLINE int getBigramProbability(
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
const int nextWordPosition, const int unigramProbability) const {
+ int bigramProbability = NOT_A_PROBABILITY;
if (mBloomFilter.isInFilter(nextWordPosition)) {
const hash_map_compat<int, int>::const_iterator bigramProbabilityIt =
mBigramMap.find(nextWordPosition);
if (bigramProbabilityIt != mBigramMap.end()) {
- const int bigramProbability = bigramProbabilityIt->second;
- return ProbabilityUtils::computeProbabilityForBigram(
- unigramProbability, bigramProbability);
+ bigramProbability = bigramProbabilityIt->second;
}
}
- return ProbabilityUtils::backoff(unigramProbability);
+ return structurePolicy->getProbability(unigramProbability, bigramProbability);
}
private:
@@ -108,17 +111,18 @@ class MultiBigramMap {
AK_FORCE_INLINE int readBigramProbabilityFromBinaryDictionary(
const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos,
const int nextWordPosition, const int unigramProbability) {
- const int bigramsListPos = structurePolicy->getBigramsPositionOfNode(nodePos);
+ int bigramProbability = NOT_A_PROBABILITY;
+ const int bigramsListPos = structurePolicy->getBigramsPositionOfPtNode(nodePos);
BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(),
bigramsListPos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
if (bigramsIt.getBigramPos() == nextWordPosition) {
- return ProbabilityUtils::computeProbabilityForBigram(
- unigramProbability, bigramsIt.getProbability());
+ bigramProbability = bigramsIt.getProbability();
+ break;
}
}
- return ProbabilityUtils::backoff(unigramProbability);
+ return structurePolicy->getProbability(unigramProbability, bigramProbability);
}
static const size_t MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP;
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.cpp b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
index 7780efdfd..fbabd92f2 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.cpp
@@ -36,8 +36,8 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
const int *const xCoordinates, const int *const yCoordinates, const int *const times,
const int *const pointerIds, const bool isGeometric) {
ASSERT(isGeometric || (inputSize < MAX_WORD_LENGTH));
- mIsContinuousSuggestionPossible =
- ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible(
+ mIsContinuousSuggestionPossible = (mHasBeenUpdatedByGeometricInput != isGeometric) ?
+ false : ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible(
inputSize, xCoordinates, yCoordinates, times, mSampledInputSize,
&mSampledInputXs, &mSampledInputYs, &mSampledTimes, &mSampledInputIndice);
if (DEBUG_DICT) {
@@ -155,6 +155,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
if (DEBUG_GEO_FULL) {
AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize);
}
+ mHasBeenUpdatedByGeometricInput = isGeometric;
}
// This function basically converts from a length to an edit distance. Accordingly, it's obviously
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.h b/native/jni/src/suggest/core/layout/proximity_info_state.h
index dbcd54488..c94060fa9 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.h
@@ -46,10 +46,11 @@ class ProximityInfoState {
: mProximityInfo(0), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f),
mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0),
mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
- mIsContinuousSuggestionPossible(false), mSampledInputXs(), mSampledInputYs(),
- mSampledTimes(), mSampledInputIndice(), mSampledLengthCache(),
- mBeelineSpeedPercentiles(), mSampledNormalizedSquaredLengthCache(), mSpeedRates(),
- mDirections(), mCharProbabilities(), mSampledNearKeySets(), mSampledSearchKeySets(),
+ mIsContinuousSuggestionPossible(false), mHasBeenUpdatedByGeometricInput(false),
+ mSampledInputXs(), mSampledInputYs(), mSampledTimes(), mSampledInputIndice(),
+ mSampledLengthCache(), mBeelineSpeedPercentiles(),
+ mSampledNormalizedSquaredLengthCache(), mSpeedRates(), mDirections(),
+ mCharProbabilities(), mSampledNearKeySets(), mSampledSearchKeySets(),
mSampledSearchKeyVectors(), mTouchPositionCorrectionEnabled(false),
mSampledInputSize(0), mMostProbableStringProbability(0.0f) {
memset(mInputProximities, 0, sizeof(mInputProximities));
@@ -129,6 +130,10 @@ class ProximityInfoState {
return mSampledInputYs[index];
}
+ int getInputIndexOfSampledPoint(const int sampledIndex) const {
+ return mSampledInputIndice[sampledIndex];
+ }
+
bool hasSpaceProximity(const int index) const;
int getLengthCache(const int index) const {
@@ -204,6 +209,7 @@ class ProximityInfoState {
int mGridHeight;
int mGridWidth;
bool mIsContinuousSuggestionPossible;
+ bool mHasBeenUpdatedByGeometricInput;
std::vector<int> mSampledInputXs;
std::vector<int> mSampledInputYs;
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index 532411509..b95488ebd 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -47,11 +47,14 @@ class DictionaryStructureWithBufferPolicy {
virtual int getTerminalNodePositionOfWord(const int *const inWord,
const int length, const bool forceLowerCaseSearch) const = 0;
- virtual int getUnigramProbability(const int nodePos) const = 0;
+ virtual int getProbability(const int unigramProbability,
+ const int bigramProbability) const = 0;
- virtual int getShortcutPositionOfNode(const int nodePos) const = 0;
+ virtual int getUnigramProbabilityOfPtNode(const int nodePos) const = 0;
- virtual int getBigramsPositionOfNode(const int nodePos) const = 0;
+ virtual int getShortcutPositionOfPtNode(const int nodePos) const = 0;
+
+ virtual int getBigramsPositionOfPtNode(const int nodePos) const = 0;
virtual const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const = 0;
@@ -71,6 +74,12 @@ class DictionaryStructureWithBufferPolicy {
virtual bool removeBigramWords(const int *const word0, const int length0,
const int *const word1, const int length1) = 0;
+ virtual void flush(const char *const filePath) = 0;
+
+ virtual void flushWithGC(const char *const filePath) = 0;
+
+ virtual bool needsToRunGC() const = 0;
+
protected:
DictionaryStructureWithBufferPolicy() {}
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 0ca583f90..50f2bbd8d 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -23,6 +23,11 @@
namespace latinime {
+// 256K bytes threshold is heuristically used to distinguish dictionaries containing many unigrams
+// (e.g. main dictionary) from small dictionaries (e.g. contacts...)
+const int DicTraverseSession::DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION =
+ 256 * 1024;
+
void DicTraverseSession::init(const Dictionary *const dictionary, const int *prevWord,
int prevWordLength, const SuggestOptions *const suggestOptions) {
mDictionary = dictionary;
@@ -30,13 +35,13 @@ void DicTraverseSession::init(const Dictionary *const dictionary, const int *pre
->getMultiWordCostMultiplier();
mSuggestOptions = suggestOptions;
if (!prevWord) {
- mPrevWordPos = NOT_A_VALID_WORD_POS;
+ mPrevWordPos = NOT_A_DICT_POS;
return;
}
// TODO: merge following similar calls to getTerminalPosition into one case-insensitive call.
mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(
prevWord, prevWordLength, false /* forceLowerCaseSearch */);
- if (mPrevWordPos == NOT_A_VALID_WORD_POS) {
+ if (mPrevWordPos == NOT_A_DICT_POS) {
// Check bigrams for lower-cased previous word if original was not found. Useful for
// auto-capitalized words like "The [current_word]".
mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(
@@ -59,8 +64,9 @@ const DictionaryStructureWithBufferPolicy *DicTraverseSession::getDictionaryStru
return mDictionary->getDictionaryStructurePolicy();
}
-void DicTraverseSession::resetCache(const int nextActiveCacheSize, const int maxWords) {
- mDicNodesCache.reset(nextActiveCacheSize, maxWords);
+void DicTraverseSession::resetCache(const int thresholdForNextActiveDicNodes, const int maxWords) {
+ mDicNodesCache.reset(thresholdForNextActiveDicNodes /* nextActiveSize */,
+ maxWords /* terminalSize */);
mMultiBigramMap.clear();
mPartiallyCommited = false;
}
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h
index 23de5cc65..e0b1c67d9 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -37,8 +37,12 @@ class DicTraverseSession {
public:
// A factory method for DicTraverseSession
- static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr) {
- return new DicTraverseSession(env, localeStr);
+ static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr,
+ jlong dictSize) {
+ // To deal with the trade-off between accuracy and memory space, large cache is used for
+ // dictionaries larger that the threshold
+ return new DicTraverseSession(env, localeStr,
+ dictSize >= DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION);
}
static AK_FORCE_INLINE void initSessionInstance(DicTraverseSession *traverseSession,
@@ -54,10 +58,10 @@ class DicTraverseSession {
delete traverseSession;
}
- AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr)
- : mPrevWordPos(NOT_A_VALID_WORD_POS), mProximityInfo(0),
- mDictionary(0), mSuggestOptions(0), mDicNodesCache(), mMultiBigramMap(),
- mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
+ AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache)
+ : mPrevWordPos(NOT_A_DICT_POS), mProximityInfo(0),
+ mDictionary(0), mSuggestOptions(0), mDicNodesCache(usesLargeCache),
+ mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
mMultiWordCostMultiplier(1.0f) {
// NOTE: mProximityInfoStates is an array of instances.
// No need to initialize it explicitly here.
@@ -73,7 +77,7 @@ class DicTraverseSession {
const int inputSize, const int *const inputXs, const int *const inputYs,
const int *const times, const int *const pointerIds, const float maxSpatialDistance,
const int maxPointerCount);
- void resetCache(const int nextActiveCacheSize, const int maxWords);
+ void resetCache(const int thresholdForNextActiveDicNodes, const int maxWords);
const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const;
@@ -109,7 +113,9 @@ class DicTraverseSession {
if (usedPointerCount != 1) {
return false;
}
- *pointerId = usedPointerId;
+ if (pointerId) {
+ *pointerId = usedPointerId;
+ }
return true;
}
@@ -181,6 +187,7 @@ class DicTraverseSession {
DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession);
// threshold to start caching
static const int CACHE_START_INPUT_LENGTH_THRESHOLD;
+ static const int DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION;
void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs,
const int *const inputYs, const int *const times, const int *const pointerIds,
const int inputSize, const float maxSpatialDistance, const int maxPointerCount);
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 7d8dd21c5..b1340e12f 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -117,7 +117,7 @@ void Suggest::initializeSearch(DicTraverseSession *traverseSession, int commitPo
* Outputs the final list of suggestions (i.e., terminal nodes).
*/
int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequencies,
- int *outputCodePoints, int *spaceIndices, int *outputTypes) const {
+ int *outputCodePoints, int *outputIndicesToPartialCommit, int *outputTypes) const {
#if DEBUG_EVALUATE_MOST_PROBABLE_STRING
const int terminalSize = 0;
#else
@@ -139,6 +139,7 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
SCORING->getMostProbableString(traverseSession, terminalSize, languageWeight,
&outputCodePoints[0], &outputTypes[0], &frequencies[0]);
if (hasMostProbableString) {
+ outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX;
++outputWordIndex;
}
@@ -160,6 +161,9 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
|| (traverseSession->getInputSize()
>= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT
&& terminals[0].hasMultipleWords())) : false;
+ // TODO: have partial commit work even with multiple pointers.
+ const bool outputSecondWordFirstLetterInputIndex =
+ traverseSession->isOnlyOnePointerUsed(0 /* pointerId */);
// Output suggestion results here
for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS;
++terminalIndex) {
@@ -171,7 +175,9 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
terminalIndex, doubleLetterTerminalIndex, doubleLetterLevel);
const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight)
+ doubleLetterCost;
- const bool isPossiblyOffensiveWord = terminalDicNode->getProbability() <= 0;
+ const bool isPossiblyOffensiveWord =
+ traverseSession->getDictionaryStructurePolicy()->getProbability(
+ terminalDicNode->getProbability(), NOT_A_PROBABILITY) <= 0;
const bool isExactMatch = terminalDicNode->isExactMatch();
const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase();
// Heuristic: We exclude freq=0 first-char-uppercase words from exact match.
@@ -192,18 +198,21 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
terminalDicNode->isExactMatch()
|| (forceCommitMultiWords && terminalDicNode->hasMultipleWords())
|| (isValidWord && SCORING->doesAutoCorrectValidWord()));
- maxScore = max(maxScore, finalScore);
-
- // TODO: Implement a smarter auto-commit method for handling multi-word suggestions.
- // Index for top typing suggestion should be 0.
- if (isValidWord && outputWordIndex == 0) {
- terminalDicNode->outputSpacePositionsResult(spaceIndices);
+ if (maxScore < finalScore && isValidWord) {
+ maxScore = finalScore;
}
// Don't output invalid words. However, we still need to submit their shortcuts if any.
if (isValidWord) {
outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags;
frequencies[outputWordIndex] = finalScore;
+ if (outputSecondWordFirstLetterInputIndex) {
+ outputIndicesToPartialCommit[outputWordIndex] =
+ terminalDicNode->getSecondWordFirstInputIndex(
+ traverseSession->getProximityInfoState(0));
+ } else {
+ outputIndicesToPartialCommit[outputWordIndex] = NOT_AN_INDEX;
+ }
// Populate the outputChars array with the suggested word.
const int startIndex = outputWordIndex * MAX_WORD_LENGTH;
terminalDicNode->outputResult(&outputCodePoints[startIndex]);
@@ -214,12 +223,23 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
BinaryDictionaryShortcutIterator shortcutIt(
traverseSession->getDictionaryStructurePolicy()->getShortcutsStructurePolicy(),
traverseSession->getDictionaryStructurePolicy()
- ->getShortcutPositionOfNode(terminalDicNode->getPos()));
+ ->getShortcutPositionOfPtNode(terminalDicNode->getPos()));
// Shortcut is not supported for multiple words suggestions.
// TODO: Check shortcuts during traversal for multiple words suggestions.
const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode);
- outputWordIndex = ShortcutUtils::outputShortcuts(&shortcutIt, outputWordIndex,
- finalScore, outputCodePoints, frequencies, outputTypes, sameAsTyped);
+ const int updatedOutputWordIndex = ShortcutUtils::outputShortcuts(&shortcutIt,
+ outputWordIndex, finalScore, outputCodePoints, frequencies, outputTypes,
+ sameAsTyped);
+ const int secondWordFirstInputIndex = terminalDicNode->getSecondWordFirstInputIndex(
+ traverseSession->getProximityInfoState(0));
+ for (int i = outputWordIndex; i < updatedOutputWordIndex; ++i) {
+ if (outputSecondWordFirstLetterInputIndex) {
+ outputIndicesToPartialCommit[i] = secondWordFirstInputIndex;
+ } else {
+ outputIndicesToPartialCommit[i] = NOT_AN_INDEX;
+ }
+ }
+ outputWordIndex = updatedOutputWordIndex;
}
DicNode::managedDelete(terminalDicNode);
}
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 875cbe4e0..b24019632 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -55,7 +55,7 @@ class Suggest : public SuggestInterface {
void createNextWordDicNode(DicTraverseSession *traverseSession, DicNode *dicNode,
const bool spaceSubstitution) const;
int outputSuggestions(DicTraverseSession *traverseSession, int *frequencies,
- int *outputCodePoints, int *outputIndices, int *outputTypes) const;
+ int *outputCodePoints, int *outputIndicesToPartialCommit, int *outputTypes) const;
void initializeSearch(DicTraverseSession *traverseSession, int commitPoint) const;
void expandCurrentDicNodes(DicTraverseSession *traverseSession) const;
void processTerminalDicNode(DicTraverseSession *traverseSession, DicNode *dicNode) const;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
index beb9bee27..6ff95cac4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_policy.h
@@ -21,7 +21,7 @@
#include "defines.h"
#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
-#include "suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h"
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h"
namespace latinime {
@@ -33,16 +33,15 @@ class BigramListPolicy : public DictionaryBigramsStructurePolicy {
void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
int *const pos) const {
- const BigramListReadingUtils::BigramFlags flags =
- BigramListReadingUtils::getFlagsAndForwardPointer(mBigramsBuf, pos);
- *outBigramPos = BigramListReadingUtils::getBigramAddressAndForwardPointer(
- mBigramsBuf, flags, pos);
- *outProbability = BigramListReadingUtils::getProbabilityFromFlags(flags);
- *outHasNext = BigramListReadingUtils::hasNext(flags);
+ BigramListReadWriteUtils::BigramFlags flags;
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBigramsBuf, &flags,
+ outBigramPos, pos);
+ *outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(flags);
+ *outHasNext = BigramListReadWriteUtils::hasNext(flags);
}
void skipAllBigrams(int *const pos) const {
- BigramListReadingUtils::skipExistingBigrams(mBigramsBuf, pos);
+ BigramListReadWriteUtils::skipExistingBigrams(mBigramsBuf, pos);
}
private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp
new file mode 100644
index 000000000..1926b9831
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h"
+
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+const BigramListReadWriteUtils::BigramFlags BigramListReadWriteUtils::MASK_ATTRIBUTE_ADDRESS_TYPE =
+ 0x30;
+const BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
+const BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
+const BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
+const BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
+// Flag for presence of more attributes
+const BigramListReadWriteUtils::BigramFlags BigramListReadWriteUtils::FLAG_ATTRIBUTE_HAS_NEXT =
+ 0x80;
+// Mask for attribute probability, stored on 4 bits inside the flags byte.
+const BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
+const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
+
+/* static */ void BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ const uint8_t *const bigramsBuf, BigramFlags *const outBigramFlags,
+ int *const outTargetPtNodePos, int *const bigramEntryPos) {
+ const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf,
+ bigramEntryPos);
+ if (outBigramFlags) {
+ *outBigramFlags = bigramFlags;
+ }
+ const int targetPos = getBigramAddressAndAdvancePosition(bigramsBuf, bigramFlags,
+ bigramEntryPos);
+ if (outTargetPtNodePos) {
+ *outTargetPtNodePos = targetPos;
+ }
+}
+
+/* static */ void BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
+ int *const bigramListPos) {
+ BigramFlags flags;
+ do {
+ getBigramEntryPropertiesAndAdvancePosition(bigramsBuf, &flags, 0 /* outTargetPtNodePos */,
+ bigramListPos);
+ } while(hasNext(flags));
+}
+
+/* static */ int BigramListReadWriteUtils::getBigramAddressAndAdvancePosition(
+ const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
+ int offset = 0;
+ const int origin = *pos;
+ switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
+ offset = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+ break;
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
+ offset = ByteArrayUtils::readUint16AndAdvancePosition(bigramsBuf, pos);
+ break;
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
+ offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos);
+ break;
+ }
+ if (offset == DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID) {
+ return NOT_A_DICT_POS;
+ } else if (offset == DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET) {
+ return origin;
+ }
+ if (isOffsetNegative(flags)) {
+ return origin - offset;
+ } else {
+ return origin + offset;
+ }
+}
+
+/* static */ bool BigramListReadWriteUtils::setHasNextFlag(
+ BufferWithExtendableBuffer *const buffer, const bool hasNext, const int entryPos) {
+ const bool usesAdditionalBuffer = buffer->isInAdditionalBuffer(entryPos);
+ int readingPos = entryPos;
+ if (usesAdditionalBuffer) {
+ readingPos -= buffer->getOriginalBufferSize();
+ }
+ BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(
+ buffer->getBuffer(usesAdditionalBuffer), &readingPos);
+ if (hasNext) {
+ bigramFlags = bigramFlags | FLAG_ATTRIBUTE_HAS_NEXT;
+ } else {
+ bigramFlags = bigramFlags & (~FLAG_ATTRIBUTE_HAS_NEXT);
+ }
+ int writingPos = entryPos;
+ return buffer->writeUintAndAdvancePosition(bigramFlags, 1 /* size */, &writingPos);
+}
+
+/* static */ bool BigramListReadWriteUtils::createAndWriteBigramEntry(
+ BufferWithExtendableBuffer *const buffer, const int targetPos, const int probability,
+ const bool hasNext, int *const writingPos) {
+ BigramFlags flags;
+ if (!createAndGetBigramFlags(*writingPos, targetPos, probability, hasNext, &flags)) {
+ return false;
+ }
+ return writeBigramEntry(buffer, flags, targetPos, writingPos);
+}
+
+/* static */ bool BigramListReadWriteUtils::writeBigramEntry(
+ BufferWithExtendableBuffer *const bufferToWrite, const BigramFlags flags,
+ const int targetPtNodePos, int *const writingPos) {
+ const int offset = getBigramTargetOffset(targetPtNodePos, *writingPos);
+ const BigramFlags flagsToWrite = (offset < 0) ?
+ (flags | FLAG_ATTRIBUTE_OFFSET_NEGATIVE) : (flags & ~FLAG_ATTRIBUTE_OFFSET_NEGATIVE);
+ if (!bufferToWrite->writeUintAndAdvancePosition(flagsToWrite, 1 /* size */, writingPos)) {
+ return false;
+ }
+ const uint32_t absOffest = abs(offset);
+ const int bigramTargetFieldSize = attributeAddressSize(flags);
+ return bufferToWrite->writeUintAndAdvancePosition(absOffest, bigramTargetFieldSize,
+ writingPos);
+}
+
+// Returns true if the bigram entry is valid and put entry flags into out*.
+/* static */ bool BigramListReadWriteUtils::createAndGetBigramFlags(const int entryPos,
+ const int targetPtNodePos, const int probability, const bool hasNext,
+ BigramFlags *const outBigramFlags) {
+ BigramFlags flags = probability & MASK_ATTRIBUTE_PROBABILITY;
+ if (hasNext) {
+ flags |= FLAG_ATTRIBUTE_HAS_NEXT;
+ }
+ const int offset = getBigramTargetOffset(targetPtNodePos, entryPos);
+ if (offset < 0) {
+ flags |= FLAG_ATTRIBUTE_OFFSET_NEGATIVE;
+ }
+ const uint32_t absOffest = abs(offset);
+ if ((absOffest >> 24) != 0) {
+ // Offset is too large.
+ return false;
+ } else if ((absOffest >> 16) != 0) {
+ flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+ } else if ((absOffest >> 8) != 0) {
+ flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
+ } else {
+ flags |= FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
+ }
+ // Currently, all newly written bigram position fields are 3 bytes to simplify dictionary
+ // writing.
+ // TODO: Remove following 2 lines and optimize memory space.
+ flags = (flags & (~MASK_ATTRIBUTE_ADDRESS_TYPE)) | FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+ *outBigramFlags = flags;
+ return true;
+}
+
+/* static */ int BigramListReadWriteUtils::getBigramTargetOffset(const int targetPtNodePos,
+ const int entryPos) {
+ if (targetPtNodePos == NOT_A_DICT_POS) {
+ return DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID;
+ } else {
+ const int offset = targetPtNodePos - (entryPos + 1 /* bigramFlagsField */);
+ if (offset == 0) {
+ return DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET;
+ } else {
+ return offset;
+ }
+ }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h
index d0c584bd5..eabe4e099 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h
@@ -14,24 +14,25 @@
* limitations under the License.
*/
-#ifndef LATINIME_BIGRAM_LIST_READING_UTILS_H
-#define LATINIME_BIGRAM_LIST_READING_UTILS_H
+#ifndef LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H
+#define LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H
+#include <cstdlib>
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
-class BigramListReadingUtils {
+class BufferWithExtendableBuffer;
+
+class BigramListReadWriteUtils {
public:
typedef uint8_t BigramFlags;
- static AK_FORCE_INLINE BigramFlags getFlagsAndForwardPointer(
- const uint8_t *const bigramsBuf, int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
- }
+ static void getBigramEntryPropertiesAndAdvancePosition(const uint8_t *const bigramsBuf,
+ BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
+ int *const bigramEntryPos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -42,21 +43,38 @@ public:
}
// Bigrams reading methods
- static AK_FORCE_INLINE void skipExistingBigrams(const uint8_t *const bigramsBuf,
- int *const pos) {
- BigramFlags flags = getFlagsAndForwardPointer(bigramsBuf, pos);
- while (hasNext(flags)) {
- *pos += attributeAddressSize(flags);
- flags = getFlagsAndForwardPointer(bigramsBuf, pos);
- }
- *pos += attributeAddressSize(flags);
+ static void skipExistingBigrams(const uint8_t *const bigramsBuf, int *const bigramListPos);
+
+ // Returns the size of the bigram position field that is stored in bigram flags.
+ static AK_FORCE_INLINE int attributeAddressSize(const BigramFlags flags) {
+ return (flags & MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
+ /* Note: this is a value-dependant optimization of what may probably be
+ more readably written this way:
+ switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) {
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1;
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2;
+ case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3;
+ default: return 0;
+ }
+ */
}
- static int getBigramAddressAndForwardPointer(const uint8_t *const bigramsBuf,
- const BigramFlags flags, int *const pos);
+ static bool setHasNextFlag(BufferWithExtendableBuffer *const buffer,
+ const bool hasNext, const int entryPos);
+
+ static AK_FORCE_INLINE BigramFlags setProbabilityInFlags(const BigramFlags flags,
+ const int probability) {
+ return (flags & (~MASK_ATTRIBUTE_PROBABILITY)) | (probability & MASK_ATTRIBUTE_PROBABILITY);
+ }
+
+ static bool createAndWriteBigramEntry(BufferWithExtendableBuffer *const buffer,
+ const int targetPos, const int probability, const bool hasNext, int *const writingPos);
+
+ static bool writeBigramEntry(BufferWithExtendableBuffer *const buffer, const BigramFlags flags,
+ const int targetOffset, int *const writingPos);
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadingUtils);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadWriteUtils);
static const BigramFlags MASK_ATTRIBUTE_ADDRESS_TYPE;
static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
@@ -67,22 +85,18 @@ private:
static const BigramFlags MASK_ATTRIBUTE_PROBABILITY;
static const int ATTRIBUTE_ADDRESS_SHIFT;
+ // Returns true if the bigram entry is valid and put entry flags into out*.
+ static bool createAndGetBigramFlags(const int entryPos, const int targetPos,
+ const int probability, const bool hasNext, BigramFlags *const outBigramFlags);
+
static AK_FORCE_INLINE bool isOffsetNegative(const BigramFlags flags) {
return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0;
}
- static AK_FORCE_INLINE int attributeAddressSize(const BigramFlags flags) {
- return (flags & MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
- /* Note: this is a value-dependant optimization of what may probably be
- more readably written this way:
- switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) {
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3;
- default: return 0;
- }
- */
- }
+ static int getBigramAddressAndAdvancePosition(const uint8_t *const bigramsBuf,
+ const BigramFlags flags, int *const pos);
+
+ static int getBigramTargetOffset(const int targetPtNodePos, const int entryPos);
};
} // namespace latinime
-#endif // LATINIME_BIGRAM_LIST_READING_UTILS_H
+#endif // LATINIME_BIGRAM_LIST_READ_WRITE_UTILS_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp
deleted file mode 100644
index 6da0e8b85..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "suggest/policyimpl/dictionary/bigram/bigram_list_reading_utils.h"
-
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
-
-namespace latinime {
-
-const BigramListReadingUtils::BigramFlags BigramListReadingUtils::MASK_ATTRIBUTE_ADDRESS_TYPE =
- 0x30;
-const BigramListReadingUtils::BigramFlags
- BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
-const BigramListReadingUtils::BigramFlags
- BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
-const BigramListReadingUtils::BigramFlags
- BigramListReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
-const BigramListReadingUtils::BigramFlags
- BigramListReadingUtils::FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
-// Flag for presence of more attributes
-const BigramListReadingUtils::BigramFlags BigramListReadingUtils::FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
-// Mask for attribute probability, stored on 4 bits inside the flags byte.
-const BigramListReadingUtils::BigramFlags
- BigramListReadingUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
-const int BigramListReadingUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
-
-/* static */ int BigramListReadingUtils::getBigramAddressAndForwardPointer(
- const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
- int offset = 0;
- const int origin = *pos;
- switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- offset = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
- break;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- offset = ByteArrayUtils::readUint16AndAdvancePosition(bigramsBuf, pos);
- break;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos);
- break;
- }
- if (isOffsetNegative(flags)) {
- return origin - offset;
- } else {
- return origin + offset;
- }
-}
-
-} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp
new file mode 100644
index 000000000..29307b56a
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h"
+
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
+#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+const int DynamicBigramListPolicy::CONTINUING_BIGRAM_LINK_COUNT_LIMIT = 10000;
+const int DynamicBigramListPolicy::BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT = 100000;
+
+void DynamicBigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability,
+ bool *const outHasNext, int *const bigramEntryPos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramEntryPos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *bigramEntryPos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int originalBigramPos;
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(buffer, &bigramFlags,
+ &originalBigramPos, bigramEntryPos);
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ *outBigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
+ *outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(bigramFlags);
+ *outHasNext = BigramListReadWriteUtils::hasNext(bigramFlags);
+ if (usesAdditionalBuffer) {
+ *bigramEntryPos += mBuffer->getOriginalBufferSize();
+ }
+}
+
+void DynamicBigramListPolicy::skipAllBigrams(int *const bigramListPos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *bigramListPos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::skipExistingBigrams(buffer, bigramListPos);
+ if (usesAdditionalBuffer) {
+ *bigramListPos += mBuffer->getOriginalBufferSize();
+ }
+}
+
+bool DynamicBigramListPolicy::copyAllBigrams(BufferWithExtendableBuffer *const bufferToWrite,
+ int *const fromPos, int *const toPos, int *const outBigramsCount) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*fromPos);
+ if (usesAdditionalBuffer) {
+ *fromPos -= mBuffer->getOriginalBufferSize();
+ }
+ *outBigramsCount = 0;
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int bigramEntryCount = 0;
+ int lastWrittenEntryPos = NOT_A_DICT_POS;
+ do {
+ if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) {
+ AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d",
+ bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT);
+ ASSERT(false);
+ return false;
+ }
+ // The buffer address can be changed after calling buffer writing methods.
+ int originalBigramPos;
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos,
+ fromPos);
+ if (originalBigramPos == NOT_A_DICT_POS) {
+ // skip invalid bigram entry.
+ continue;
+ }
+ if (usesAdditionalBuffer) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
+ if (bigramPos == NOT_A_DICT_POS) {
+ // Target PtNode has been invalidated.
+ continue;
+ }
+ lastWrittenEntryPos = *toPos;
+ if (!BigramListReadWriteUtils::createAndWriteBigramEntry(bufferToWrite, bigramPos,
+ BigramListReadWriteUtils::getProbabilityFromFlags(bigramFlags),
+ BigramListReadWriteUtils::hasNext(bigramFlags), toPos)) {
+ return false;
+ }
+ (*outBigramsCount)++;
+ } while(BigramListReadWriteUtils::hasNext(bigramFlags));
+ // Makes the last entry the terminal of the list. Updates the flags.
+ if (lastWrittenEntryPos != NOT_A_DICT_POS) {
+ if (!BigramListReadWriteUtils::setHasNextFlag(bufferToWrite, false /* hasNext */,
+ lastWrittenEntryPos)) {
+ return false;
+ }
+ }
+ if (usesAdditionalBuffer) {
+ *fromPos += mBuffer->getOriginalBufferSize();
+ }
+ return true;
+}
+
+// Finding useless bigram entries and remove them. Bigram entry is useless when the target PtNode
+// has been deleted or is not a valid terminal.
+bool DynamicBigramListPolicy::updateAllBigramEntriesAndDeleteUselessEntries(
+ int *const bigramListPos) {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos);
+ if (usesAdditionalBuffer) {
+ *bigramListPos -= mBuffer->getOriginalBufferSize();
+ }
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy);
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int bigramEntryCount = 0;
+ do {
+ if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) {
+ AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d",
+ bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT);
+ ASSERT(false);
+ return false;
+ }
+ int bigramEntryPos = *bigramListPos;
+ int originalBigramPos;
+ // The buffer address can be changed after calling buffer writing methods.
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos,
+ bigramListPos);
+ if (usesAdditionalBuffer) {
+ bigramEntryPos += mBuffer->getOriginalBufferSize();
+ }
+ if (originalBigramPos == NOT_A_DICT_POS) {
+ // This entry has already been removed.
+ continue;
+ }
+ if (usesAdditionalBuffer) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ const int bigramTargetNodePos =
+ followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(bigramTargetNodePos);
+ // TODO: Update probability for supporting probability decaying.
+ if (nodeReader.isDeleted() || !nodeReader.isTerminal()
+ || bigramTargetNodePos == NOT_A_DICT_POS) {
+ // The target is no longer valid terminal. Invalidate the current bigram entry.
+ if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags,
+ NOT_A_DICT_POS /* targetOffset */, &bigramEntryPos)) {
+ return false;
+ }
+ }
+ } while(BigramListReadWriteUtils::hasNext(bigramFlags));
+ return true;
+}
+
+// Updates bigram target PtNode positions in the list after the placing step in GC.
+bool DynamicBigramListPolicy::updateAllBigramTargetPtNodePositions(int *const bigramListPos,
+ const DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap *const
+ ptNodePositionRelocationMap) {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos);
+ if (usesAdditionalBuffer) {
+ *bigramListPos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int bigramEntryCount = 0;
+ do {
+ if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) {
+ AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d",
+ bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT);
+ ASSERT(false);
+ return false;
+ }
+ int bigramEntryPos = *bigramListPos;
+ if (usesAdditionalBuffer) {
+ bigramEntryPos += mBuffer->getOriginalBufferSize();
+ }
+ int bigramTargetPtNodePos;
+ // The buffer address can be changed after calling buffer writing methods.
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &bigramTargetPtNodePos,
+ bigramListPos);
+ if (bigramTargetPtNodePos == NOT_A_DICT_POS) {
+ continue;
+ }
+ if (usesAdditionalBuffer) {
+ bigramTargetPtNodePos += mBuffer->getOriginalBufferSize();
+ }
+
+ DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::const_iterator it =
+ ptNodePositionRelocationMap->find(bigramTargetPtNodePos);
+ if (it != ptNodePositionRelocationMap->end()) {
+ bigramTargetPtNodePos = it->second;
+ } else {
+ bigramTargetPtNodePos = NOT_A_DICT_POS;
+ }
+ if (!BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags,
+ bigramTargetPtNodePos, &bigramEntryPos)) {
+ return false;
+ }
+ } while(BigramListReadWriteUtils::hasNext(bigramFlags));
+ return true;
+}
+
+bool DynamicBigramListPolicy::addNewBigramEntryToBigramList(const int bigramTargetPos,
+ const int probability, int *const bigramListPos) {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*bigramListPos);
+ if (usesAdditionalBuffer) {
+ *bigramListPos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int bigramEntryCount = 0;
+ do {
+ if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) {
+ AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d",
+ bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT);
+ ASSERT(false);
+ return false;
+ }
+ int entryPos = *bigramListPos;
+ if (usesAdditionalBuffer) {
+ entryPos += mBuffer->getOriginalBufferSize();
+ }
+ int originalBigramPos;
+ // The buffer address can be changed after calling buffer writing methods.
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos,
+ bigramListPos);
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ if (followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos) == bigramTargetPos) {
+ // Update this bigram entry.
+ const BigramListReadWriteUtils::BigramFlags updatedFlags =
+ BigramListReadWriteUtils::setProbabilityInFlags(bigramFlags, probability);
+ return BigramListReadWriteUtils::writeBigramEntry(mBuffer, updatedFlags,
+ originalBigramPos, &entryPos);
+ }
+ if (BigramListReadWriteUtils::hasNext(bigramFlags)) {
+ continue;
+ }
+ // The current last entry is found.
+ // First, update the flags of the last entry.
+ if (!BigramListReadWriteUtils::setHasNextFlag(mBuffer, true /* hasNext */, entryPos)) {
+ return false;
+ }
+ if (usesAdditionalBuffer) {
+ *bigramListPos += mBuffer->getOriginalBufferSize();
+ }
+ // Then, add a new entry after the last entry.
+ return writeNewBigramEntry(bigramTargetPos, probability, bigramListPos);
+ } while(BigramListReadWriteUtils::hasNext(bigramFlags));
+ // We return directly from the while loop.
+ ASSERT(false);
+ return false;
+}
+
+bool DynamicBigramListPolicy::writeNewBigramEntry(const int bigramTargetPos, const int probability,
+ int *const writingPos) {
+ // hasNext is false because we are adding a new bigram entry at the end of the bigram list.
+ return BigramListReadWriteUtils::createAndWriteBigramEntry(mBuffer, bigramTargetPos,
+ probability, false /* hasNext */, writingPos);
+}
+
+bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int bigramTargetPos) {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(bigramListPos);
+ int pos = bigramListPos;
+ if (usesAdditionalBuffer) {
+ pos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::BigramFlags bigramFlags;
+ int bigramEntryCount = 0;
+ do {
+ if (++bigramEntryCount > BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT) {
+ AKLOGE("Too many bigram entries. Entry count: %d, Limit: %d",
+ bigramEntryCount, BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT);
+ ASSERT(false);
+ return false;
+ }
+ int bigramEntryPos = pos;
+ int originalBigramPos;
+ // The buffer address can be changed after calling buffer writing methods.
+ BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), &bigramFlags, &originalBigramPos, &pos);
+ if (usesAdditionalBuffer) {
+ bigramEntryPos += mBuffer->getOriginalBufferSize();
+ }
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
+ if (bigramPos != bigramTargetPos) {
+ continue;
+ }
+ // Target entry is found. Write an invalid target position to mark the bigram invalid.
+ return BigramListReadWriteUtils::writeBigramEntry(mBuffer, bigramFlags,
+ NOT_A_DICT_POS /* targetOffset */, &bigramEntryPos);
+ } while(BigramListReadWriteUtils::hasNext(bigramFlags));
+ return false;
+}
+
+int DynamicBigramListPolicy::followBigramLinkAndGetCurrentBigramPtNodePos(
+ const int originalBigramPos) const {
+ if (originalBigramPos == NOT_A_DICT_POS) {
+ return NOT_A_DICT_POS;
+ }
+ int currentPos = originalBigramPos;
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy);
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(currentPos);
+ int bigramLinkCount = 0;
+ while (nodeReader.getBigramLinkedNodePos() != NOT_A_DICT_POS) {
+ currentPos = nodeReader.getBigramLinkedNodePos();
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(currentPos);
+ bigramLinkCount++;
+ if (bigramLinkCount > CONTINUING_BIGRAM_LINK_COUNT_LIMIT) {
+ AKLOGE("Bigram link is invalid. start position: %d", originalBigramPos);
+ ASSERT(false);
+ return NOT_A_DICT_POS;
+ }
+ }
+ return currentPos;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h
new file mode 100644
index 000000000..8ea318a41
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H
+#define LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+class DictionaryShortcutsStructurePolicy;
+
+/*
+ * This is a dynamic version of BigramListPolicy and supports an additional buffer.
+ */
+class DynamicBigramListPolicy : public DictionaryBigramsStructurePolicy {
+ public:
+ DynamicBigramListPolicy(BufferWithExtendableBuffer *const buffer,
+ const DictionaryShortcutsStructurePolicy *const shortcutPolicy)
+ : mBuffer(buffer), mShortcutPolicy(shortcutPolicy) {}
+
+ ~DynamicBigramListPolicy() {}
+
+ void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
+ int *const bigramEntryPos) const;
+
+ void skipAllBigrams(int *const bigramListPos) const;
+
+ // Copy bigrams from the bigram list that starts at fromPos in mBuffer to toPos in
+ // bufferToWrite and advance these positions after bigram lists. This method skips invalid
+ // bigram entries and write the valid bigram entry count to outBigramsCount.
+ bool copyAllBigrams(BufferWithExtendableBuffer *const bufferToWrite, int *const fromPos,
+ int *const toPos, int *const outBigramsCount) const;
+
+ bool updateAllBigramEntriesAndDeleteUselessEntries(int *const bigramListPos);
+
+ bool updateAllBigramTargetPtNodePositions(int *const bigramListPos,
+ const DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap *const
+ ptNodePositionRelocationMap);
+
+ bool addNewBigramEntryToBigramList(const int bigramTargetPos, const int probability,
+ int *const bigramListPos);
+
+ bool writeNewBigramEntry(const int bigramTargetPos, const int probability,
+ int *const writingPos);
+
+ // Return if targetBigramPos is found or not.
+ bool removeBigram(const int bigramListPos, const int bigramTargetPos);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicBigramListPolicy);
+
+ static const int CONTINUING_BIGRAM_LINK_COUNT_LIMIT;
+ static const int BIGRAM_ENTRY_COUNT_IN_A_BIGRAM_LIST_LIMIT;
+
+ BufferWithExtendableBuffer *const mBuffer;
+ const DictionaryShortcutsStructurePolicy *const mShortcutPolicy;
+
+ // Follow bigram link and return the position of bigram target PtNode that is currently valid.
+ int followBigramLinkAndGetCurrentBigramPtNodePos(const int originalBigramPos) const;
+};
+} // namespace latinime
+#endif // LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/binary_format.h b/native/jni/src/suggest/policyimpl/dictionary/binary_format.h
deleted file mode 100644
index 23f4c7fec..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/binary_format.h
+++ /dev/null
@@ -1,470 +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.
- */
-
-#ifndef LATINIME_BINARY_FORMAT_H
-#define LATINIME_BINARY_FORMAT_H
-
-#include <stdint.h>
-
-#include "suggest/core/dictionary/probability_utils.h"
-#include "utils/char_utils.h"
-
-namespace latinime {
-
-class BinaryFormat {
- public:
- // Mask and flags for children address type selection.
- static const int MASK_GROUP_ADDRESS_TYPE = 0xC0;
-
- // Flag for single/multiple char group
- static const int FLAG_HAS_MULTIPLE_CHARS = 0x20;
-
- // Flag for terminal groups
- static const int FLAG_IS_TERMINAL = 0x10;
-
- // Flag for shortcut targets presence
- static const int FLAG_HAS_SHORTCUT_TARGETS = 0x08;
- // Flag for bigram presence
- static const int FLAG_HAS_BIGRAMS = 0x04;
- // Flag for non-words (typically, shortcut only entries)
- static const int FLAG_IS_NOT_A_WORD = 0x02;
- // Flag for blacklist
- static const int FLAG_IS_BLACKLISTED = 0x01;
-
- // Attribute (bigram/shortcut) related flags:
- // Flag for presence of more attributes
- static const int FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
- // Flag for sign of offset. If this flag is set, the offset value must be negated.
- static const int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
-
- // Mask for attribute probability, stored on 4 bits inside the flags byte.
- static const int MASK_ATTRIBUTE_PROBABILITY = 0x0F;
-
- // Mask and flags for attribute address type selection.
- static const int MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30;
-
- static int getGroupCountAndForwardPointer(const uint8_t *const dict, int *pos);
- static uint8_t getFlagsAndForwardPointer(const uint8_t *const dict, int *pos);
- static int getCodePointAndForwardPointer(const uint8_t *const dict, int *pos);
- static int readProbabilityWithoutMovingPointer(const uint8_t *const dict, const int pos);
- static int skipOtherCharacters(const uint8_t *const dict, const int pos);
- static int skipChildrenPosition(const uint8_t flags, const int pos);
- static int skipProbability(const uint8_t flags, const int pos);
- static int skipShortcuts(const uint8_t *const dict, const uint8_t flags, const int pos);
- static int skipChildrenPosAndAttributes(const uint8_t *const dict, const uint8_t flags,
- const int pos);
- static int readChildrenPosition(const uint8_t *const dict, const uint8_t flags, const int pos);
- static bool hasChildrenInFlags(const uint8_t flags);
- static int getTerminalPosition(const uint8_t *const root, const int *const inWord,
- const int length, const bool forceLowerCaseSearch);
- static int getCodePointsAndProbabilityAndReturnCodePointCount(
- const uint8_t *const root, const int nodePos, const int maxCodePointCount,
- int *const outCodePoints, int *const outUnigramProbability);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryFormat);
-
- static const int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00;
- static const int FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40;
- static const int FLAG_GROUP_ADDRESS_TYPE_TWOBYTES = 0x80;
- static const int FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = 0xC0;
- static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
- static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
- static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
-
- static const int CHARACTER_ARRAY_TERMINATOR_SIZE = 1;
- static const int MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
- static const int CHARACTER_ARRAY_TERMINATOR = 0x1F;
- static const int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2;
- static const int NO_FLAGS = 0;
- static int skipAllAttributes(const uint8_t *const dict, const uint8_t flags, const int pos);
- static int skipBigrams(const uint8_t *const dict, const uint8_t flags, const int pos);
-};
-
-AK_FORCE_INLINE int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t *const dict,
- int *pos) {
- const int msb = dict[(*pos)++];
- if (msb < 0x80) return msb;
- return ((msb & 0x7F) << 8) | dict[(*pos)++];
-}
-
-inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t *const dict, int *pos) {
- return dict[(*pos)++];
-}
-
-AK_FORCE_INLINE int BinaryFormat::getCodePointAndForwardPointer(const uint8_t *const dict,
- int *pos) {
- const int origin = *pos;
- const int codePoint = dict[origin];
- if (codePoint < MINIMAL_ONE_BYTE_CHARACTER_VALUE) {
- if (codePoint == CHARACTER_ARRAY_TERMINATOR) {
- *pos = origin + 1;
- return NOT_A_CODE_POINT;
- } else {
- *pos = origin + 3;
- const int char_1 = codePoint << 16;
- const int char_2 = char_1 + (dict[origin + 1] << 8);
- return char_2 + dict[origin + 2];
- }
- } else {
- *pos = origin + 1;
- return codePoint;
- }
-}
-
-inline int BinaryFormat::readProbabilityWithoutMovingPointer(const uint8_t *const dict,
- const int pos) {
- return dict[pos];
-}
-
-AK_FORCE_INLINE int BinaryFormat::skipOtherCharacters(const uint8_t *const dict, const int pos) {
- int currentPos = pos;
- int character = dict[currentPos++];
- while (CHARACTER_ARRAY_TERMINATOR != character) {
- if (character < MINIMAL_ONE_BYTE_CHARACTER_VALUE) {
- currentPos += MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE;
- }
- character = dict[currentPos++];
- }
- return currentPos;
-}
-
-static inline int attributeAddressSize(const uint8_t flags) {
- static const int ATTRIBUTE_ADDRESS_SHIFT = 4;
- return (flags & BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
- /* Note: this is a value-dependant optimization of what may probably be
- more readably written this way:
- switch (flags * BinaryFormat::MASK_ATTRIBUTE_ADDRESS_TYPE) {
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: return 1;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: return 2;
- case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTE: return 3;
- default: return 0;
- }
- */
-}
-
-static AK_FORCE_INLINE int skipExistingBigrams(const uint8_t *const dict, const int pos) {
- int currentPos = pos;
- uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(dict, &currentPos);
- while (flags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT) {
- currentPos += attributeAddressSize(flags);
- flags = BinaryFormat::getFlagsAndForwardPointer(dict, &currentPos);
- }
- currentPos += attributeAddressSize(flags);
- return currentPos;
-}
-
-static inline int childrenAddressSize(const uint8_t flags) {
- static const int CHILDREN_ADDRESS_SHIFT = 6;
- return (BinaryFormat::MASK_GROUP_ADDRESS_TYPE & flags) >> CHILDREN_ADDRESS_SHIFT;
- /* See the note in attributeAddressSize. The same applies here */
-}
-
-static AK_FORCE_INLINE int shortcutByteSize(const uint8_t *const dict, const int pos) {
- return (static_cast<int>(dict[pos] << 8)) + (dict[pos + 1]);
-}
-
-inline int BinaryFormat::skipChildrenPosition(const uint8_t flags, const int pos) {
- return pos + childrenAddressSize(flags);
-}
-
-inline int BinaryFormat::skipProbability(const uint8_t flags, const int pos) {
- return FLAG_IS_TERMINAL & flags ? pos + 1 : pos;
-}
-
-AK_FORCE_INLINE int BinaryFormat::skipShortcuts(const uint8_t *const dict, const uint8_t flags,
- const int pos) {
- if (FLAG_HAS_SHORTCUT_TARGETS & flags) {
- return pos + shortcutByteSize(dict, pos);
- } else {
- return pos;
- }
-}
-
-AK_FORCE_INLINE int BinaryFormat::skipBigrams(const uint8_t *const dict, const uint8_t flags,
- const int pos) {
- if (FLAG_HAS_BIGRAMS & flags) {
- return skipExistingBigrams(dict, pos);
- } else {
- return pos;
- }
-}
-
-AK_FORCE_INLINE int BinaryFormat::skipAllAttributes(const uint8_t *const dict, const uint8_t flags,
- const int pos) {
- // This function skips all attributes: shortcuts and bigrams.
- int newPos = pos;
- newPos = skipShortcuts(dict, flags, newPos);
- newPos = skipBigrams(dict, flags, newPos);
- return newPos;
-}
-
-AK_FORCE_INLINE int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t *const dict,
- const uint8_t flags, const int pos) {
- int currentPos = pos;
- currentPos = skipChildrenPosition(flags, currentPos);
- currentPos = skipAllAttributes(dict, flags, currentPos);
- return currentPos;
-}
-
-AK_FORCE_INLINE int BinaryFormat::readChildrenPosition(const uint8_t *const dict,
- const uint8_t flags, const int pos) {
- int offset = 0;
- switch (MASK_GROUP_ADDRESS_TYPE & flags) {
- case FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
- offset = dict[pos];
- break;
- case FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
- offset = dict[pos] << 8;
- offset += dict[pos + 1];
- break;
- case FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
- offset = dict[pos] << 16;
- offset += dict[pos + 1] << 8;
- offset += dict[pos + 2];
- break;
- default:
- // If we come here, it means we asked for the children of a word with
- // no children.
- return -1;
- }
- return pos + offset;
-}
-
-inline bool BinaryFormat::hasChildrenInFlags(const uint8_t flags) {
- return (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS != (MASK_GROUP_ADDRESS_TYPE & flags));
-}
-
-// This function gets the byte position of the last chargroup of the exact matching word in the
-// dictionary. If no match is found, it returns NOT_A_VALID_WORD_POS.
-AK_FORCE_INLINE int BinaryFormat::getTerminalPosition(const uint8_t *const root,
- const int *const inWord, const int length, const bool forceLowerCaseSearch) {
- int pos = 0;
- int wordPos = 0;
-
- while (true) {
- // If we already traversed the tree further than the word is long, there means
- // there was no match (or we would have found it).
- if (wordPos >= length) return NOT_A_VALID_WORD_POS;
- int charGroupCount = BinaryFormat::getGroupCountAndForwardPointer(root, &pos);
- const int wChar = forceLowerCaseSearch
- ? CharUtils::toLowerCase(inWord[wordPos]) : inWord[wordPos];
- while (true) {
- // If there are no more character groups in this node, it means we could not
- // find a matching character for this depth, therefore there is no match.
- if (0 >= charGroupCount) return NOT_A_VALID_WORD_POS;
- const int charGroupPos = pos;
- const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
- int character = BinaryFormat::getCodePointAndForwardPointer(root, &pos);
- if (character == wChar) {
- // This is the correct node. Only one character group may start with the same
- // char within a node, so either we found our match in this node, or there is
- // no match and we can return NOT_A_VALID_WORD_POS. So we will check all the
- // characters in this character group indeed does match.
- if (FLAG_HAS_MULTIPLE_CHARS & flags) {
- character = BinaryFormat::getCodePointAndForwardPointer(root, &pos);
- while (NOT_A_CODE_POINT != character) {
- ++wordPos;
- // If we shoot the length of the word we search for, or if we find a single
- // character that does not match, as explained above, it means the word is
- // not in the dictionary (by virtue of this chargroup being the only one to
- // match the word on the first character, but not matching the whole word).
- if (wordPos >= length) return NOT_A_VALID_WORD_POS;
- if (inWord[wordPos] != character) return NOT_A_VALID_WORD_POS;
- character = BinaryFormat::getCodePointAndForwardPointer(root, &pos);
- }
- }
- // If we come here we know that so far, we do match. Either we are on a terminal
- // and we match the length, in which case we found it, or we traverse children.
- // If we don't match the length AND don't have children, then a word in the
- // dictionary fully matches a prefix of the searched word but not the full word.
- ++wordPos;
- if (FLAG_IS_TERMINAL & flags) {
- if (wordPos == length) {
- return charGroupPos;
- }
- pos = BinaryFormat::skipProbability(FLAG_IS_TERMINAL, pos);
- }
- if (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS == (MASK_GROUP_ADDRESS_TYPE & flags)) {
- return NOT_A_VALID_WORD_POS;
- }
- // We have children and we are still shorter than the word we are searching for, so
- // we need to traverse children. Put the pointer on the children position, and
- // break
- pos = BinaryFormat::readChildrenPosition(root, flags, pos);
- break;
- } else {
- // This chargroup does not match, so skip the remaining part and go to the next.
- if (FLAG_HAS_MULTIPLE_CHARS & flags) {
- pos = BinaryFormat::skipOtherCharacters(root, pos);
- }
- pos = BinaryFormat::skipProbability(flags, pos);
- pos = BinaryFormat::skipChildrenPosAndAttributes(root, flags, pos);
- }
- --charGroupCount;
- }
- }
-}
-
-// This function searches for a terminal in the dictionary by its address.
-// Due to the fact that words are ordered in the dictionary in a strict breadth-first order,
-// it is possible to check for this with advantageous complexity. For each node, we search
-// for groups with children and compare the children address with the address we look for.
-// When we shoot the address we look for, it means the word we look for is in the children
-// of the previous group. The only tricky part is the fact that if we arrive at the end of a
-// node with the last group's children address still less than what we are searching for, we
-// must descend the last group's children (for example, if the word we are searching for starts
-// with a z, it's the last group of the root node, so all children addresses will be smaller
-// than the address we look for, and we have to descend the z node).
-/* Parameters :
- * root: the dictionary buffer
- * address: the byte position of the last chargroup of the word we are searching for (this is
- * what is stored as the "bigram address" in each bigram)
- * outword: an array to write the found word, with MAX_WORD_LENGTH size.
- * outUnigramProbability: a pointer to an int to write the probability into.
- * Return value : the length of the word, of 0 if the word was not found.
- */
-AK_FORCE_INLINE int BinaryFormat::getCodePointsAndProbabilityAndReturnCodePointCount(
- const uint8_t *const root, const int nodePos, const int maxCodePointCount,
- int *const outCodePoints, int *const outUnigramProbability) {
- int pos = 0;
- int wordPos = 0;
-
- // One iteration of the outer loop iterates through nodes. As stated above, we will only
- // traverse nodes that are actually a part of the terminal we are searching, so each time
- // we enter this loop we are one depth level further than last time.
- // The only reason we count nodes is because we want to reduce the probability of infinite
- // looping in case there is a bug. Since we know there is an upper bound to the depth we are
- // supposed to traverse, it does not hurt to count iterations.
- for (int loopCount = maxCodePointCount; loopCount > 0; --loopCount) {
- int lastCandidateGroupPos = 0;
- // Let's loop through char groups in this node searching for either the terminal
- // or one of its ascendants.
- for (int charGroupCount = getGroupCountAndForwardPointer(root, &pos); charGroupCount > 0;
- --charGroupCount) {
- const int startPos = pos;
- const uint8_t flags = getFlagsAndForwardPointer(root, &pos);
- const int character = getCodePointAndForwardPointer(root, &pos);
- if (nodePos == startPos) {
- // We found the address. Copy the rest of the word in the buffer and return
- // the length.
- outCodePoints[wordPos] = character;
- if (FLAG_HAS_MULTIPLE_CHARS & flags) {
- int nextChar = getCodePointAndForwardPointer(root, &pos);
- // We count chars in order to avoid infinite loops if the file is broken or
- // if there is some other bug
- int charCount = maxCodePointCount;
- while (NOT_A_CODE_POINT != nextChar && --charCount > 0) {
- outCodePoints[++wordPos] = nextChar;
- nextChar = getCodePointAndForwardPointer(root, &pos);
- }
- }
- *outUnigramProbability = readProbabilityWithoutMovingPointer(root, pos);
- return ++wordPos;
- }
- // We need to skip past this char group, so skip any remaining chars after the
- // first and possibly the probability.
- if (FLAG_HAS_MULTIPLE_CHARS & flags) {
- pos = skipOtherCharacters(root, pos);
- }
- pos = skipProbability(flags, pos);
-
- // The fact that this group has children is very important. Since we already know
- // that this group does not match, if it has no children we know it is irrelevant
- // to what we are searching for.
- const bool hasChildren = (FLAG_GROUP_ADDRESS_TYPE_NOADDRESS !=
- (MASK_GROUP_ADDRESS_TYPE & flags));
- // We will write in `found' whether we have passed the children address we are
- // searching for. For example if we search for "beer", the children of b are less
- // than the address we are searching for and the children of c are greater. When we
- // come here for c, we realize this is too big, and that we should descend b.
- bool found;
- if (hasChildren) {
- // Here comes the tricky part. First, read the children position.
- const int childrenPos = readChildrenPosition(root, flags, pos);
- if (childrenPos > nodePos) {
- // If the children pos is greater than address, it means the previous chargroup,
- // which address is stored in lastCandidateGroupPos, was the right one.
- found = true;
- } else if (1 >= charGroupCount) {
- // However if we are on the LAST group of this node, and we have NOT shot the
- // address we should descend THIS node. So we trick the lastCandidateGroupPos
- // so that we will descend this node, not the previous one.
- lastCandidateGroupPos = startPos;
- found = true;
- } else {
- // Else, we should continue looking.
- found = false;
- }
- } else {
- // Even if we don't have children here, we could still be on the last group of this
- // node. If this is the case, we should descend the last group that had children,
- // and their address is already in lastCandidateGroup.
- found = (1 >= charGroupCount);
- }
-
- if (found) {
- // Okay, we found the group we should descend. Its address is in
- // the lastCandidateGroupPos variable, so we just re-read it.
- if (0 != lastCandidateGroupPos) {
- const uint8_t lastFlags =
- getFlagsAndForwardPointer(root, &lastCandidateGroupPos);
- const int lastChar =
- getCodePointAndForwardPointer(root, &lastCandidateGroupPos);
- // We copy all the characters in this group to the buffer
- outCodePoints[wordPos] = lastChar;
- if (FLAG_HAS_MULTIPLE_CHARS & lastFlags) {
- int nextChar = getCodePointAndForwardPointer(root, &lastCandidateGroupPos);
- int charCount = maxCodePointCount;
- while (-1 != nextChar && --charCount > 0) {
- outCodePoints[++wordPos] = nextChar;
- nextChar = getCodePointAndForwardPointer(root, &lastCandidateGroupPos);
- }
- }
- ++wordPos;
- // Now we only need to branch to the children address. Skip the probability if
- // it's there, read pos, and break to resume the search at pos.
- lastCandidateGroupPos = skipProbability(lastFlags, lastCandidateGroupPos);
- pos = readChildrenPosition(root, lastFlags, lastCandidateGroupPos);
- break;
- } else {
- // Here is a little tricky part: we come here if we found out that all children
- // addresses in this group are bigger than the address we are searching for.
- // Should we conclude the word is not in the dictionary? No! It could still be
- // one of the remaining chargroups in this node, so we have to keep looking in
- // this node until we find it (or we realize it's not there either, in which
- // case it's actually not in the dictionary). Pass the end of this group, ready
- // to start the next one.
- pos = skipChildrenPosAndAttributes(root, flags, pos);
- }
- } else {
- // If we did not find it, we should record the last children address for the next
- // iteration.
- if (hasChildren) lastCandidateGroupPos = startPos;
- // Now skip the end of this group (children pos and the attributes if any) so that
- // our pos is after the end of this char group, at the start of the next one.
- pos = skipChildrenPosAndAttributes(root, flags, pos);
- }
-
- }
- }
- // If we have looked through all the chargroups and found no match, the address is
- // not the address of a terminal in this dictionary.
- return 0;
-}
-
-} // namespace latinime
-#endif // LATINIME_BINARY_FORMAT_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
index cc5252c43..ff80dd2f6 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
@@ -22,17 +22,17 @@
#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h"
#include "suggest/policyimpl/dictionary/patricia_trie_policy.h"
#include "suggest/policyimpl/dictionary/utils/format_utils.h"
-#include "suggest/policyimpl/dictionary/utils/mmaped_buffer.h"
+#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
namespace latinime {
/* static */ DictionaryStructureWithBufferPolicy *DictionaryStructureWithBufferPolicyFactory
- ::newDictionaryStructureWithBufferPolicy(const char *const path, const int pathLength,
- const int bufOffset, const int size, const bool isUpdatable) {
+ ::newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset,
+ const int size, const bool isUpdatable) {
// Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of
// impl classes of DictionaryStructureWithBufferPolicy.
- const MmapedBuffer *const mmapedBuffer = MmapedBuffer::openBuffer(path, pathLength, bufOffset,
- size, isUpdatable);
+ const MmappedBuffer *const mmapedBuffer = MmappedBuffer::openBuffer(path, bufOffset, size,
+ isUpdatable);
if (!mmapedBuffer) {
return 0;
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h
index 1cb7a89c4..8cebc3b16 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h
@@ -27,8 +27,7 @@ namespace latinime {
class DictionaryStructureWithBufferPolicyFactory {
public:
static DictionaryStructureWithBufferPolicy *newDictionaryStructureWithBufferPolicy(
- const char *const path, const int pathLength, const int bufOffset, const int size,
- const bool isUpdatable);
+ const char *const path, const int bufOffset, const int size, const bool isUpdatable);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructureWithBufferPolicyFactory);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp
new file mode 100644
index 000000000..c60e45819
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h"
+
+namespace latinime {
+
+bool DynamicPatriciaTrieGcEventListeners
+ ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted
+ ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints) {
+ // PtNode is useless when the PtNode is not a terminal and doesn't have any not useless
+ // children.
+ bool isUselessPtNode = !node->isTerminal();
+ if (mChildrenValue > 0) {
+ isUselessPtNode = false;
+ } else if (node->isTerminal()) {
+ // Remove children as all children are useless.
+ int writingPos = node->getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(
+ mBuffer, NOT_A_DICT_POS /* childrenPosition */, &writingPos)) {
+ return false;
+ }
+ }
+ if (isUselessPtNode) {
+ // Current PtNode is no longer needed. Mark it as deleted.
+ if (!mWritingHelper->markNodeAsDeleted(node)) {
+ return false;
+ }
+ } else {
+ valueStack.back() += 1;
+ }
+ return true;
+}
+
+// Writes dummy PtNode array size when the head of PtNode array is read.
+bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
+ ::onDescend(const int ptNodeArrayPos) {
+ mValidPtNodeCount = 0;
+ int writingPos = mBufferToWrite->getTailPosition();
+ mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.insert(
+ DynamicPatriciaTrieWritingHelper::PtNodeArrayPositionRelocationMap::value_type(
+ ptNodeArrayPos, writingPos));
+ // Writes dummy PtNode array size because arrays can have a forward link or needles PtNodes.
+ // This field will be updated later in onReadingPtNodeArrayTail() with actual PtNode count.
+ mPtNodeArraySizeFieldPos = writingPos;
+ return DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(
+ mBufferToWrite, 0 /* arraySize */, &writingPos);
+}
+
+// Write PtNode array terminal and actual PtNode array size.
+bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
+ ::onReadingPtNodeArrayTail() {
+ int writingPos = mBufferToWrite->getTailPosition();
+ // Write PtNode array terminal.
+ if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(
+ mBufferToWrite, NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) {
+ return false;
+ }
+ // Write actual PtNode array size.
+ if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(
+ mBufferToWrite, mValidPtNodeCount, &mPtNodeArraySizeFieldPos)) {
+ return false;
+ }
+ return true;
+}
+
+// Write valid PtNode to buffer and memorize mapping from the old position to the new position.
+bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
+ ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints) {
+ if (node->isDeleted()) {
+ // Current PtNode is not written in new buffer because it has been deleted.
+ mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert(
+ DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::value_type(
+ node->getHeadPos(), NOT_A_DICT_POS));
+ return true;
+ }
+ int writingPos = mBufferToWrite->getTailPosition();
+ mDictPositionRelocationMap->mPtNodePositionRelocationMap.insert(
+ DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::value_type(
+ node->getHeadPos(), writingPos));
+ mValidPtNodeCount++;
+ // Writes current PtNode.
+ return mWritingHelper->writePtNodeToBufferByCopyingPtNodeInfo(mBufferToWrite, node,
+ node->getParentPos(), nodeCodePoints, node->getCodePointCount(),
+ node->getProbability(), &writingPos);
+}
+
+bool DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateAllPositionFields
+ ::onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints) {
+ // Updates parent position.
+ int parentPos = node->getParentPos();
+ if (parentPos != NOT_A_DICT_POS) {
+ DynamicPatriciaTrieWritingHelper::PtNodePositionRelocationMap::const_iterator it =
+ mDictPositionRelocationMap->mPtNodePositionRelocationMap.find(parentPos);
+ if (it != mDictPositionRelocationMap->mPtNodePositionRelocationMap.end()) {
+ parentPos = it->second;
+ }
+ }
+ int writingPos = node->getHeadPos() + DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE;
+ // Write updated parent offset.
+ if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(mBufferToWrite,
+ parentPos, node->getHeadPos(), &writingPos)) {
+ return false;
+ }
+
+ // Updates children position.
+ int childrenPos = node->getChildrenPos();
+ if (childrenPos != NOT_A_DICT_POS) {
+ DynamicPatriciaTrieWritingHelper::PtNodeArrayPositionRelocationMap::const_iterator it =
+ mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.find(childrenPos);
+ if (it != mDictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.end()) {
+ childrenPos = it->second;
+ }
+ }
+ writingPos = node->getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBufferToWrite,
+ childrenPos, &writingPos)) {
+ return false;
+ }
+
+ // Updates bigram target PtNode positions in the bigram list.
+ int bigramsPos = node->getBigramsPos();
+ if (bigramsPos != NOT_A_DICT_POS) {
+ if (!mBigramPolicy->updateAllBigramTargetPtNodePositions(&bigramsPos,
+ &mDictPositionRelocationMap->mPtNodePositionRelocationMap)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h
new file mode 100644
index 000000000..4256f22fb
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H
+#define LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H
+
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+#include "utils/hash_map_compat.h"
+
+namespace latinime {
+
+class DynamicPatriciaTrieGcEventListeners {
+ public:
+ // Updates all PtNodes that can be reached from the root. Checks if each PtNode is useless or
+ // not and marks useless PtNodes as deleted. Such deleted PtNodes will be discarded in the GC.
+ // TODO: Concatenate non-terminal PtNodes.
+ class TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted
+ : public DynamicPatriciaTrieReadingHelper::TraversingEventListener {
+ public:
+ TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted(
+ DynamicPatriciaTrieWritingHelper *const writingHelper,
+ BufferWithExtendableBuffer *const buffer)
+ : mWritingHelper(writingHelper), mBuffer(buffer), valueStack(),
+ mChildrenValue(0) {}
+
+ ~TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted() {};
+
+ bool onAscend() {
+ if (valueStack.empty()) {
+ return false;
+ }
+ mChildrenValue = valueStack.back();
+ valueStack.pop_back();
+ return true;
+ }
+
+ bool onDescend(const int ptNodeArrayPos) {
+ valueStack.push_back(0);
+ return true;
+ }
+
+ bool onReadingPtNodeArrayTail() { return true; }
+
+ bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(
+ TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted);
+
+ DynamicPatriciaTrieWritingHelper *const mWritingHelper;
+ BufferWithExtendableBuffer *const mBuffer;
+ std::vector<int> valueStack;
+ int mChildrenValue;
+ };
+
+ // Updates all bigram entries that are held by valid PtNodes. This removes useless bigram
+ // entries.
+ class TraversePolicyToUpdateBigramProbability
+ : public DynamicPatriciaTrieReadingHelper::TraversingEventListener {
+ public:
+ TraversePolicyToUpdateBigramProbability(DynamicBigramListPolicy *const bigramPolicy)
+ : mBigramPolicy(bigramPolicy) {}
+
+ bool onAscend() { return true; }
+
+ bool onDescend(const int ptNodeArrayPos) { return true; }
+
+ bool onReadingPtNodeArrayTail() { return true; }
+
+ bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints) {
+ if (!node->isDeleted()) {
+ int pos = node->getBigramsPos();
+ if (pos != NOT_A_DICT_POS) {
+ if (!mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries(&pos)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateBigramProbability);
+
+ DynamicBigramListPolicy *const mBigramPolicy;
+ };
+
+ class TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
+ : public DynamicPatriciaTrieReadingHelper::TraversingEventListener {
+ public:
+ TraversePolicyToPlaceAndWriteValidPtNodesToBuffer(
+ DynamicPatriciaTrieWritingHelper *const writingHelper,
+ BufferWithExtendableBuffer *const bufferToWrite,
+ DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const
+ dictPositionRelocationMap)
+ : mWritingHelper(writingHelper), mBufferToWrite(bufferToWrite),
+ mDictPositionRelocationMap(dictPositionRelocationMap), mValidPtNodeCount(0),
+ mPtNodeArraySizeFieldPos(NOT_A_DICT_POS) {};
+
+ bool onAscend() { return true; }
+
+ bool onDescend(const int ptNodeArrayPos);
+
+ bool onReadingPtNodeArrayTail();
+
+ bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToPlaceAndWriteValidPtNodesToBuffer);
+
+ DynamicPatriciaTrieWritingHelper *const mWritingHelper;
+ BufferWithExtendableBuffer *const mBufferToWrite;
+ DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const
+ mDictPositionRelocationMap;
+ int mValidPtNodeCount;
+ int mPtNodeArraySizeFieldPos;
+ };
+
+ class TraversePolicyToUpdateAllPositionFields
+ : public DynamicPatriciaTrieReadingHelper::TraversingEventListener {
+ public:
+ TraversePolicyToUpdateAllPositionFields(
+ DynamicPatriciaTrieWritingHelper *const writingHelper,
+ DynamicBigramListPolicy *const bigramPolicy,
+ BufferWithExtendableBuffer *const bufferToWrite,
+ const DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const
+ dictPositionRelocationMap)
+ : mWritingHelper(writingHelper), mBigramPolicy(bigramPolicy),
+ mBufferToWrite(bufferToWrite),
+ mDictPositionRelocationMap(dictPositionRelocationMap) {};
+
+ bool onAscend() { return true; }
+
+ bool onDescend(const int ptNodeArrayPos) { return true; }
+
+ bool onReadingPtNodeArrayTail() { return true; }
+
+ bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateAllPositionFields);
+
+ DynamicPatriciaTrieWritingHelper *const mWritingHelper;
+ DynamicBigramListPolicy *const mBigramPolicy;
+ BufferWithExtendableBuffer *const mBufferToWrite;
+ const DynamicPatriciaTrieWritingHelper::DictPositionRelocationMap *const
+ mDictPositionRelocationMap;
+ };
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieGcEventListeners);
+};
+} // namespace latinime
+#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_GC_EVENT_LISTENERS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
index 77a85c86d..456352c17 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
@@ -19,33 +19,66 @@
#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
namespace latinime {
-void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(const int nodePos,
- const int maxCodePointCount, int *const outCodePoints) {
- int pos = nodePos;
- mFlags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
- const int parentPos =
- DynamicPatriciaTrieReadingUtils::getParentPosAndAdvancePosition(mDictRoot, &pos);
- mParentPos = (parentPos != 0) ? mNodePos + parentPos : NOT_A_DICT_POS;
+void DynamicPatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProcessMovedPtNode(
+ const int ptNodePos, const int maxCodePointCount, int *const outCodePoints) {
+ if (ptNodePos < 0 || ptNodePos >= mBuffer->getTailPosition()) {
+ AKLOGE("Fetching PtNode info form invalid dictionary position: %d, dictionary size: %d",
+ ptNodePos, mBuffer->getTailPosition());
+ ASSERT(false);
+ invalidatePtNodeInfo();
+ return;
+ }
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodePos);
+ const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
+ int pos = ptNodePos;
+ mHeadPos = ptNodePos;
+ if (usesAdditionalBuffer) {
+ pos -= mBuffer->getOriginalBufferSize();
+ }
+ mFlags = PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos);
+ const int parentPosOffset =
+ DynamicPatriciaTrieReadingUtils::getParentPtNodePosOffsetAndAdvancePosition(dictBuf,
+ &pos);
+ mParentPos = DynamicPatriciaTrieReadingUtils::getParentPtNodePos(parentPosOffset, mHeadPos);
if (outCodePoints != 0) {
mCodePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
- mDictRoot, mFlags, maxCodePointCount, outCodePoints, &pos);
+ dictBuf, mFlags, maxCodePointCount, outCodePoints, &pos);
} else {
mCodePointCount = PatriciaTrieReadingUtils::skipCharacters(
- mDictRoot, mFlags, MAX_WORD_LENGTH, &pos);
+ dictBuf, mFlags, MAX_WORD_LENGTH, &pos);
}
if (isTerminal()) {
- mProbability = PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ mProbabilityFieldPos = pos;
+ if (usesAdditionalBuffer) {
+ mProbabilityFieldPos += mBuffer->getOriginalBufferSize();
+ }
+ mProbability = PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictBuf, &pos);
} else {
+ mProbabilityFieldPos = NOT_A_DICT_POS;
mProbability = NOT_A_PROBABILITY;
}
- if (hasChildren()) {
- mChildrenPos = DynamicPatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
- mDictRoot, mFlags, &pos);
- } else {
- mChildrenPos = NOT_A_DICT_POS;
+ mChildrenPosFieldPos = pos;
+ if (usesAdditionalBuffer) {
+ mChildrenPosFieldPos += mBuffer->getOriginalBufferSize();
+ }
+ mChildrenPos = DynamicPatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
+ dictBuf, &pos);
+ if (usesAdditionalBuffer && mChildrenPos != NOT_A_DICT_POS) {
+ mChildrenPos += mBuffer->getOriginalBufferSize();
+ }
+ if (mSiblingPos == NOT_A_DICT_POS) {
+ if (DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) {
+ mBigramLinkedNodePos = mChildrenPos;
+ } else {
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ }
+ }
+ if (usesAdditionalBuffer) {
+ pos += mBuffer->getOriginalBufferSize();
}
if (PatriciaTrieReadingUtils::hasShortcutTargets(mFlags)) {
mShortcutPos = pos;
@@ -60,15 +93,31 @@ void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(c
mBigramPos = NOT_A_DICT_POS;
}
// Update siblingPos if needed.
- if (mSiblingPos == NOT_A_VALID_WORD_POS) {
+ if (mSiblingPos == NOT_A_DICT_POS) {
// Sibling position is the tail position of current node.
mSiblingPos = pos;
}
// Read destination node if the read node is a moved node.
if (DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) {
// The destination position is stored at the same place as the parent position.
- fetchNodeInfoFromBufferAndProcessMovedNode(mParentPos, maxCodePointCount, outCodePoints);
+ fetchPtNodeInfoFromBufferAndProcessMovedPtNode(mParentPos, maxCodePointCount,
+ outCodePoints);
}
}
+void DynamicPatriciaTrieNodeReader::invalidatePtNodeInfo() {
+ mHeadPos = NOT_A_DICT_POS;
+ mFlags = 0;
+ mParentPos = NOT_A_DICT_POS;
+ mCodePointCount = 0;
+ mProbabilityFieldPos = NOT_A_DICT_POS;
+ mProbability = NOT_A_PROBABILITY;
+ mChildrenPosFieldPos = NOT_A_DICT_POS;
+ mChildrenPos = NOT_A_DICT_POS;
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ mShortcutPos = NOT_A_DICT_POS;
+ mBigramPos = NOT_A_DICT_POS;
+ mSiblingPos = NOT_A_DICT_POS;
+}
+
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
index e990809e8..3b36d425f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
@@ -25,6 +25,7 @@
namespace latinime {
+class BufferWithExtendableBuffer;
class DictionaryBigramsStructurePolicy;
class DictionaryShortcutsStructurePolicy;
@@ -34,32 +35,35 @@ class DictionaryShortcutsStructurePolicy;
*/
class DynamicPatriciaTrieNodeReader {
public:
- DynamicPatriciaTrieNodeReader(const uint8_t *const dictRoot,
+ DynamicPatriciaTrieNodeReader(const BufferWithExtendableBuffer *const buffer,
const DictionaryBigramsStructurePolicy *const bigramsPolicy,
const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
- : mDictRoot(dictRoot), mBigramsPolicy(bigramsPolicy),
- mShortcutsPolicy(shortcutsPolicy), mNodePos(NOT_A_VALID_WORD_POS), mFlags(0),
- mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mProbability(NOT_A_PROBABILITY),
- mChildrenPos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS),
- mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_VALID_WORD_POS) {}
+ : mBuffer(buffer), mBigramsPolicy(bigramsPolicy),
+ mShortcutsPolicy(shortcutsPolicy), mHeadPos(NOT_A_DICT_POS), mFlags(0),
+ mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mProbabilityFieldPos(NOT_A_DICT_POS),
+ mProbability(NOT_A_PROBABILITY), mChildrenPosFieldPos(NOT_A_DICT_POS),
+ mChildrenPos(NOT_A_DICT_POS), mBigramLinkedNodePos(NOT_A_DICT_POS),
+ mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS),
+ mSiblingPos(NOT_A_DICT_POS) {}
~DynamicPatriciaTrieNodeReader() {}
- // Reads node information from dictionary buffer and updates members with the information.
- AK_FORCE_INLINE void fetchNodeInfoFromBuffer(const int nodePos) {
- fetchNodeInfoFromBufferAndGetNodeCodePoints(nodePos , 0 /* maxCodePointCount */,
- 0 /* outCodePoints */);
+ // Reads PtNode information from dictionary buffer and updates members with the information.
+ AK_FORCE_INLINE void fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) {
+ fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(ptNodePos ,
+ 0 /* maxCodePointCount */, 0 /* outCodePoints */);
}
- AK_FORCE_INLINE void fetchNodeInfoFromBufferAndGetNodeCodePoints(const int nodePos,
- const int maxCodePointCount, int *const outCodePoints) {
- mNodePos = nodePos;
- mSiblingPos = NOT_A_VALID_WORD_POS;
- fetchNodeInfoFromBufferAndProcessMovedNode(mNodePos, maxCodePointCount, outCodePoints);
+ AK_FORCE_INLINE void fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(
+ const int ptNodePos, const int maxCodePointCount, int *const outCodePoints) {
+ mSiblingPos = NOT_A_DICT_POS;
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, maxCodePointCount, outCodePoints);
}
- AK_FORCE_INLINE int getNodePos() const {
- return mNodePos;
+ // HeadPos is different from NodePos when the current PtNode is a moved PtNode.
+ AK_FORCE_INLINE int getHeadPos() const {
+ return mHeadPos;
}
// Flags
@@ -68,7 +72,7 @@ class DynamicPatriciaTrieNodeReader {
}
AK_FORCE_INLINE bool hasChildren() const {
- return PatriciaTrieReadingUtils::hasChildrenInFlags(mFlags);
+ return mChildrenPos != NOT_A_DICT_POS;
}
AK_FORCE_INLINE bool isTerminal() const {
@@ -94,15 +98,28 @@ class DynamicPatriciaTrieNodeReader {
}
// Probability
+ AK_FORCE_INLINE int getProbabilityFieldPos() const {
+ return mProbabilityFieldPos;
+ }
+
AK_FORCE_INLINE int getProbability() const {
return mProbability;
}
- // Children node group position
+ // Children PtNode array position
+ AK_FORCE_INLINE int getChildrenPosFieldPos() const {
+ return mChildrenPosFieldPos;
+ }
+
AK_FORCE_INLINE int getChildrenPos() const {
return mChildrenPos;
}
+ // Bigram linked node position.
+ AK_FORCE_INLINE int getBigramLinkedNodePos() const {
+ return mBigramLinkedNodePos;
+ }
+
// Shortcutlist position
AK_FORCE_INLINE int getShortcutPos() const {
return mShortcutPos;
@@ -121,22 +138,26 @@ class DynamicPatriciaTrieNodeReader {
private:
DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieNodeReader);
- // TODO: Consolidate mDictRoot.
- const uint8_t *const mDictRoot;
+ const BufferWithExtendableBuffer *const mBuffer;
const DictionaryBigramsStructurePolicy *const mBigramsPolicy;
const DictionaryShortcutsStructurePolicy *const mShortcutsPolicy;
- int mNodePos;
+ int mHeadPos;
DynamicPatriciaTrieReadingUtils::NodeFlags mFlags;
int mParentPos;
uint8_t mCodePointCount;
+ int mProbabilityFieldPos;
int mProbability;
+ int mChildrenPosFieldPos;
int mChildrenPos;
+ int mBigramLinkedNodePos;
int mShortcutPos;
int mBigramPos;
int mSiblingPos;
- void fetchNodeInfoFromBufferAndProcessMovedNode(const int nodePos, const int maxCodePointCount,
- int *const outCodePoints);
+ void fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos,
+ const int maxCodePointCount, int *const outCodePoints);
+
+ void invalidatePtNodeInfo();
};
} // namespace latinime
#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
index 3000860a3..42397c19e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
@@ -20,95 +20,70 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h"
#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h"
#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/probability_utils.h"
namespace latinime {
-// To avoid infinite loop caused by invalid or malicious forward links.
-const int DynamicPatriciaTriePolicy::MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP = 100000;
-
void DynamicPatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode,
DicNodeVector *const childDicNodes) const {
if (!dicNode->hasChildren()) {
return;
}
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- int mergedNodeCodePoints[MAX_WORD_LENGTH];
- int nextPos = dicNode->getChildrenPos();
- int totalChildCount = 0;
- do {
- const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
- mDictRoot, &nextPos);
- totalChildCount += childCount;
- if (childCount <= 0 || totalChildCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP) {
- // Invalid dictionary.
- AKLOGI("Invalid dictionary. childCount: %d, totalChildCount: %d, MAX: %d",
- childCount, totalChildCount, MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP);
- ASSERT(false);
- return;
- }
- for (int i = 0; i < childCount; i++) {
- nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(nextPos, MAX_WORD_LENGTH,
- mergedNodeCodePoints);
- if (!nodeReader.isDeleted()) {
- // Push child node when the node is not a deleted node.
- childDicNodes->pushLeavingChild(dicNode, nodeReader.getNodePos(),
- nodeReader.getChildrenPos(), nodeReader.getProbability(),
- nodeReader.isTerminal(), nodeReader.hasChildren(),
- nodeReader.isBlacklisted() || nodeReader.isNotAWord(),
- nodeReader.getCodePointCount(), mergedNodeCodePoints);
- }
- nextPos = nodeReader.getSiblingNodePos();
- }
- nextPos = DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(mDictRoot, nextPos);
- } while (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(nextPos));
+ DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ readingHelper.initWithPtNodeArrayPos(dicNode->getChildrenPos());
+ const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader();
+ while (!readingHelper.isEnd()) {
+ childDicNodes->pushLeavingChild(dicNode, nodeReader->getHeadPos(),
+ nodeReader->getChildrenPos(), nodeReader->getProbability(),
+ nodeReader->isTerminal() && !nodeReader->isDeleted(),
+ nodeReader->hasChildren(), nodeReader->isBlacklisted() || nodeReader->isNotAWord(),
+ nodeReader->getCodePointCount(), readingHelper.getMergedNodeCodePoints());
+ readingHelper.readNextSiblingNode();
+ }
}
int DynamicPatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
- const int nodePos, const int maxCodePointCount, int *const outCodePoints,
+ const int ptNodePos, const int maxCodePointCount, int *const outCodePoints,
int *const outUnigramProbability) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
- *outUnigramProbability = NOT_A_PROBABILITY;
- return 0;
- }
// This method traverses parent nodes from the terminal by following parent pointers; thus,
// node code points are stored in the buffer in the reverse order.
int reverseCodePoints[maxCodePointCount];
- int mergedNodeCodePoints[maxCodePointCount];
- int codePointCount = 0;
-
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- // First, read terminal node and get its probability.
- nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(nodePos, maxCodePointCount,
- mergedNodeCodePoints);
- // Store terminal node probability.
- *outUnigramProbability = nodeReader.getProbability();
- // Store terminal node code points to buffer in the reverse order.
- for (int i = nodeReader.getCodePointCount() - 1; i >= 0; --i) {
- reverseCodePoints[codePointCount++] = mergedNodeCodePoints[i];
+ DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ // First, read the terminal node and get its probability.
+ readingHelper.initWithPtNodePos(ptNodePos);
+ if (!readingHelper.isValidTerminalNode()) {
+ // Node at the ptNodePos is not a valid terminal node.
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
}
- // Then, follow parent pos toward the root node.
- while (nodeReader.getParentPos() != NOT_A_DICT_POS) {
- // codePointCount must be incremented at least once in each iteration to ensure preventing
- // infinite loop.
- if (nodeReader.isDeleted() || codePointCount > maxCodePointCount
- || nodeReader.getCodePointCount() <= 0) {
- // The nodePos is not a valid terminal node position in the dictionary.
+ // Store terminal node probability.
+ *outUnigramProbability = readingHelper.getNodeReader()->getProbability();
+ // Then, following parent node link to the dictionary root and fetch node code points.
+ while (!readingHelper.isEnd()) {
+ if (readingHelper.getTotalCodePointCount() > maxCodePointCount) {
+ // The ptNodePos is not a valid terminal node position in the dictionary.
*outUnigramProbability = NOT_A_PROBABILITY;
return 0;
}
- // Read parent node.
- nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(nodeReader.getParentPos(),
- maxCodePointCount, mergedNodeCodePoints);
// Store node code points to buffer in the reverse order.
- for (int i = nodeReader.getCodePointCount() - 1; i >= 0; --i) {
- reverseCodePoints[codePointCount++] = mergedNodeCodePoints[i];
- }
+ readingHelper.fetchMergedNodeCodePointsInReverseOrder(
+ readingHelper.getPrevTotalCodePointCount(), reverseCodePoints);
+ // Follow parent node toward the root node.
+ readingHelper.readParentNode();
+ }
+ if (readingHelper.isError()) {
+ // The node position or the dictionary is invalid.
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
}
// Reverse the stored code points to output them.
+ const int codePointCount = readingHelper.getTotalCodePointCount();
for (int i = 0; i < codePointCount; ++i) {
outCodePoints[i] = reverseCodePoints[codePointCount - i - 1];
}
@@ -121,110 +96,91 @@ int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const in
for (int i = 0; i < length; ++i) {
searchCodePoints[i] = forceLowerCaseSearch ? CharUtils::toLowerCase(inWord[i]) : inWord[i];
}
- int mergedNodeCodePoints[MAX_WORD_LENGTH];
- int currentLength = 0;
- int pos = getRootPosition();
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- while (currentLength <= length) {
- // When foundMatchedNode becomes true, currentLength is increased at least once.
- bool foundMatchedNode = false;
- int totalChildCount = 0;
- do {
- const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
- mDictRoot, &pos);
- totalChildCount += childCount;
- if (childCount <= 0 || totalChildCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP) {
- // Invalid dictionary.
- AKLOGI("Invalid dictionary. childCount: %d, totalChildCount: %d, MAX: %d",
- childCount, totalChildCount, MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP);
- ASSERT(false);
- return NOT_A_VALID_WORD_POS;
- }
- for (int i = 0; i < childCount; i++) {
- nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(pos, MAX_WORD_LENGTH,
- mergedNodeCodePoints);
- if (nodeReader.isDeleted() || nodeReader.getCodePointCount() <= 0) {
- // Skip deleted or empty node.
- pos = nodeReader.getSiblingNodePos();
- continue;
- }
- bool matched = true;
- for (int j = 0; j < nodeReader.getCodePointCount(); ++j) {
- if (mergedNodeCodePoints[j] != searchCodePoints[currentLength + j]) {
- // Different code point is found.
- matched = false;
- break;
- }
- }
- if (matched) {
- currentLength += nodeReader.getCodePointCount();
- if (length == currentLength) {
- // Terminal position is found.
- return nodeReader.getNodePos();
- }
- if (!nodeReader.hasChildren()) {
- return NOT_A_VALID_WORD_POS;
- }
- foundMatchedNode = true;
- // Advance to the children nodes.
- pos = nodeReader.getChildrenPos();
- break;
- }
- // Try next sibling node.
- pos = nodeReader.getSiblingNodePos();
- }
- if (foundMatchedNode) {
- break;
+ DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ readingHelper.initWithPtNodeArrayPos(getRootPosition());
+ const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader();
+ while (!readingHelper.isEnd()) {
+ const int matchedCodePointCount = readingHelper.getPrevTotalCodePointCount();
+ if (readingHelper.getTotalCodePointCount() > length
+ || !readingHelper.isMatchedCodePoint(0 /* index */,
+ searchCodePoints[matchedCodePointCount])) {
+ // Current node has too many code points or its first code point is different from
+ // target code point. Skip this node and read the next sibling node.
+ readingHelper.readNextSiblingNode();
+ continue;
+ }
+ // Check following merged node code points.
+ const int nodeCodePointCount = nodeReader->getCodePointCount();
+ for (int j = 1; j < nodeCodePointCount; ++j) {
+ if (!readingHelper.isMatchedCodePoint(
+ j, searchCodePoints[matchedCodePointCount + j])) {
+ // Different code point is found. The given word is not included in the dictionary.
+ return NOT_A_DICT_POS;
}
- // If the matched node is not found in the current node group, try to follow the
- // forward link.
- pos = DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(
- mDictRoot, pos);
- } while (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(pos));
- if (!foundMatchedNode) {
- // Matched node is not found.
- return NOT_A_VALID_WORD_POS;
}
+ // All characters are matched.
+ if (length == readingHelper.getTotalCodePointCount()) {
+ // Terminal position is found.
+ return nodeReader->getHeadPos();
+ }
+ if (!nodeReader->hasChildren()) {
+ return NOT_A_DICT_POS;
+ }
+ // Advance to the children nodes.
+ readingHelper.readChildNode();
}
// If we already traversed the tree further than the word is long, there means
// there was no match (or we would have found it).
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
-int DynamicPatriciaTriePolicy::getUnigramProbability(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int DynamicPatriciaTriePolicy::getProbability(const int unigramProbability,
+ const int bigramProbability) const {
+ // TODO: check mHeaderPolicy.usesForgettingCurve();
+ if (unigramProbability == NOT_A_PROBABILITY) {
return NOT_A_PROBABILITY;
+ } else if (bigramProbability == NOT_A_PROBABILITY) {
+ return ProbabilityUtils::backoff(unigramProbability);
+ } else {
+ return ProbabilityUtils::computeProbabilityForBigram(unigramProbability,
+ bigramProbability);
}
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- nodeReader.fetchNodeInfoFromBuffer(nodePos);
+}
+
+int DynamicPatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
+ return NOT_A_PROBABILITY;
+ }
+ DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos);
if (nodeReader.isDeleted() || nodeReader.isBlacklisted() || nodeReader.isNotAWord()) {
return NOT_A_PROBABILITY;
}
- return nodeReader.getProbability();
+ return getProbability(nodeReader.getProbability(), NOT_A_PROBABILITY);
}
-int DynamicPatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int DynamicPatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- nodeReader.fetchNodeInfoFromBuffer(nodePos);
+ DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos);
if (nodeReader.isDeleted()) {
return NOT_A_DICT_POS;
}
return nodeReader.getShortcutPos();
}
-int DynamicPatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int DynamicPatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
- DynamicPatriciaTrieNodeReader nodeReader(mDictRoot, getBigramsStructurePolicy(),
- getShortcutsStructurePolicy());
- nodeReader.fetchNodeInfoFromBuffer(nodePos);
+ DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos);
if (nodeReader.isDeleted()) {
return NOT_A_DICT_POS;
}
@@ -237,8 +193,12 @@ bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int
AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary.");
return false;
}
- // TODO: Implement.
- return false;
+ DynamicPatriciaTrieReadingHelper readingHelper(&mBufferWithExtendableBuffer,
+ getBigramsStructurePolicy(), getShortcutsStructurePolicy());
+ readingHelper.initWithPtNodeArrayPos(getRootPosition());
+ DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
+ &mBigramListPolicy, &mShortcutListPolicy);
+ return writingHelper.addUnigramWord(&readingHelper, word, length, probability);
}
bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int length0,
@@ -247,8 +207,19 @@ bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int
AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary.");
return false;
}
- // TODO: Implement.
- return false;
+ const int word0Pos = getTerminalNodePositionOfWord(word0, length0,
+ false /* forceLowerCaseSearch */);
+ if (word0Pos == NOT_A_DICT_POS) {
+ return false;
+ }
+ const int word1Pos = getTerminalNodePositionOfWord(word1, length1,
+ false /* forceLowerCaseSearch */);
+ if (word1Pos == NOT_A_DICT_POS) {
+ return false;
+ }
+ DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
+ &mBigramListPolicy, &mShortcutListPolicy);
+ return writingHelper.addBigramWords(word0Pos, word1Pos, probability);
}
bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0,
@@ -257,8 +228,48 @@ bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const
AKLOGI("Warning: removeBigramWords() is called for non-updatable dictionary.");
return false;
}
- // TODO: Implement.
- return false;
+ const int word0Pos = getTerminalNodePositionOfWord(word0, length0,
+ false /* forceLowerCaseSearch */);
+ if (word0Pos == NOT_A_DICT_POS) {
+ return false;
+ }
+ const int word1Pos = getTerminalNodePositionOfWord(word1, length1,
+ false /* forceLowerCaseSearch */);
+ if (word1Pos == NOT_A_DICT_POS) {
+ return false;
+ }
+ DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
+ &mBigramListPolicy, &mShortcutListPolicy);
+ return writingHelper.removeBigramWords(word0Pos, word1Pos);
+}
+
+void DynamicPatriciaTriePolicy::flush(const char *const filePath) {
+ if (!mBuffer->isUpdatable()) {
+ AKLOGI("Warning: flush() is called for non-updatable dictionary.");
+ return;
+ }
+ DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
+ &mBigramListPolicy, &mShortcutListPolicy);
+ writingHelper.writeToDictFile(filePath, &mHeaderPolicy);
+}
+
+void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) {
+ if (!mBuffer->isUpdatable()) {
+ AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary.");
+ return;
+ }
+ DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
+ &mBigramListPolicy, &mShortcutListPolicy);
+ writingHelper.writeToDictFileWithGC(getRootPosition(), filePath, &mHeaderPolicy);
+}
+
+bool DynamicPatriciaTriePolicy::needsToRunGC() const {
+ if (!mBuffer->isUpdatable()) {
+ AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary.");
+ return false;
+ }
+ // TODO: Implement more properly.
+ return mBufferWithExtendableBuffer.isNearSizeLimit();
}
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
index 708967d7b..06d8095d8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
@@ -17,14 +17,13 @@
#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
#define LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
-#include <stdint.h>
-
#include "defines.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
-#include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h"
#include "suggest/policyimpl/dictionary/header/header_policy.h"
-#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h"
-#include "suggest/policyimpl/dictionary/utils/mmaped_buffer.h"
+#include "suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
namespace latinime {
@@ -33,10 +32,12 @@ class DicNodeVector;
class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
public:
- DynamicPatriciaTriePolicy(const MmapedBuffer *const buffer)
- : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer()),
- mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()),
- mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {}
+ DynamicPatriciaTriePolicy(const MmappedBuffer *const buffer)
+ : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), buffer->getBufferSize()),
+ mBufferWithExtendableBuffer(mBuffer->getBuffer() + mHeaderPolicy.getSize(),
+ mBuffer->getBufferSize() - mHeaderPolicy.getSize()),
+ mShortcutListPolicy(&mBufferWithExtendableBuffer),
+ mBigramListPolicy(&mBufferWithExtendableBuffer, &mShortcutListPolicy) {}
~DynamicPatriciaTriePolicy() {
delete mBuffer;
@@ -50,17 +51,19 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
DicNodeVector *const childDicNodes) const;
int getCodePointsAndProbabilityAndReturnCodePointCount(
- const int terminalNodePos, const int maxCodePointCount, int *const outCodePoints,
+ const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints,
int *const outUnigramProbability) const;
int getTerminalNodePositionOfWord(const int *const inWord,
const int length, const bool forceLowerCaseSearch) const;
- int getUnigramProbability(const int nodePos) const;
+ int getProbability(const int unigramProbability, const int bigramProbability) const;
+
+ int getUnigramProbabilityOfPtNode(const int ptNodePos) const;
- int getShortcutPositionOfNode(const int nodePos) const;
+ int getShortcutPositionOfPtNode(const int ptNodePos) const;
- int getBigramsPositionOfNode(const int nodePos) const;
+ int getBigramsPositionOfPtNode(const int ptNodePos) const;
const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const {
return &mHeaderPolicy;
@@ -82,16 +85,20 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
bool removeBigramWords(const int *const word0, const int length0, const int *const word1,
const int length1);
+ void flush(const char *const filePath);
+
+ void flushWithGC(const char *const filePath);
+
+ bool needsToRunGC() const;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTriePolicy);
- static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP;
- const MmapedBuffer *const mBuffer;
+ const MmappedBuffer *const mBuffer;
const HeaderPolicy mHeaderPolicy;
- // TODO: Consolidate mDictRoot.
- const uint8_t *const mDictRoot;
- const BigramListPolicy mBigramListPolicy;
- const ShortcutListPolicy mShortcutListPolicy;
+ BufferWithExtendableBuffer mBufferWithExtendableBuffer;
+ DynamicShortcutListPolicy mShortcutListPolicy;
+ DynamicBigramListPolicy mBigramListPolicy;
};
} // namespace latinime
#endif // LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp
new file mode 100644
index 000000000..f4a2ef389
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h"
+
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+// To avoid infinite loop caused by invalid or malicious forward links.
+const int DynamicPatriciaTrieReadingHelper::MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP = 100000;
+const int DynamicPatriciaTrieReadingHelper::MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP = 100000;
+const size_t DynamicPatriciaTrieReadingHelper::MAX_READING_STATE_STACK_SIZE = MAX_WORD_LENGTH;
+
+// Visits all PtNodes in post-order depth first manner.
+// For example, visits c -> b -> y -> x -> a for the following dictionary:
+// a _ b _ c
+// \ x _ y
+bool DynamicPatriciaTrieReadingHelper::traverseAllPtNodesInPostorderDepthFirstManner(
+ TraversingEventListener *const listener) {
+ bool alreadyVisitedChildren = false;
+ // Descend from the root to the root PtNode array.
+ if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) {
+ return false;
+ }
+ while (!isEnd()) {
+ if (!alreadyVisitedChildren) {
+ if (mNodeReader.hasChildren()) {
+ // Move to the first child.
+ if (!listener->onDescend(mNodeReader.getChildrenPos())) {
+ return false;
+ }
+ pushReadingStateToStack();
+ readChildNode();
+ } else {
+ alreadyVisitedChildren = true;
+ }
+ } else {
+ if (!listener->onVisitingPtNode(&mNodeReader, mMergedNodeCodePoints)) {
+ return false;
+ }
+ readNextSiblingNode();
+ if (isEnd()) {
+ // All PtNodes in current linked PtNode arrays have been visited.
+ // Return to the parent.
+ if (!listener->onReadingPtNodeArrayTail()) {
+ return false;
+ }
+ if (mReadingStateStack.size() <= 0) {
+ break;
+ }
+ if (!listener->onAscend()) {
+ return false;
+ }
+ popReadingStateFromStack();
+ alreadyVisitedChildren = true;
+ } else {
+ // Process sibling PtNode.
+ alreadyVisitedChildren = false;
+ }
+ }
+ }
+ // Ascend from the root PtNode array to the root.
+ if (!listener->onAscend()) {
+ return false;
+ }
+ return !isError();
+}
+
+// Visits all PtNodes in PtNode array level pre-order depth first manner, which is the same order
+// that PtNodes are written in the dictionary buffer.
+// For example, visits a -> b -> x -> c -> y for the following dictionary:
+// a _ b _ c
+// \ x _ y
+bool DynamicPatriciaTrieReadingHelper::traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner(
+ TraversingEventListener *const listener) {
+ bool alreadyVisitedAllPtNodesInArray = false;
+ bool alreadyVisitedChildren = false;
+ // Descend from the root to the root PtNode array.
+ if (!listener->onDescend(getPosOfLastPtNodeArrayHead())) {
+ return false;
+ }
+ pushReadingStateToStack();
+ while (!isEnd()) {
+ if (alreadyVisitedAllPtNodesInArray) {
+ if (alreadyVisitedChildren) {
+ // Move to next sibling PtNode's children.
+ readNextSiblingNode();
+ if (isEnd()) {
+ // Return to the parent PTNode.
+ if (!listener->onAscend()) {
+ return false;
+ }
+ if (mReadingStateStack.size() <= 0) {
+ break;
+ }
+ popReadingStateFromStack();
+ alreadyVisitedChildren = true;
+ alreadyVisitedAllPtNodesInArray = true;
+ } else {
+ alreadyVisitedChildren = false;
+ }
+ } else {
+ if (mNodeReader.hasChildren()) {
+ // Move to the first child.
+ if (!listener->onDescend(mNodeReader.getChildrenPos())) {
+ return false;
+ }
+ pushReadingStateToStack();
+ readChildNode();
+ // Push state to return the head of PtNode array.
+ pushReadingStateToStack();
+ alreadyVisitedAllPtNodesInArray = false;
+ alreadyVisitedChildren = false;
+ } else {
+ alreadyVisitedChildren = true;
+ }
+ }
+ } else {
+ if (!listener->onVisitingPtNode(&mNodeReader, mMergedNodeCodePoints)) {
+ return false;
+ }
+ readNextSiblingNode();
+ if (isEnd()) {
+ if (!listener->onReadingPtNodeArrayTail()) {
+ return false;
+ }
+ // Return to the head of current PtNode array.
+ popReadingStateFromStack();
+ alreadyVisitedAllPtNodesInArray = true;
+ }
+ }
+ }
+ popReadingStateFromStack();
+ // Ascend from the root PtNode array to the root.
+ if (!listener->onAscend()) {
+ return false;
+ }
+ return !isError();
+}
+
+// Read node array size and process empty node arrays. Nodes and arrays are counted up in this
+// method to avoid an infinite loop.
+void DynamicPatriciaTrieReadingHelper::nextPtNodeArray() {
+ mReadingState.mPosOfLastPtNodeArrayHead = mReadingState.mPos;
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(mReadingState.mPos);
+ const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ mReadingState.mPos -= mBuffer->getOriginalBufferSize();
+ }
+ mReadingState.mNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
+ dictBuf, &mReadingState.mPos);
+ if (usesAdditionalBuffer) {
+ mReadingState.mPos += mBuffer->getOriginalBufferSize();
+ }
+ // Count up nodes and node arrays to avoid infinite loop.
+ mReadingState.mTotalNodeCount += mReadingState.mNodeCount;
+ mReadingState.mNodeArrayCount++;
+ if (mReadingState.mNodeCount < 0
+ || mReadingState.mTotalNodeCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP
+ || mReadingState.mNodeArrayCount > MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP) {
+ // Invalid dictionary.
+ AKLOGI("Invalid dictionary. nodeCount: %d, totalNodeCount: %d, MAX_CHILD_COUNT: %d"
+ "nodeArrayCount: %d, MAX_NODE_ARRAY_COUNT: %d",
+ mReadingState.mNodeCount, mReadingState.mTotalNodeCount,
+ MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP, mReadingState.mNodeArrayCount,
+ MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP);
+ ASSERT(false);
+ mIsError = true;
+ mReadingState.mPos = NOT_A_DICT_POS;
+ return;
+ }
+ if (mReadingState.mNodeCount == 0) {
+ // Empty node array. Try following forward link.
+ followForwardLink();
+ }
+}
+
+// Follow the forward link and read the next node array if exists.
+void DynamicPatriciaTrieReadingHelper::followForwardLink() {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(mReadingState.mPos);
+ const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ mReadingState.mPos -= mBuffer->getOriginalBufferSize();
+ }
+ const int forwardLinkPosition =
+ DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(dictBuf, mReadingState.mPos);
+ if (usesAdditionalBuffer) {
+ mReadingState.mPos += mBuffer->getOriginalBufferSize();
+ }
+ mReadingState.mPosOfLastForwardLinkField = mReadingState.mPos;
+ if (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(forwardLinkPosition)) {
+ // Follow the forward link.
+ mReadingState.mPos += forwardLinkPosition;
+ nextPtNodeArray();
+ } else {
+ // All node arrays have been read.
+ mReadingState.mPos = NOT_A_DICT_POS;
+ }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h
new file mode 100644
index 000000000..c6d8ddcf7
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H
+#define LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H
+
+#include <cstddef>
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+class DictionaryBigramsStructurePolicy;
+class DictionaryShortcutsStructurePolicy;
+
+/*
+ * This class is used for traversing dynamic patricia trie. This class supports iterating nodes and
+ * dealing with additional buffer. This class counts nodes and node arrays to avoid infinite loop.
+ */
+class DynamicPatriciaTrieReadingHelper {
+ public:
+ class TraversingEventListener {
+ public:
+ virtual ~TraversingEventListener() {};
+
+ // Returns whether the event handling was succeeded or not.
+ virtual bool onAscend() = 0;
+
+ // Returns whether the event handling was succeeded or not.
+ virtual bool onDescend(const int ptNodeArrayPos) = 0;
+
+ // Returns whether the event handling was succeeded or not.
+ virtual bool onReadingPtNodeArrayTail() = 0;
+
+ // Returns whether the event handling was succeeded or not.
+ virtual bool onVisitingPtNode(const DynamicPatriciaTrieNodeReader *const node,
+ const int *const nodeCodePoints) = 0;
+
+ protected:
+ TraversingEventListener() {};
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TraversingEventListener);
+ };
+
+ DynamicPatriciaTrieReadingHelper(const BufferWithExtendableBuffer *const buffer,
+ const DictionaryBigramsStructurePolicy *const bigramsPolicy,
+ const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
+ : mIsError(false), mReadingState(), mBuffer(buffer),
+ mNodeReader(mBuffer, bigramsPolicy, shortcutsPolicy), mReadingStateStack() {}
+
+ ~DynamicPatriciaTrieReadingHelper() {}
+
+ AK_FORCE_INLINE bool isError() const {
+ return mIsError;
+ }
+
+ AK_FORCE_INLINE bool isEnd() const {
+ return mReadingState.mPos == NOT_A_DICT_POS;
+ }
+
+ // Initialize reading state with the head position of a PtNode array.
+ AK_FORCE_INLINE void initWithPtNodeArrayPos(const int ptNodeArrayPos) {
+ if (ptNodeArrayPos == NOT_A_DICT_POS) {
+ mReadingState.mPos = NOT_A_DICT_POS;
+ } else {
+ mIsError = false;
+ mReadingState.mPos = ptNodeArrayPos;
+ mReadingState.mPrevTotalCodePointCount = 0;
+ mReadingState.mTotalNodeCount = 0;
+ mReadingState.mNodeArrayCount = 0;
+ mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
+ mReadingStateStack.clear();
+ nextPtNodeArray();
+ if (!isEnd()) {
+ fetchPtNodeInfo();
+ }
+ }
+ }
+
+ // Initialize reading state with the head position of a node.
+ AK_FORCE_INLINE void initWithPtNodePos(const int ptNodePos) {
+ if (ptNodePos == NOT_A_DICT_POS) {
+ mReadingState.mPos = NOT_A_DICT_POS;
+ } else {
+ mIsError = false;
+ mReadingState.mPos = ptNodePos;
+ mReadingState.mNodeCount = 1;
+ mReadingState.mPrevTotalCodePointCount = 0;
+ mReadingState.mTotalNodeCount = 1;
+ mReadingState.mNodeArrayCount = 1;
+ mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
+ mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS;
+ mReadingStateStack.clear();
+ fetchPtNodeInfo();
+ }
+ }
+
+ AK_FORCE_INLINE const DynamicPatriciaTrieNodeReader* getNodeReader() const {
+ return &mNodeReader;
+ }
+
+ AK_FORCE_INLINE bool isValidTerminalNode() const {
+ return !isEnd() && !mNodeReader.isDeleted() && mNodeReader.isTerminal();
+ }
+
+ AK_FORCE_INLINE bool isMatchedCodePoint(const int index, const int codePoint) const {
+ return mMergedNodeCodePoints[index] == codePoint;
+ }
+
+ // Return code point count exclude the last read node's code points.
+ AK_FORCE_INLINE int getPrevTotalCodePointCount() const {
+ return mReadingState.mPrevTotalCodePointCount;
+ }
+
+ // Return code point count include the last read node's code points.
+ AK_FORCE_INLINE int getTotalCodePointCount() const {
+ return mReadingState.mPrevTotalCodePointCount + mNodeReader.getCodePointCount();
+ }
+
+ AK_FORCE_INLINE void fetchMergedNodeCodePointsInReverseOrder(
+ const int index, int *const outCodePoints) const {
+ const int nodeCodePointCount = mNodeReader.getCodePointCount();
+ for (int i = 0; i < nodeCodePointCount; ++i) {
+ outCodePoints[index + i] = mMergedNodeCodePoints[nodeCodePointCount - 1 - i];
+ }
+ }
+
+ AK_FORCE_INLINE const int *getMergedNodeCodePoints() const {
+ return mMergedNodeCodePoints;
+ }
+
+ AK_FORCE_INLINE void readNextSiblingNode() {
+ mReadingState.mNodeCount -= 1;
+ mReadingState.mPos = mNodeReader.getSiblingNodePos();
+ if (mReadingState.mNodeCount <= 0) {
+ // All nodes in the current node array have been read.
+ followForwardLink();
+ if (!isEnd()) {
+ fetchPtNodeInfo();
+ }
+ } else {
+ fetchPtNodeInfo();
+ }
+ }
+
+ // Read the first child node of the current node.
+ AK_FORCE_INLINE void readChildNode() {
+ if (mNodeReader.hasChildren()) {
+ mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount();
+ mReadingState.mTotalNodeCount = 0;
+ mReadingState.mNodeArrayCount = 0;
+ mReadingState.mPos = mNodeReader.getChildrenPos();
+ mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
+ // Read children node array.
+ nextPtNodeArray();
+ if (!isEnd()) {
+ fetchPtNodeInfo();
+ }
+ } else {
+ mReadingState.mPos = NOT_A_DICT_POS;
+ }
+ }
+
+ // Read the parent node of the current node.
+ AK_FORCE_INLINE void readParentNode() {
+ if (mNodeReader.getParentPos() != NOT_A_DICT_POS) {
+ mReadingState.mPrevTotalCodePointCount += mNodeReader.getCodePointCount();
+ mReadingState.mTotalNodeCount = 1;
+ mReadingState.mNodeArrayCount = 1;
+ mReadingState.mNodeCount = 1;
+ mReadingState.mPos = mNodeReader.getParentPos();
+ mReadingState.mPosOfLastForwardLinkField = NOT_A_DICT_POS;
+ mReadingState.mPosOfLastPtNodeArrayHead = NOT_A_DICT_POS;
+ fetchPtNodeInfo();
+ } else {
+ mReadingState.mPos = NOT_A_DICT_POS;
+ }
+ }
+
+ AK_FORCE_INLINE int getPosOfLastForwardLinkField() const {
+ return mReadingState.mPosOfLastForwardLinkField;
+ }
+
+ AK_FORCE_INLINE int getPosOfLastPtNodeArrayHead() const {
+ return mReadingState.mPosOfLastPtNodeArrayHead;
+ }
+
+ AK_FORCE_INLINE void reloadCurrentPtNodeInfo() {
+ if (!isEnd()) {
+ fetchPtNodeInfo();
+ }
+ }
+
+ bool traverseAllPtNodesInPostorderDepthFirstManner(TraversingEventListener *const listener);
+
+ bool traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner(
+ TraversingEventListener *const listener);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieReadingHelper);
+
+ class ReadingState {
+ public:
+ // Note that copy constructor and assignment operator are used for this class to use
+ // std::vector.
+ ReadingState() : mPos(NOT_A_DICT_POS), mNodeCount(0), mPrevTotalCodePointCount(0),
+ mTotalNodeCount(0), mNodeArrayCount(0), mPosOfLastForwardLinkField(NOT_A_DICT_POS),
+ mPosOfLastPtNodeArrayHead(NOT_A_DICT_POS) {}
+
+ int mPos;
+ // Node count of a node array.
+ int mNodeCount;
+ int mPrevTotalCodePointCount;
+ int mTotalNodeCount;
+ int mNodeArrayCount;
+ int mPosOfLastForwardLinkField;
+ int mPosOfLastPtNodeArrayHead;
+ };
+
+ static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP;
+ static const int MAX_NODE_ARRAY_COUNT_TO_AVOID_INFINITE_LOOP;
+ static const size_t MAX_READING_STATE_STACK_SIZE;
+
+ bool mIsError;
+ ReadingState mReadingState;
+ const BufferWithExtendableBuffer *const mBuffer;
+ DynamicPatriciaTrieNodeReader mNodeReader;
+ int mMergedNodeCodePoints[MAX_WORD_LENGTH];
+ std::vector<ReadingState> mReadingStateStack;
+
+ void nextPtNodeArray();
+
+ void followForwardLink();
+
+ AK_FORCE_INLINE void fetchPtNodeInfo() {
+ mNodeReader.fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(mReadingState.mPos,
+ MAX_WORD_LENGTH, mMergedNodeCodePoints);
+ if (mNodeReader.getCodePointCount() <= 0) {
+ // Empty node is not allowed.
+ mIsError = true;
+ mReadingState.mPos = NOT_A_DICT_POS;
+ }
+ }
+
+ AK_FORCE_INLINE void pushReadingStateToStack() {
+ if (mReadingStateStack.size() > MAX_READING_STATE_STACK_SIZE) {
+ AKLOGI("Reading state stack overflow. Max size: %zd", MAX_READING_STATE_STACK_SIZE);
+ ASSERT(false);
+ mIsError = true;
+ mReadingState.mPos = NOT_A_DICT_POS;
+ } else {
+ mReadingStateStack.push_back(mReadingState);
+ }
+ }
+
+ AK_FORCE_INLINE void popReadingStateFromStack() {
+ if (mReadingStateStack.empty()) {
+ mReadingState.mPos = NOT_A_DICT_POS;
+ } else {
+ mReadingState = mReadingStateStack.back();
+ mReadingStateStack.pop_back();
+ fetchPtNodeInfo();
+ }
+ }
+};
+} // namespace latinime
+#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_READING_HELPER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
index 1ef3b65c3..d68446db6 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
@@ -28,13 +28,44 @@ const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_NOT_MOVED = 0xC0;
const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_MOVED = 0x40;
const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_DELETED = 0x80;
-/* static */ int DptReadingUtils::readChildrenPositionAndAdvancePosition(
- const uint8_t *const buffer, const NodeFlags flags, int *const pos) {
- if ((flags & MASK_MOVED) == FLAG_IS_NOT_MOVED) {
- const int base = *pos;
- return base + ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
+// TODO: Make DICT_OFFSET_ZERO_OFFSET = 0.
+// Currently, DICT_OFFSET_INVALID is 0 in Java side but offset can be 0 during GC. So, the maximum
+// value of offsets, which is 0x7FFFFF is used to represent 0 offset.
+const int DptReadingUtils::DICT_OFFSET_INVALID = 0;
+const int DptReadingUtils::DICT_OFFSET_ZERO_OFFSET = 0x7FFFFF;
+
+/* static */ int DptReadingUtils::getForwardLinkPosition(const uint8_t *const buffer,
+ const int pos) {
+ int linkAddressPos = pos;
+ return ByteArrayUtils::readSint24AndAdvancePosition(buffer, &linkAddressPos);
+}
+
+/* static */ int DptReadingUtils::getParentPtNodePosOffsetAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ return ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
+}
+
+/* static */ int DptReadingUtils::getParentPtNodePos(const int parentOffset, const int ptNodePos) {
+ if (parentOffset == DICT_OFFSET_INVALID) {
+ return NOT_A_DICT_POS;
+ } else if (parentOffset == DICT_OFFSET_ZERO_OFFSET) {
+ return ptNodePos;
} else {
+ return parentOffset + ptNodePos;
+ }
+}
+
+/* static */ int DptReadingUtils::readChildrenPositionAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ const int base = *pos;
+ const int offset = ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
+ if (offset == DICT_OFFSET_INVALID) {
+ // The PtNode does not have children.
return NOT_A_DICT_POS;
+ } else if (offset == DICT_OFFSET_ZERO_OFFSET) {
+ return base;
+ } else {
+ return base + offset;
}
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
index a6cb46d39..67c3cc57e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,22 +27,21 @@ class DynamicPatriciaTrieReadingUtils {
public:
typedef uint8_t NodeFlags;
- static AK_FORCE_INLINE int getForwardLinkPosition(const uint8_t *const buffer, const int pos) {
- int linkAddressPos = pos;
- return ByteArrayUtils::readSint24AndAdvancePosition(buffer, &linkAddressPos);
- }
+ static const int DICT_OFFSET_INVALID;
+ static const int DICT_OFFSET_ZERO_OFFSET;
+
+ static int getForwardLinkPosition(const uint8_t *const buffer, const int pos);
static AK_FORCE_INLINE bool isValidForwardLinkPosition(const int forwardLinkAddress) {
return forwardLinkAddress != 0;
}
- static AK_FORCE_INLINE int getParentPosAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
- }
+ static int getParentPtNodePosOffsetAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos);
- static int readChildrenPositionAndAdvancePosition(const uint8_t *const buffer,
- const NodeFlags flags, int *const pos);
+ static int getParentPtNodePos(const int parentOffset, const int ptNodePos);
+
+ static int readChildrenPositionAndAdvancePosition(const uint8_t *const buffer, int *const pos);
/**
* Node Flags
@@ -56,6 +54,15 @@ class DynamicPatriciaTrieReadingUtils {
return FLAG_IS_DELETED == (MASK_MOVED & flags);
}
+ static AK_FORCE_INLINE NodeFlags updateAndGetFlags(const NodeFlags originalFlags,
+ const bool isMoved, const bool isDeleted) {
+ NodeFlags flags = originalFlags;
+ flags = isMoved ? ((flags & (~MASK_MOVED)) | FLAG_IS_MOVED) : flags;
+ flags = isDeleted ? ((flags & (~MASK_MOVED)) | FLAG_IS_DELETED) : flags;
+ flags = (!isMoved && !isDeleted) ? ((flags & (~MASK_MOVED)) | FLAG_IS_NOT_MOVED) : flags;
+ return flags;
+ }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieReadingUtils);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
new file mode 100644
index 000000000..578645cd5
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h"
+
+#include "suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_gc_event_listeners.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h"
+#include "suggest/policyimpl/dictionary/header/header_policy.h"
+#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h"
+#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
+#include "utils/hash_map_compat.h"
+
+namespace latinime {
+
+const int DynamicPatriciaTrieWritingHelper::CHILDREN_POSITION_FIELD_SIZE = 3;
+// TODO: Make MAX_DICTIONARY_SIZE 8MB.
+const size_t DynamicPatriciaTrieWritingHelper::MAX_DICTIONARY_SIZE = 2 * 1024 * 1024;
+
+bool DynamicPatriciaTrieWritingHelper::addUnigramWord(
+ DynamicPatriciaTrieReadingHelper *const readingHelper,
+ const int *const wordCodePoints, const int codePointCount, const int probability) {
+ int parentPos = NOT_A_DICT_POS;
+ while (!readingHelper->isEnd()) {
+ const int matchedCodePointCount = readingHelper->getPrevTotalCodePointCount();
+ if (!readingHelper->isMatchedCodePoint(0 /* index */,
+ wordCodePoints[matchedCodePointCount])) {
+ // The first code point is different from target code point. Skip this node and read
+ // the next sibling node.
+ readingHelper->readNextSiblingNode();
+ continue;
+ }
+ // Check following merged node code points.
+ const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper->getNodeReader();
+ const int nodeCodePointCount = nodeReader->getCodePointCount();
+ for (int j = 1; j < nodeCodePointCount; ++j) {
+ const int nextIndex = matchedCodePointCount + j;
+ if (nextIndex >= codePointCount || !readingHelper->isMatchedCodePoint(j,
+ wordCodePoints[matchedCodePointCount + j])) {
+ return reallocatePtNodeAndAddNewPtNodes(nodeReader,
+ readingHelper->getMergedNodeCodePoints(), j, probability,
+ wordCodePoints + matchedCodePointCount,
+ codePointCount - matchedCodePointCount);
+ }
+ }
+ // All characters are matched.
+ if (codePointCount == readingHelper->getTotalCodePointCount()) {
+ return setPtNodeProbability(nodeReader, probability,
+ readingHelper->getMergedNodeCodePoints());
+ }
+ if (!nodeReader->hasChildren()) {
+ return createChildrenPtNodeArrayAndAChildPtNode(nodeReader, probability,
+ wordCodePoints + readingHelper->getTotalCodePointCount(),
+ codePointCount - readingHelper->getTotalCodePointCount());
+ }
+ // Advance to the children nodes.
+ parentPos = nodeReader->getHeadPos();
+ readingHelper->readChildNode();
+ }
+ if (readingHelper->isError()) {
+ // The dictionary is invalid.
+ return false;
+ }
+ int pos = readingHelper->getPosOfLastForwardLinkField();
+ return createAndInsertNodeIntoPtNodeArray(parentPos,
+ wordCodePoints + readingHelper->getPrevTotalCodePointCount(),
+ codePointCount - readingHelper->getPrevTotalCodePointCount(),
+ probability, &pos);
+}
+
+bool DynamicPatriciaTrieWritingHelper::addBigramWords(const int word0Pos, const int word1Pos,
+ const int probability) {
+ int mMergedNodeCodePoints[MAX_WORD_LENGTH];
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy);
+ nodeReader.fetchNodeInfoInBufferFromPtNodePosAndGetNodeCodePoints(word0Pos, MAX_WORD_LENGTH,
+ mMergedNodeCodePoints);
+ // Move node to add bigram entry.
+ const int newNodePos = mBuffer->getTailPosition();
+ if (!markNodeAsMovedAndSetPosition(&nodeReader, newNodePos, newNodePos)) {
+ return false;
+ }
+ int writingPos = newNodePos;
+ // Write a new PtNode using original PtNode's info to the tail of the dictionary in mBuffer.
+ if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, &nodeReader, nodeReader.getParentPos(),
+ mMergedNodeCodePoints, nodeReader.getCodePointCount(), nodeReader.getProbability(),
+ &writingPos)) {
+ return false;
+ }
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(newNodePos);
+ if (nodeReader.getBigramsPos() != NOT_A_DICT_POS) {
+ // Insert a new bigram entry into the existing bigram list.
+ int bigramListPos = nodeReader.getBigramsPos();
+ return mBigramPolicy->addNewBigramEntryToBigramList(word1Pos, probability, &bigramListPos);
+ } else {
+ // The PtNode doesn't have a bigram list.
+ // First, Write a bigram entry at the tail position of the PtNode.
+ if (!mBigramPolicy->writeNewBigramEntry(word1Pos, probability, &writingPos)) {
+ return false;
+ }
+ // Then, Mark as the PtNode having bigram list in the flags.
+ const PatriciaTrieReadingUtils::NodeFlags updatedFlags =
+ PatriciaTrieReadingUtils::createAndGetFlags(nodeReader.isBlacklisted(),
+ nodeReader.isNotAWord(), nodeReader.getProbability() != NOT_A_PROBABILITY,
+ nodeReader.getShortcutPos() != NOT_A_DICT_POS, true /* hasBigrams */,
+ nodeReader.getCodePointCount() > 1, CHILDREN_POSITION_FIELD_SIZE);
+ writingPos = newNodePos;
+ // Write updated flags into the moved PtNode's flags field.
+ return DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags,
+ &writingPos);
+ }
+}
+
+// Remove a bigram relation from word0Pos to word1Pos.
+bool DynamicPatriciaTrieWritingHelper::removeBigramWords(const int word0Pos, const int word1Pos) {
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy);
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(word0Pos);
+ if (nodeReader.getBigramsPos() == NOT_A_DICT_POS) {
+ return false;
+ }
+ return mBigramPolicy->removeBigram(nodeReader.getBigramsPos(), word1Pos);
+}
+
+void DynamicPatriciaTrieWritingHelper::writeToDictFile(const char *const fileName,
+ const HeaderPolicy *const headerPolicy) {
+ BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */);
+ if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, false /* updatesLastUpdatedTime */)) {
+ return;
+ }
+ DictFileWritingUtils::flushAllHeaderAndBodyToFile(fileName, &headerBuffer, mBuffer);
+}
+
+void DynamicPatriciaTrieWritingHelper::writeToDictFileWithGC(const int rootPtNodeArrayPos,
+ const char *const fileName, const HeaderPolicy *const headerPolicy) {
+ BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */);
+ if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */)) {
+ return;
+ }
+ BufferWithExtendableBuffer newDictBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */,
+ MAX_DICTIONARY_SIZE);
+ if (!runGC(rootPtNodeArrayPos, &newDictBuffer)) {
+ return;
+ }
+ DictFileWritingUtils::flushAllHeaderAndBodyToFile(fileName, &headerBuffer, &newDictBuffer);
+}
+
+bool DynamicPatriciaTrieWritingHelper::markNodeAsDeleted(
+ const DynamicPatriciaTrieNodeReader *const nodeToUpdate) {
+ int pos = nodeToUpdate->getHeadPos();
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(pos);
+ const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ pos -= mBuffer->getOriginalBufferSize();
+ }
+ // Read original flags
+ const PatriciaTrieReadingUtils::NodeFlags originalFlags =
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos);
+ const PatriciaTrieReadingUtils::NodeFlags updatedFlags =
+ DynamicPatriciaTrieReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */,
+ true /* isDeleted */);
+ int writingPos = nodeToUpdate->getHeadPos();
+ // Update flags.
+ return DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags,
+ &writingPos);
+}
+
+bool DynamicPatriciaTrieWritingHelper::markNodeAsMovedAndSetPosition(
+ const DynamicPatriciaTrieNodeReader *const originalNode, const int movedPos,
+ const int bigramLinkedNodePos) {
+ int pos = originalNode->getHeadPos();
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(pos);
+ const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ pos -= mBuffer->getOriginalBufferSize();
+ }
+ // Read original flags
+ const PatriciaTrieReadingUtils::NodeFlags originalFlags =
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos);
+ const PatriciaTrieReadingUtils::NodeFlags updatedFlags =
+ DynamicPatriciaTrieReadingUtils::updateAndGetFlags(originalFlags, true /* isMoved */,
+ false /* isDeleted */);
+ int writingPos = originalNode->getHeadPos();
+ // Update flags.
+ if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags,
+ &writingPos)) {
+ return false;
+ }
+ // Update moved position, which is stored in the parent offset field.
+ if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(
+ mBuffer, movedPos, originalNode->getHeadPos(), &writingPos)) {
+ return false;
+ }
+ // Update bigram linked node position, which is stored in the children position field.
+ int childrenPosFieldPos = originalNode->getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(
+ mBuffer, bigramLinkedNodePos, &childrenPosFieldPos)) {
+ return false;
+ }
+ if (originalNode->hasChildren()) {
+ // Update children's parent position.
+ DynamicPatriciaTrieReadingHelper readingHelper(mBuffer, mBigramPolicy, mShortcutPolicy);
+ const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader();
+ readingHelper.initWithPtNodeArrayPos(originalNode->getChildrenPos());
+ while (!readingHelper.isEnd()) {
+ int parentOffsetFieldPos = nodeReader->getHeadPos()
+ + DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE;
+ if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(
+ mBuffer, movedPos, nodeReader->getHeadPos(), &parentOffsetFieldPos)) {
+ // Parent offset cannot be written because of a bug or a broken dictionary; thus,
+ // we give up to update dictionary.
+ return false;
+ }
+ readingHelper.readNextSiblingNode();
+ }
+ }
+ return true;
+}
+
+// Write new PtNode at writingPos.
+bool DynamicPatriciaTrieWritingHelper::writePtNodeWithFullInfoToBuffer(
+ BufferWithExtendableBuffer *const bufferToWrite, const bool isBlacklisted,
+ const bool isNotAWord, const int parentPos, const int *const codePoints,
+ const int codePointCount, const int probability, const int childrenPos,
+ const int originalBigramListPos, const int originalShortcutListPos,
+ int *const writingPos) {
+ const int nodePos = *writingPos;
+ // Write dummy flags. The Node flags are updated with appropriate flags at the last step of the
+ // PtNode writing.
+ if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(bufferToWrite,
+ 0 /* nodeFlags */, writingPos)) {
+ return false;
+ }
+ // Calculate a parent offset and write the offset.
+ if (!DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(bufferToWrite,
+ parentPos, nodePos, writingPos)) {
+ return false;
+ }
+ // Write code points
+ if (!DynamicPatriciaTrieWritingUtils::writeCodePointsAndAdvancePosition(bufferToWrite,
+ codePoints, codePointCount, writingPos)) {
+ return false;
+ }
+ // Write probability when the probability is a valid probability, which means this node is
+ // terminal.
+ if (probability != NOT_A_PROBABILITY) {
+ if (!DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition(bufferToWrite,
+ probability, writingPos)) {
+ return false;
+ }
+ }
+ // Write children position
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(bufferToWrite,
+ childrenPos, writingPos)) {
+ return false;
+ }
+ // Copy shortcut list when the originalShortcutListPos is valid dictionary position.
+ if (originalShortcutListPos != NOT_A_DICT_POS) {
+ int fromPos = originalShortcutListPos;
+ if (!mShortcutPolicy->copyAllShortcutsAndReturnIfSucceededOrNot(bufferToWrite, &fromPos,
+ writingPos)) {
+ return false;
+ }
+ }
+ // Copy bigram list when the originalBigramListPos is valid dictionary position.
+ int bigramCount = 0;
+ if (originalBigramListPos != NOT_A_DICT_POS) {
+ int fromPos = originalBigramListPos;
+ if (!mBigramPolicy->copyAllBigrams(bufferToWrite, &fromPos, writingPos, &bigramCount)) {
+ return false;
+ }
+ }
+ // Create node flags and write them.
+ PatriciaTrieReadingUtils::NodeFlags nodeFlags =
+ PatriciaTrieReadingUtils::createAndGetFlags(isBlacklisted, isNotAWord,
+ probability != NOT_A_PROBABILITY /* isTerminal */,
+ originalShortcutListPos != NOT_A_DICT_POS /* hasShortcutTargets */,
+ bigramCount > 0 /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */,
+ CHILDREN_POSITION_FIELD_SIZE);
+ int flagsFieldPos = nodePos;
+ if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(bufferToWrite, nodeFlags,
+ &flagsFieldPos)) {
+ return false;
+ }
+ return true;
+}
+
+bool DynamicPatriciaTrieWritingHelper::writePtNodeToBuffer(
+ BufferWithExtendableBuffer *const bufferToWrite, const int parentPos,
+ const int *const codePoints, const int codePointCount, const int probability,
+ int *const writingPos) {
+ return writePtNodeWithFullInfoToBuffer(bufferToWrite, false /* isBlacklisted */,
+ false /* isNotAWord */, parentPos, codePoints, codePointCount, probability,
+ NOT_A_DICT_POS /* childrenPos */, NOT_A_DICT_POS /* originalBigramsPos */,
+ NOT_A_DICT_POS /* originalShortcutPos */, writingPos);
+}
+
+bool DynamicPatriciaTrieWritingHelper::writePtNodeToBufferByCopyingPtNodeInfo(
+ BufferWithExtendableBuffer *const bufferToWrite,
+ const DynamicPatriciaTrieNodeReader *const originalNode, const int parentPos,
+ const int *const codePoints, const int codePointCount, const int probability,
+ int *const writingPos) {
+ return writePtNodeWithFullInfoToBuffer(bufferToWrite, originalNode->isBlacklisted(),
+ originalNode->isNotAWord(), parentPos, codePoints, codePointCount, probability,
+ originalNode->getChildrenPos(), originalNode->getBigramsPos(),
+ originalNode->getShortcutPos(), writingPos);
+}
+
+bool DynamicPatriciaTrieWritingHelper::createAndInsertNodeIntoPtNodeArray(const int parentPos,
+ const int *const nodeCodePoints, const int nodeCodePointCount, const int probability,
+ int *const forwardLinkFieldPos) {
+ const int newPtNodeArrayPos = mBuffer->getTailPosition();
+ if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer,
+ newPtNodeArrayPos, forwardLinkFieldPos)) {
+ return false;
+ }
+ return createNewPtNodeArrayWithAChildPtNode(parentPos, nodeCodePoints, nodeCodePointCount,
+ probability);
+}
+
+bool DynamicPatriciaTrieWritingHelper::setPtNodeProbability(
+ const DynamicPatriciaTrieNodeReader *const originalPtNode, const int probability,
+ const int *const codePoints) {
+ if (originalPtNode->isTerminal()) {
+ // Overwrites the probability.
+ int probabilityFieldPos = originalPtNode->getProbabilityFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition(mBuffer,
+ probability, &probabilityFieldPos)) {
+ return false;
+ }
+ } else {
+ // Make the node terminal and write the probability.
+ int movedPos = mBuffer->getTailPosition();
+ if (!markNodeAsMovedAndSetPosition(originalPtNode, movedPos, movedPos)) {
+ return false;
+ }
+ if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, originalPtNode,
+ originalPtNode->getParentPos(), codePoints, originalPtNode->getCodePointCount(),
+ probability, &movedPos)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DynamicPatriciaTrieWritingHelper::createChildrenPtNodeArrayAndAChildPtNode(
+ const DynamicPatriciaTrieNodeReader *const parentNode, const int probability,
+ const int *const codePoints, const int codePointCount) {
+ const int newPtNodeArrayPos = mBuffer->getTailPosition();
+ int childrenPosFieldPos = parentNode->getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBuffer,
+ newPtNodeArrayPos, &childrenPosFieldPos)) {
+ return false;
+ }
+ return createNewPtNodeArrayWithAChildPtNode(parentNode->getHeadPos(), codePoints,
+ codePointCount, probability);
+}
+
+bool DynamicPatriciaTrieWritingHelper::createNewPtNodeArrayWithAChildPtNode(
+ const int parentPtNodePos, const int *const nodeCodePoints, const int nodeCodePointCount,
+ const int probability) {
+ int writingPos = mBuffer->getTailPosition();
+ if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer,
+ 1 /* arraySize */, &writingPos)) {
+ return false;
+ }
+ if (!writePtNodeToBuffer(mBuffer, parentPtNodePos, nodeCodePoints, nodeCodePointCount,
+ probability, &writingPos)) {
+ return false;
+ }
+ if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer,
+ NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) {
+ return false;
+ }
+ return true;
+}
+
+// Returns whether the dictionary updating was succeeded or not.
+bool DynamicPatriciaTrieWritingHelper::reallocatePtNodeAndAddNewPtNodes(
+ const DynamicPatriciaTrieNodeReader *const reallocatingPtNode,
+ const int *const reallocatingPtNodeCodePoints, const int overlappingCodePointCount,
+ const int probabilityOfNewPtNode, const int *const newNodeCodePoints,
+ const int newNodeCodePointCount) {
+ // When addsExtraChild is true, split the reallocating PtNode and add new child.
+ // Reallocating PtNode: abcde, newNode: abcxy.
+ // abc (1st, not terminal) __ de (2nd)
+ // \_ xy (extra child, terminal)
+ // Otherwise, this method makes 1st part terminal and write probabilityOfNewPtNode.
+ // Reallocating PtNode: abcde, newNode: abc.
+ // abc (1st, terminal) __ de (2nd)
+ const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount;
+ const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition();
+ int writingPos = firstPartOfReallocatedPtNodePos;
+ // Write the 1st part of the reallocating node. The children position will be updated later
+ // with actual children position.
+ const int newProbability = addsExtraChild ? NOT_A_PROBABILITY : probabilityOfNewPtNode;
+ if (!writePtNodeToBuffer(mBuffer, reallocatingPtNode->getParentPos(),
+ reallocatingPtNodeCodePoints, overlappingCodePointCount, newProbability,
+ &writingPos)) {
+ return false;
+ }
+ const int actualChildrenPos = writingPos;
+ // Create new children PtNode array.
+ const size_t newPtNodeCount = addsExtraChild ? 2 : 1;
+ if (!DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer,
+ newPtNodeCount, &writingPos)) {
+ return false;
+ }
+ // Write the 2nd part of the reallocating node.
+ const int secondPartOfReallocatedPtNodePos = writingPos;
+ if (!writePtNodeToBufferByCopyingPtNodeInfo(mBuffer, reallocatingPtNode,
+ firstPartOfReallocatedPtNodePos,
+ reallocatingPtNodeCodePoints + overlappingCodePointCount,
+ reallocatingPtNode->getCodePointCount() - overlappingCodePointCount,
+ reallocatingPtNode->getProbability(), &writingPos)) {
+ return false;
+ }
+ if (addsExtraChild) {
+ if (!writePtNodeToBuffer(mBuffer, firstPartOfReallocatedPtNodePos,
+ newNodeCodePoints + overlappingCodePointCount,
+ newNodeCodePointCount - overlappingCodePointCount, probabilityOfNewPtNode,
+ &writingPos)) {
+ return false;
+ }
+ }
+ if (!DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer,
+ NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) {
+ return false;
+ }
+ // Update original reallocatingPtNode as moved.
+ if (!markNodeAsMovedAndSetPosition(reallocatingPtNode, firstPartOfReallocatedPtNodePos,
+ secondPartOfReallocatedPtNodePos)) {
+ return false;
+ }
+ // Load node info. Information of the 1st part will be fetched.
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy);
+ nodeReader.fetchNodeInfoInBufferFromPtNodePos(firstPartOfReallocatedPtNodePos);
+ // Update children position.
+ int childrenPosFieldPos = nodeReader.getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBuffer,
+ actualChildrenPos, &childrenPosFieldPos)) {
+ return false;
+ }
+ return true;
+}
+
+bool DynamicPatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
+ BufferWithExtendableBuffer *const bufferToWrite) {
+ DynamicPatriciaTrieReadingHelper readingHelper(mBuffer, mBigramPolicy, mShortcutPolicy);
+ readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
+ DynamicPatriciaTrieGcEventListeners
+ ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted
+ traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted(
+ this, mBuffer);
+ if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner(
+ &traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted)) {
+ return false;
+ }
+
+ readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
+ DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateBigramProbability
+ traversePolicyToUpdateBigramProbability(mBigramPolicy);
+ if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner(
+ &traversePolicyToUpdateBigramProbability)) {
+ return false;
+ }
+
+ // Mapping from positions in mBuffer to positions in bufferToWrite.
+ DictPositionRelocationMap dictPositionRelocationMap;
+ readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
+ DynamicPatriciaTrieGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
+ traversePolicyToPlaceAndWriteValidPtNodesToBuffer(this, bufferToWrite,
+ &dictPositionRelocationMap);
+ if (!readingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner(
+ &traversePolicyToPlaceAndWriteValidPtNodesToBuffer)) {
+ return false;
+ }
+
+ // Create policy instance for the GCed dictionary.
+ DynamicShortcutListPolicy newDictShortcutPolicy(bufferToWrite);
+ DynamicBigramListPolicy newDictBigramPolicy(bufferToWrite, &newDictShortcutPolicy);
+ // Create reading helper for the GCed dictionary.
+ DynamicPatriciaTrieReadingHelper newDictReadingHelper(bufferToWrite, &newDictBigramPolicy,
+ &newDictShortcutPolicy);
+ newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
+ DynamicPatriciaTrieGcEventListeners::TraversePolicyToUpdateAllPositionFields
+ traversePolicyToUpdateAllPositionFields(this, &newDictBigramPolicy, bufferToWrite,
+ &dictPositionRelocationMap);
+ if (!newDictReadingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner(
+ &traversePolicyToUpdateAllPositionFields)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h
new file mode 100644
index 000000000..fe1b2437a
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H
+#define LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "utils/hash_map_compat.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+class DynamicBigramListPolicy;
+class DynamicPatriciaTrieNodeReader;
+class DynamicPatriciaTrieReadingHelper;
+class DynamicShortcutListPolicy;
+class HeaderPolicy;
+
+class DynamicPatriciaTrieWritingHelper {
+ public:
+ typedef hash_map_compat<int, int> PtNodeArrayPositionRelocationMap;
+ typedef hash_map_compat<int, int> PtNodePositionRelocationMap;
+ struct DictPositionRelocationMap {
+ public:
+ DictPositionRelocationMap()
+ : mPtNodeArrayPositionRelocationMap(), mPtNodePositionRelocationMap() {}
+
+ PtNodeArrayPositionRelocationMap mPtNodeArrayPositionRelocationMap;
+ PtNodePositionRelocationMap mPtNodePositionRelocationMap;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DictPositionRelocationMap);
+ };
+
+ DynamicPatriciaTrieWritingHelper(BufferWithExtendableBuffer *const buffer,
+ DynamicBigramListPolicy *const bigramPolicy,
+ DynamicShortcutListPolicy *const shortcutPolicy)
+ : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortcutPolicy(shortcutPolicy) {}
+
+ ~DynamicPatriciaTrieWritingHelper() {}
+
+ // Add a word to the dictionary. If the word already exists, update the probability.
+ bool addUnigramWord(DynamicPatriciaTrieReadingHelper *const readingHelper,
+ const int *const wordCodePoints, const int codePointCount, const int probability);
+
+ // Add a bigram relation from word0Pos to word1Pos.
+ bool addBigramWords(const int word0Pos, const int word1Pos, const int probability);
+
+ // Remove a bigram relation from word0Pos to word1Pos.
+ bool removeBigramWords(const int word0Pos, const int word1Pos);
+
+ void writeToDictFile(const char *const fileName, const HeaderPolicy *const headerPolicy);
+
+ void writeToDictFileWithGC(const int rootPtNodeArrayPos, const char *const fileName,
+ const HeaderPolicy *const headerPolicy);
+
+ // CAVEAT: This method must be called only from inner classes of
+ // DynamicPatriciaTrieGcEventListeners.
+ bool markNodeAsDeleted(const DynamicPatriciaTrieNodeReader *const nodeToUpdate);
+
+ // CAVEAT: This method must be called only from this class or inner classes of
+ // DynamicPatriciaTrieGcEventListeners.
+ bool writePtNodeToBufferByCopyingPtNodeInfo(BufferWithExtendableBuffer *const bufferToWrite,
+ const DynamicPatriciaTrieNodeReader *const originalNode, const int parentPos,
+ const int *const codePoints, const int codePointCount, const int probability,
+ int *const writingPos);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieWritingHelper);
+
+ static const int CHILDREN_POSITION_FIELD_SIZE;
+ static const size_t MAX_DICTIONARY_SIZE;
+
+ BufferWithExtendableBuffer *const mBuffer;
+ DynamicBigramListPolicy *const mBigramPolicy;
+ DynamicShortcutListPolicy *const mShortcutPolicy;
+
+ bool markNodeAsMovedAndSetPosition(const DynamicPatriciaTrieNodeReader *const nodeToUpdate,
+ const int movedPos, const int bigramLinkedNodePos);
+
+ bool writePtNodeWithFullInfoToBuffer(BufferWithExtendableBuffer *const bufferToWrite,
+ const bool isBlacklisted, const bool isNotAWord,
+ const int parentPos, const int *const codePoints, const int codePointCount,
+ const int probability, const int childrenPos, const int originalBigramListPos,
+ const int originalShortcutListPos, int *const writingPos);
+
+ bool writePtNodeToBuffer(BufferWithExtendableBuffer *const bufferToWrite,
+ const int parentPos, const int *const codePoints, const int codePointCount,
+ const int probability, int *const writingPos);
+
+ bool createAndInsertNodeIntoPtNodeArray(const int parentPos, const int *const nodeCodePoints,
+ const int nodeCodePointCount, const int probability, int *const forwardLinkFieldPos);
+
+ bool setPtNodeProbability(const DynamicPatriciaTrieNodeReader *const originalNode,
+ const int probability, const int *const codePoints);
+
+ bool createChildrenPtNodeArrayAndAChildPtNode(
+ const DynamicPatriciaTrieNodeReader *const parentNode, const int probability,
+ const int *const codePoints, const int codePointCount);
+
+ bool createNewPtNodeArrayWithAChildPtNode(const int parentPos, const int *const nodeCodePoints,
+ const int nodeCodePointCount, const int probability);
+
+ bool reallocatePtNodeAndAddNewPtNodes(
+ const DynamicPatriciaTrieNodeReader *const reallocatingPtNode,
+ const int *const reallocatingPtNodeCodePoints, const int overlappingCodePointCount,
+ const int probabilityOfNewPtNode, const int *const newNodeCodePoints,
+ const int newNodeCodePointCount);
+
+ bool runGC(const int rootPtNodeArrayPos, BufferWithExtendableBuffer *const bufferToWrite);
+};
+} // namespace latinime
+#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_HELPER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp
new file mode 100644
index 000000000..30ff10cd6
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h"
+
+#include <cstddef>
+#include <cstdlib>
+#include <stdint.h>
+
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+const size_t DynamicPatriciaTrieWritingUtils::MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD = 0x7F;
+const size_t DynamicPatriciaTrieWritingUtils::MAX_PTNODE_ARRAY_SIZE = 0x7FFF;
+const int DynamicPatriciaTrieWritingUtils::SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE = 1;
+const int DynamicPatriciaTrieWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE = 2;
+const int DynamicPatriciaTrieWritingUtils::LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG = 0x8000;
+const int DynamicPatriciaTrieWritingUtils::DICT_OFFSET_FIELD_SIZE = 3;
+const int DynamicPatriciaTrieWritingUtils::MAX_DICT_OFFSET_VALUE = 0x7FFFFF;
+const int DynamicPatriciaTrieWritingUtils::MIN_DICT_OFFSET_VALUE = -0x7FFFFF;
+const int DynamicPatriciaTrieWritingUtils::DICT_OFFSET_NEGATIVE_FLAG = 0x800000;
+const int DynamicPatriciaTrieWritingUtils::PROBABILITY_FIELD_SIZE = 1;
+const int DynamicPatriciaTrieWritingUtils::NODE_FLAG_FIELD_SIZE = 1;
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeEmptyDictionary(
+ BufferWithExtendableBuffer *const buffer, const int rootPos) {
+ int writingPos = rootPos;
+ if (!writePtNodeArraySizeAndAdvancePosition(buffer, 0 /* arraySize */, &writingPos)) {
+ return false;
+ }
+ return writeForwardLinkPositionAndAdvancePosition(buffer, NOT_A_DICT_POS /* forwardLinkPos */,
+ &writingPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeForwardLinkPositionAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int forwardLinkPos,
+ int *const forwardLinkFieldPos) {
+ return writeDictOffset(buffer, forwardLinkPos, (*forwardLinkFieldPos), forwardLinkFieldPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writePtNodeArraySizeAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const size_t arraySize,
+ int *const arraySizeFieldPos) {
+ // Currently, all array size field to be created has LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE to
+ // simplify updating process.
+ // TODO: Use SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE for small arrays.
+ /*if (arraySize <= MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD) {
+ return buffer->writeUintAndAdvancePosition(arraySize, SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE,
+ arraySizeFieldPos);
+ } else */
+ if (arraySize <= MAX_PTNODE_ARRAY_SIZE) {
+ uint32_t data = arraySize | LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG;
+ return buffer->writeUintAndAdvancePosition(data, LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE,
+ arraySizeFieldPos);
+ } else {
+ AKLOGI("PtNode array size cannot be written because arraySize is too large: %zd",
+ arraySize);
+ ASSERT(false);
+ return false;
+ }
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer,
+ const DynamicPatriciaTrieReadingUtils::NodeFlags nodeFlags, int *const nodeFlagsFieldPos) {
+ return buffer->writeUintAndAdvancePosition(nodeFlags, NODE_FLAG_FIELD_SIZE, nodeFlagsFieldPos);
+}
+
+// Note that parentOffset is offset from node's head position.
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeParentPosOffsetAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int parentPos, const int basePos,
+ int *const parentPosFieldPos) {
+ return writeDictOffset(buffer, parentPos, basePos, parentPosFieldPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeCodePointsAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int *const codePoints,
+ const int codePointCount, int *const codePointFieldPos) {
+ if (codePointCount <= 0) {
+ AKLOGI("code points cannot be written because codePointCount is invalid: %d",
+ codePointCount);
+ ASSERT(false);
+ return false;
+ }
+ const bool hasMultipleCodePoints = codePointCount > 1;
+ return buffer->writeCodePointsAndAdvancePosition(codePoints, codePointCount,
+ hasMultipleCodePoints, codePointFieldPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeProbabilityAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int probability,
+ int *const probabilityFieldPos) {
+ if (probability < 0 || probability > MAX_PROBABILITY) {
+ AKLOGI("probability cannot be written because the probability is invalid: %d",
+ probability);
+ ASSERT(false);
+ return false;
+ }
+ return buffer->writeUintAndAdvancePosition(probability, PROBABILITY_FIELD_SIZE,
+ probabilityFieldPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int childrenPosition,
+ int *const childrenPositionFieldPos) {
+ return writeDictOffset(buffer, childrenPosition, (*childrenPositionFieldPos),
+ childrenPositionFieldPos);
+}
+
+/* static */ bool DynamicPatriciaTrieWritingUtils::writeDictOffset(
+ BufferWithExtendableBuffer *const buffer, const int targetPos, const int basePos,
+ int *const offsetFieldPos) {
+ int offset = targetPos - basePos;
+ if (targetPos == NOT_A_DICT_POS) {
+ offset = DynamicPatriciaTrieReadingUtils::DICT_OFFSET_INVALID;
+ } else if (offset == 0) {
+ offset = DynamicPatriciaTrieReadingUtils::DICT_OFFSET_ZERO_OFFSET;
+ }
+ if (offset > MAX_DICT_OFFSET_VALUE || offset < MIN_DICT_OFFSET_VALUE) {
+ AKLOGI("offset cannot be written because the offset is too large or too small: %d",
+ offset);
+ ASSERT(false);
+ return false;
+ }
+ uint32_t data = 0;
+ if (offset >= 0) {
+ data = offset;
+ } else {
+ data = abs(offset) | DICT_OFFSET_NEGATIVE_FLAG;
+ }
+ return buffer->writeUintAndAdvancePosition(data, DICT_OFFSET_FIELD_SIZE, offsetFieldPos);
+}
+}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h
new file mode 100644
index 000000000..af76bc6b5
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H
+#define LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H
+
+#include <cstddef>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+
+class DynamicPatriciaTrieWritingUtils {
+ public:
+ static const int NODE_FLAG_FIELD_SIZE;
+
+ static bool writeEmptyDictionary(BufferWithExtendableBuffer *const buffer, const int rootPos);
+
+ static bool writeForwardLinkPositionAndAdvancePosition(
+ BufferWithExtendableBuffer *const buffer, const int forwardLinkPos,
+ int *const forwardLinkFieldPos);
+
+ static bool writePtNodeArraySizeAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const size_t arraySize, int *const arraySizeFieldPos);
+
+ static bool writeFlagsAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const DynamicPatriciaTrieReadingUtils::NodeFlags nodeFlags,
+ int *const nodeFlagsFieldPos);
+
+ static bool writeParentPosOffsetAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const int parentPosition, const int basePos, int *const parentPosFieldPos);
+
+ static bool writeCodePointsAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const int *const codePoints, const int codePointCount, int *const codePointFieldPos);
+
+ static bool writeProbabilityAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const int probability, int *const probabilityFieldPos);
+
+ static bool writeChildrenPositionAndAdvancePosition(BufferWithExtendableBuffer *const buffer,
+ const int childrenPosition, int *const childrenPositionFieldPos);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTrieWritingUtils);
+
+ static const size_t MAX_PTNODE_ARRAY_SIZE_TO_USE_SMALL_SIZE_FIELD;
+ static const size_t MAX_PTNODE_ARRAY_SIZE;
+ static const int SMALL_PTNODE_ARRAY_SIZE_FIELD_SIZE;
+ static const int LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE;
+ static const int LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG;
+ static const int DICT_OFFSET_FIELD_SIZE;
+ static const int MAX_DICT_OFFSET_VALUE;
+ static const int MIN_DICT_OFFSET_VALUE;
+ static const int DICT_OFFSET_NEGATIVE_FLAG;
+ static const int PROBABILITY_FIELD_SIZE;
+
+ static bool writeDictOffset(BufferWithExtendableBuffer *const buffer, const int targetPos,
+ const int basePos, int *const offsetFieldPos);
+};
+} // namespace latinime
+#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_WRITING_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
index eb828b58c..7bbeacaa0 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
@@ -16,24 +16,116 @@
#include "suggest/policyimpl/dictionary/header/header_policy.h"
+#include <cstddef>
+#include <cstdio>
+#include <ctime>
+
namespace latinime {
-const char *const HeaderPolicy::MULTIPLE_WORDS_DEMOTION_RATE_KEY =
- "MULTIPLE_WORDS_DEMOTION_RATE";
-const float HeaderPolicy::DEFAULT_MULTI_WORD_COST_MULTIPLIER = 1.0f;
-const float HeaderPolicy::MULTI_WORD_COST_MULTIPLIER_SCALE = 100.0f;
-float HeaderPolicy::readMultiWordCostMultiplier() const {
- const int headerValue = HeaderReadingUtils::readHeaderValueInt(
- mDictBuf, MULTIPLE_WORDS_DEMOTION_RATE_KEY);
- if (headerValue == S_INT_MIN) {
- // not found
- return DEFAULT_MULTI_WORD_COST_MULTIPLIER;
+// Note that these are corresponding definitions in Java side in FormatSpec.FileHeader.
+const char *const HeaderPolicy::MULTIPLE_WORDS_DEMOTION_RATE_KEY = "MULTIPLE_WORDS_DEMOTION_RATE";
+const char *const HeaderPolicy::USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE";
+const char *const HeaderPolicy::LAST_UPDATED_TIME_KEY = "date";
+const int HeaderPolicy::DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE = 100;
+const float HeaderPolicy::MULTIPLE_WORD_COST_MULTIPLIER_SCALE = 100.0f;
+
+// Used for logging. Question mark is used to indicate that the key is not found.
+void HeaderPolicy::readHeaderValueOrQuestionMark(const char *const key, int *outValue,
+ int outValueSize) const {
+ if (outValueSize <= 0) return;
+ if (outValueSize == 1) {
+ outValue[0] = '\0';
+ return;
+ }
+ std::vector<int> keyCodePointVector;
+ HeaderReadWriteUtils::insertCharactersIntoVector(key, &keyCodePointVector);
+ HeaderReadWriteUtils::AttributeMap::const_iterator it = mAttributeMap.find(keyCodePointVector);
+ if (it == mAttributeMap.end()) {
+ // The key was not found.
+ outValue[0] = '?';
+ outValue[1] = '\0';
+ return;
}
- if (headerValue <= 0) {
+ const int terminalIndex = min(static_cast<int>(it->second.size()), outValueSize - 1);
+ for (int i = 0; i < terminalIndex; ++i) {
+ outValue[i] = it->second[i];
+ }
+ outValue[terminalIndex] = '\0';
+}
+
+float HeaderPolicy::readMultipleWordCostMultiplier() const {
+ std::vector<int> keyVector;
+ HeaderReadWriteUtils::insertCharactersIntoVector(MULTIPLE_WORDS_DEMOTION_RATE_KEY, &keyVector);
+ const int demotionRate = HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap,
+ &keyVector, DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE);
+ if (demotionRate <= 0) {
return static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
}
- return MULTI_WORD_COST_MULTIPLIER_SCALE / static_cast<float>(headerValue);
+ return MULTIPLE_WORD_COST_MULTIPLIER_SCALE / static_cast<float>(demotionRate);
+}
+
+bool HeaderPolicy::readUsesForgettingCurveFlag() const {
+ std::vector<int> keyVector;
+ HeaderReadWriteUtils::insertCharactersIntoVector(USES_FORGETTING_CURVE_KEY, &keyVector);
+ return HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, &keyVector,
+ false /* defaultValue */);
+}
+
+// Returns current time when the key is not found or the value is invalid.
+int HeaderPolicy::readLastUpdatedTime() const {
+ std::vector<int> keyVector;
+ HeaderReadWriteUtils::insertCharactersIntoVector(LAST_UPDATED_TIME_KEY, &keyVector);
+ return HeaderReadWriteUtils::readIntAttributeValue(&mAttributeMap, &keyVector,
+ time(0) /* defaultValue */);
+}
+
+bool HeaderPolicy::writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite,
+ const bool updatesLastUpdatedTime) const {
+ int writingPos = 0;
+ if (!HeaderReadWriteUtils::writeDictionaryVersion(bufferToWrite, mDictFormatVersion,
+ &writingPos)) {
+ return false;
+ }
+ if (!HeaderReadWriteUtils::writeDictionaryFlags(bufferToWrite, mDictionaryFlags,
+ &writingPos)) {
+ return false;
+ }
+ // Temporarily writes a dummy header size.
+ int headerSizeFieldPos = writingPos;
+ if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, 0 /* size */,
+ &writingPos)) {
+ return false;
+ }
+ if (updatesLastUpdatedTime) {
+ // Set current time as a last updated time.
+ HeaderReadWriteUtils::AttributeMap attributeMapTowrite(mAttributeMap);
+ std::vector<int> updatedTimekey;
+ HeaderReadWriteUtils::insertCharactersIntoVector(LAST_UPDATED_TIME_KEY, &updatedTimekey);
+ HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, &updatedTimekey, time(0));
+ if (!HeaderReadWriteUtils::writeHeaderAttributes(bufferToWrite, &attributeMapTowrite,
+ &writingPos)) {
+ return false;
+ }
+ } else {
+ if (!HeaderReadWriteUtils::writeHeaderAttributes(bufferToWrite, &mAttributeMap,
+ &writingPos)) {
+ return false;
+ }
+ }
+ // Writes an actual header size.
+ if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, writingPos,
+ &headerSizeFieldPos)) {
+ return false;
+ }
+ return true;
+}
+
+/* static */ HeaderReadWriteUtils::AttributeMap
+ HeaderPolicy::createAttributeMapAndReadAllAttributes(const uint8_t *const dictBuf) {
+ HeaderReadWriteUtils::AttributeMap attributeMap;
+ HeaderReadWriteUtils::fetchAllHeaderAttributes(dictBuf, &attributeMap);
+ return attributeMap;
}
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index e3e6fc077..e97c08ca4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -21,16 +21,32 @@
#include "defines.h"
#include "suggest/core/policy/dictionary_header_structure_policy.h"
-#include "suggest/policyimpl/dictionary/header/header_reading_utils.h"
+#include "suggest/policyimpl/dictionary/header/header_read_write_utils.h"
+#include "suggest/policyimpl/dictionary/utils/format_utils.h"
namespace latinime {
class HeaderPolicy : public DictionaryHeaderStructurePolicy {
public:
- explicit HeaderPolicy(const uint8_t *const dictBuf)
- : mDictBuf(dictBuf), mDictionaryFlags(HeaderReadingUtils::getFlags(dictBuf)),
- mSize(HeaderReadingUtils::getHeaderSize(dictBuf)),
- mMultiWordCostMultiplier(readMultiWordCostMultiplier()) {}
+ // Reads information from existing dictionary buffer.
+ HeaderPolicy(const uint8_t *const dictBuf, const int dictSize)
+ : mDictFormatVersion(FormatUtils::detectFormatVersion(dictBuf, dictSize)),
+ mDictionaryFlags(HeaderReadWriteUtils::getFlags(dictBuf)),
+ mSize(HeaderReadWriteUtils::getHeaderSize(dictBuf)),
+ mAttributeMap(createAttributeMapAndReadAllAttributes(dictBuf)),
+ mMultiWordCostMultiplier(readMultipleWordCostMultiplier()),
+ mUsesForgettingCurve(readUsesForgettingCurveFlag()),
+ mLastUpdatedTime(readLastUpdatedTime()) {}
+
+ // Constructs header information using an attribute map.
+ HeaderPolicy(const FormatUtils::FORMAT_VERSION dictFormatVersion,
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap)
+ : mDictFormatVersion(dictFormatVersion),
+ mDictionaryFlags(HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap(
+ attributeMap)), mSize(0), mAttributeMap(*attributeMap),
+ mMultiWordCostMultiplier(readUsesForgettingCurveFlag()),
+ mUsesForgettingCurve(readUsesForgettingCurveFlag()),
+ mLastUpdatedTime(readLastUpdatedTime()) {}
~HeaderPolicy() {}
@@ -39,50 +55,60 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy {
}
AK_FORCE_INLINE bool supportsDynamicUpdate() const {
- return HeaderReadingUtils::supportsDynamicUpdate(mDictionaryFlags);
+ return HeaderReadWriteUtils::supportsDynamicUpdate(mDictionaryFlags);
}
AK_FORCE_INLINE bool requiresGermanUmlautProcessing() const {
- return HeaderReadingUtils::requiresGermanUmlautProcessing(mDictionaryFlags);
+ return HeaderReadWriteUtils::requiresGermanUmlautProcessing(mDictionaryFlags);
}
AK_FORCE_INLINE bool requiresFrenchLigatureProcessing() const {
- return HeaderReadingUtils::requiresFrenchLigatureProcessing(
- mDictionaryFlags);
+ return HeaderReadWriteUtils::requiresFrenchLigatureProcessing(mDictionaryFlags);
}
AK_FORCE_INLINE float getMultiWordCostMultiplier() const {
return mMultiWordCostMultiplier;
}
- AK_FORCE_INLINE void readHeaderValueOrQuestionMark(const char *const key,
- int *outValue, int outValueSize) const {
- if (outValueSize <= 0) return;
- if (outValueSize == 1) {
- outValue[0] = '\0';
- return;
- }
- if (!HeaderReadingUtils::readHeaderValue(mDictBuf,
- key, outValue, outValueSize)) {
- outValue[0] = '?';
- outValue[1] = '\0';
- }
+ AK_FORCE_INLINE bool usesForgettingCurve() const {
+ return mUsesForgettingCurve;
}
+ AK_FORCE_INLINE int getLastUpdatedTime() const {
+ return mLastUpdatedTime;
+ }
+
+ void readHeaderValueOrQuestionMark(const char *const key,
+ int *outValue, int outValueSize) const;
+
+ bool writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite,
+ const bool updatesLastUpdatedTime) const;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPolicy);
static const char *const MULTIPLE_WORDS_DEMOTION_RATE_KEY;
- static const float DEFAULT_MULTI_WORD_COST_MULTIPLIER;
- static const float MULTI_WORD_COST_MULTIPLIER_SCALE;
+ static const char *const USES_FORGETTING_CURVE_KEY;
+ static const char *const LAST_UPDATED_TIME_KEY;
+ static const int DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE;
+ static const float MULTIPLE_WORD_COST_MULTIPLIER_SCALE;
- const uint8_t *const mDictBuf;
- const HeaderReadingUtils::DictionaryFlags mDictionaryFlags;
+ const FormatUtils::FORMAT_VERSION mDictFormatVersion;
+ const HeaderReadWriteUtils::DictionaryFlags mDictionaryFlags;
const int mSize;
+ HeaderReadWriteUtils::AttributeMap mAttributeMap;
const float mMultiWordCostMultiplier;
+ const bool mUsesForgettingCurve;
+ const int mLastUpdatedTime;
- float readMultiWordCostMultiplier() const;
-};
+ float readMultipleWordCostMultiplier() const;
+
+ bool readUsesForgettingCurveFlag() const;
+ int readLastUpdatedTime() const;
+
+ static HeaderReadWriteUtils::AttributeMap createAttributeMapAndReadAllAttributes(
+ const uint8_t *const dictBuf);
+};
} // namespace latinime
#endif /* LATINIME_HEADER_POLICY_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
new file mode 100644
index 000000000..3b1c78085
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/header/header_read_write_utils.h"
+
+#include <cctype>
+#include <cstdio>
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+
+namespace latinime {
+
+const int HeaderReadWriteUtils::MAX_ATTRIBUTE_KEY_LENGTH = 256;
+const int HeaderReadWriteUtils::MAX_ATTRIBUTE_VALUE_LENGTH = 256;
+
+const int HeaderReadWriteUtils::HEADER_MAGIC_NUMBER_SIZE = 4;
+const int HeaderReadWriteUtils::HEADER_DICTIONARY_VERSION_SIZE = 2;
+const int HeaderReadWriteUtils::HEADER_FLAG_SIZE = 2;
+const int HeaderReadWriteUtils::HEADER_SIZE_FIELD_SIZE = 4;
+
+const HeaderReadWriteUtils::DictionaryFlags HeaderReadWriteUtils::NO_FLAGS = 0;
+// Flags for special processing
+// Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAG) or
+// something very bad (like, the apocalypse) will happen. Please update both at the same time.
+const HeaderReadWriteUtils::DictionaryFlags
+ HeaderReadWriteUtils::GERMAN_UMLAUT_PROCESSING_FLAG = 0x1;
+const HeaderReadWriteUtils::DictionaryFlags
+ HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_FLAG = 0x2;
+const HeaderReadWriteUtils::DictionaryFlags
+ HeaderReadWriteUtils::FRENCH_LIGATURE_PROCESSING_FLAG = 0x4;
+
+// Note that these are corresponding definitions in Java side in FormatSpec.FileHeader.
+const char *const HeaderReadWriteUtils::SUPPORTS_DYNAMIC_UPDATE_KEY = "SUPPORTS_DYNAMIC_UPDATE";
+const char *const HeaderReadWriteUtils::REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY =
+ "REQUIRES_GERMAN_UMLAUT_PROCESSING";
+const char *const HeaderReadWriteUtils::REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY =
+ "REQUIRES_FRENCH_LIGATURE_PROCESSING";
+
+/* static */ int HeaderReadWriteUtils::getHeaderSize(const uint8_t *const dictBuf) {
+ // See the format of the header in the comment in
+ // BinaryDictionaryFormatUtils::detectFormatVersion()
+ return ByteArrayUtils::readUint32(dictBuf, HEADER_MAGIC_NUMBER_SIZE
+ + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE);
+}
+
+/* static */ HeaderReadWriteUtils::DictionaryFlags
+ HeaderReadWriteUtils::getFlags(const uint8_t *const dictBuf) {
+ return ByteArrayUtils::readUint16(dictBuf,
+ HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE);
+}
+
+/* static */ HeaderReadWriteUtils::DictionaryFlags
+ HeaderReadWriteUtils::createAndGetDictionaryFlagsUsingAttributeMap(
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap) {
+ AttributeMap::key_type key;
+ insertCharactersIntoVector(REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY, &key);
+ const bool requiresGermanUmlautProcessing = readBoolAttributeValue(attributeMap, &key,
+ false /* defaultValue */);
+ key.clear();
+ insertCharactersIntoVector(REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY, &key);
+ const bool requiresFrenchLigatureProcessing = readBoolAttributeValue(attributeMap, &key,
+ false /* defaultValue */);
+ key.clear();
+ insertCharactersIntoVector(SUPPORTS_DYNAMIC_UPDATE_KEY, &key);
+ const bool supportsDynamicUpdate = readBoolAttributeValue(attributeMap, &key,
+ false /* defaultValue */);
+ DictionaryFlags dictflags = NO_FLAGS;
+ dictflags |= requiresGermanUmlautProcessing ? GERMAN_UMLAUT_PROCESSING_FLAG : 0;
+ dictflags |= requiresFrenchLigatureProcessing ? FRENCH_LIGATURE_PROCESSING_FLAG : 0;
+ dictflags |= supportsDynamicUpdate ? SUPPORTS_DYNAMIC_UPDATE_FLAG : 0;
+ return dictflags;
+}
+
+/* static */ void HeaderReadWriteUtils::fetchAllHeaderAttributes(const uint8_t *const dictBuf,
+ AttributeMap *const headerAttributes) {
+ const int headerSize = getHeaderSize(dictBuf);
+ int pos = getHeaderOptionsPosition();
+ if (pos == NOT_A_DICT_POS) {
+ // The header doesn't have header options.
+ return;
+ }
+ int keyBuffer[MAX_ATTRIBUTE_KEY_LENGTH];
+ int valueBuffer[MAX_ATTRIBUTE_VALUE_LENGTH];
+ while (pos < headerSize) {
+ const int keyLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
+ MAX_ATTRIBUTE_KEY_LENGTH, keyBuffer, &pos);
+ std::vector<int> key;
+ key.insert(key.end(), keyBuffer, keyBuffer + keyLength);
+ const int valueLength = ByteArrayUtils::readStringAndAdvancePosition(dictBuf,
+ MAX_ATTRIBUTE_VALUE_LENGTH, valueBuffer, &pos);
+ std::vector<int> value;
+ value.insert(value.end(), valueBuffer, valueBuffer + valueLength);
+ headerAttributes->insert(AttributeMap::value_type(key, value));
+ }
+}
+
+/* static */ bool HeaderReadWriteUtils::writeDictionaryVersion(
+ BufferWithExtendableBuffer *const buffer, const FormatUtils::FORMAT_VERSION version,
+ int *const writingPos) {
+ if (!buffer->writeUintAndAdvancePosition(FormatUtils::MAGIC_NUMBER, HEADER_MAGIC_NUMBER_SIZE,
+ writingPos)) {
+ return false;
+ }
+ switch (version) {
+ case FormatUtils::VERSION_2:
+ // Version 2 dictionary writing is not supported.
+ return false;
+ case FormatUtils::VERSION_3:
+ return buffer->writeUintAndAdvancePosition(3 /* data */,
+ HEADER_DICTIONARY_VERSION_SIZE, writingPos);
+ default:
+ return false;
+ }
+}
+
+/* static */ bool HeaderReadWriteUtils::writeDictionaryFlags(
+ BufferWithExtendableBuffer *const buffer, const DictionaryFlags flags,
+ int *const writingPos) {
+ return buffer->writeUintAndAdvancePosition(flags, HEADER_FLAG_SIZE, writingPos);
+}
+
+/* static */ bool HeaderReadWriteUtils::writeDictionaryHeaderSize(
+ BufferWithExtendableBuffer *const buffer, const int size, int *const writingPos) {
+ return buffer->writeUintAndAdvancePosition(size, HEADER_SIZE_FIELD_SIZE, writingPos);
+}
+
+/* static */ bool HeaderReadWriteUtils::writeHeaderAttributes(
+ BufferWithExtendableBuffer *const buffer, const AttributeMap *const headerAttributes,
+ int *const writingPos) {
+ for (AttributeMap::const_iterator it = headerAttributes->begin();
+ it != headerAttributes->end(); ++it) {
+ // Write a key.
+ if (!buffer->writeCodePointsAndAdvancePosition(&(it->first.at(0)), it->first.size(),
+ true /* writesTerminator */, writingPos)) {
+ return false;
+ }
+ // Write a value.
+ if (!buffer->writeCodePointsAndAdvancePosition(&(it->second.at(0)), it->second.size(),
+ true /* writesTerminator */, writingPos)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* static */ void HeaderReadWriteUtils::setBoolAttribute(AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const bool value) {
+ setIntAttribute(headerAttributes, key, value ? 1 : 0);
+}
+
+/* static */ void HeaderReadWriteUtils::setIntAttribute(AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const int value) {
+ AttributeMap::mapped_type valueVector;
+ char charBuf[LARGEST_INT_DIGIT_COUNT + 1];
+ snprintf(charBuf, LARGEST_INT_DIGIT_COUNT + 1, "%d", value);
+ insertCharactersIntoVector(charBuf, &valueVector);
+ (*headerAttributes)[*key] = valueVector;
+}
+
+/* static */ bool HeaderReadWriteUtils::readBoolAttributeValue(
+ const AttributeMap *const headerAttributes, const AttributeMap::key_type *const key,
+ const bool defaultValue) {
+ const int intDefaultValue = defaultValue ? 1 : 0;
+ const int intValue = readIntAttributeValue(headerAttributes, key, intDefaultValue);
+ return intValue != 0;
+}
+
+/* static */ int HeaderReadWriteUtils::readIntAttributeValue(
+ const AttributeMap *const headerAttributes, const AttributeMap::key_type *const key,
+ const int defaultValue) {
+ AttributeMap::const_iterator it = headerAttributes->find(*key);
+ if (it != headerAttributes->end()) {
+ int value = 0;
+ bool isNegative = false;
+ for (size_t i = 0; i < it->second.size(); ++i) {
+ if (i == 0 && it->second.at(i) == '-') {
+ isNegative = true;
+ } else {
+ if (!isdigit(it->second.at(i))) {
+ // If not a number.
+ return defaultValue;
+ }
+ value *= 10;
+ value += it->second.at(i) - '0';
+ }
+ }
+ return isNegative ? -value : value;
+ }
+ return defaultValue;
+}
+
+/* static */ void HeaderReadWriteUtils::insertCharactersIntoVector(const char *const characters,
+ std::vector<int> *const vector) {
+ for (int i = 0; characters[i]; ++i) {
+ vector->push_back(characters[i]);
+ }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h
new file mode 100644
index 000000000..caa5097f6
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_HEADER_READ_WRITE_UTILS_H
+#define LATINIME_HEADER_READ_WRITE_UTILS_H
+
+#include <map>
+#include <stdint.h>
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/utils/format_utils.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+
+class HeaderReadWriteUtils {
+ public:
+ typedef uint16_t DictionaryFlags;
+ typedef std::map<std::vector<int>, std::vector<int> > AttributeMap;
+
+ static int getHeaderSize(const uint8_t *const dictBuf);
+
+ static DictionaryFlags getFlags(const uint8_t *const dictBuf);
+
+ static AK_FORCE_INLINE bool supportsDynamicUpdate(const DictionaryFlags flags) {
+ return (flags & SUPPORTS_DYNAMIC_UPDATE_FLAG) != 0;
+ }
+
+ static AK_FORCE_INLINE bool requiresGermanUmlautProcessing(const DictionaryFlags flags) {
+ return (flags & GERMAN_UMLAUT_PROCESSING_FLAG) != 0;
+ }
+
+ static AK_FORCE_INLINE bool requiresFrenchLigatureProcessing(const DictionaryFlags flags) {
+ return (flags & FRENCH_LIGATURE_PROCESSING_FLAG) != 0;
+ }
+
+ static AK_FORCE_INLINE int getHeaderOptionsPosition() {
+ return HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE
+ + HEADER_SIZE_FIELD_SIZE;
+ }
+
+ static DictionaryFlags createAndGetDictionaryFlagsUsingAttributeMap(
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap);
+
+ static void fetchAllHeaderAttributes(const uint8_t *const dictBuf,
+ AttributeMap *const headerAttributes);
+
+ static bool writeDictionaryVersion(BufferWithExtendableBuffer *const buffer,
+ const FormatUtils::FORMAT_VERSION version, int *const writingPos);
+
+ static bool writeDictionaryFlags(BufferWithExtendableBuffer *const buffer,
+ const DictionaryFlags flags, int *const writingPos);
+
+ static bool writeDictionaryHeaderSize(BufferWithExtendableBuffer *const buffer,
+ const int size, int *const writingPos);
+
+ static bool writeHeaderAttributes(BufferWithExtendableBuffer *const buffer,
+ const AttributeMap *const headerAttributes, int *const writingPos);
+
+ /**
+ * Methods for header attributes.
+ */
+ static void setBoolAttribute(AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const bool value);
+
+ static void setIntAttribute(AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const int value);
+
+ static bool readBoolAttributeValue(const AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const bool defaultValue);
+
+ static int readIntAttributeValue(const AttributeMap *const headerAttributes,
+ const AttributeMap::key_type *const key, const int defaultValue);
+
+ static void insertCharactersIntoVector(const char *const characters,
+ AttributeMap::key_type *const key);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderReadWriteUtils);
+
+ static const int MAX_ATTRIBUTE_KEY_LENGTH;
+ static const int MAX_ATTRIBUTE_VALUE_LENGTH;
+
+ static const int HEADER_MAGIC_NUMBER_SIZE;
+ static const int HEADER_DICTIONARY_VERSION_SIZE;
+ static const int HEADER_FLAG_SIZE;
+ static const int HEADER_SIZE_FIELD_SIZE;
+
+ static const DictionaryFlags NO_FLAGS;
+ // Flags for special processing
+ // Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAGS) or
+ // something very bad (like, the apocalypse) will happen. Please update both at the same time.
+ static const DictionaryFlags GERMAN_UMLAUT_PROCESSING_FLAG;
+ static const DictionaryFlags SUPPORTS_DYNAMIC_UPDATE_FLAG;
+ static const DictionaryFlags FRENCH_LIGATURE_PROCESSING_FLAG;
+
+ static const char *const SUPPORTS_DYNAMIC_UPDATE_KEY;
+ static const char *const REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY;
+ static const char *const REQUIRES_FRENCH_LIGATURE_PROCESSING_KEY;
+};
+}
+#endif /* LATINIME_HEADER_READ_WRITE_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.cpp
deleted file mode 100644
index f323876c4..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "suggest/policyimpl/dictionary/header/header_reading_utils.h"
-
-#include <cctype>
-#include <cstdlib>
-
-#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
-
-namespace latinime {
-
-const int HeaderReadingUtils::MAX_OPTION_KEY_LENGTH = 256;
-
-const int HeaderReadingUtils::HEADER_MAGIC_NUMBER_SIZE = 4;
-const int HeaderReadingUtils::HEADER_DICTIONARY_VERSION_SIZE = 2;
-const int HeaderReadingUtils::HEADER_FLAG_SIZE = 2;
-const int HeaderReadingUtils::HEADER_SIZE_FIELD_SIZE = 4;
-
-const HeaderReadingUtils::DictionaryFlags
- HeaderReadingUtils::NO_FLAGS = 0;
-// Flags for special processing
-// Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAG) or
-// something very bad (like, the apocalypse) will happen. Please update both at the same time.
-const HeaderReadingUtils::DictionaryFlags
- HeaderReadingUtils::GERMAN_UMLAUT_PROCESSING_FLAG = 0x1;
-const HeaderReadingUtils::DictionaryFlags
- HeaderReadingUtils::SUPPORTS_DYNAMIC_UPDATE_FLAG = 0x2;
-const HeaderReadingUtils::DictionaryFlags
- HeaderReadingUtils::FRENCH_LIGATURE_PROCESSING_FLAG = 0x4;
-
-/* static */ int HeaderReadingUtils::getHeaderSize(const uint8_t *const dictBuf) {
- // See the format of the header in the comment in
- // BinaryDictionaryFormatUtils::detectFormatVersion()
- return ByteArrayUtils::readUint32(dictBuf, HEADER_MAGIC_NUMBER_SIZE
- + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE);
-}
-
-/* static */ HeaderReadingUtils::DictionaryFlags
- HeaderReadingUtils::getFlags(const uint8_t *const dictBuf) {
- return ByteArrayUtils::readUint16(dictBuf,
- HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE);
-}
-
-// Returns if the key is found or not and reads the found value into outValue.
-/* static */ bool HeaderReadingUtils::readHeaderValue(const uint8_t *const dictBuf,
- const char *const key, int *outValue, const int outValueSize) {
- if (outValueSize <= 0) {
- return false;
- }
- const int headerSize = getHeaderSize(dictBuf);
- int pos = getHeaderOptionsPosition();
- if (pos == NOT_A_DICT_POS) {
- // The header doesn't have header options.
- return false;
- }
- while (pos < headerSize) {
- if(ByteArrayUtils::compareStringInBufferWithCharArray(
- dictBuf, key, headerSize - pos, &pos) == 0) {
- // The key was found.
- const int length = ByteArrayUtils::readStringAndAdvancePosition(dictBuf, outValueSize,
- outValue, &pos);
- // Add a 0 terminator to the string.
- outValue[length < outValueSize ? length : outValueSize - 1] = '\0';
- return true;
- }
- ByteArrayUtils::advancePositionToBehindString(dictBuf, headerSize - pos, &pos);
- }
- // The key was not found.
- return false;
-}
-
-/* static */ int HeaderReadingUtils::readHeaderValueInt(
- const uint8_t *const dictBuf, const char *const key) {
- const int bufferSize = LARGEST_INT_DIGIT_COUNT;
- int intBuffer[bufferSize];
- char charBuffer[bufferSize];
- if (!readHeaderValue(dictBuf, key, intBuffer, bufferSize)) {
- return S_INT_MIN;
- }
- for (int i = 0; i < bufferSize; ++i) {
- charBuffer[i] = intBuffer[i];
- if (charBuffer[i] == '0') {
- break;
- }
- if (!isdigit(charBuffer[i])) {
- // If not a number, return S_INT_MIN
- return S_INT_MIN;
- }
- }
- return atoi(charBuffer);
-}
-
-} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.h
deleted file mode 100644
index c94919640..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_reading_utils.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LATINIME_HEADER_READING_UTILS_H
-#define LATINIME_HEADER_READING_UTILS_H
-
-#include <stdint.h>
-
-#include "defines.h"
-
-namespace latinime {
-
-class HeaderReadingUtils {
- public:
- typedef uint16_t DictionaryFlags;
-
- static const int MAX_OPTION_KEY_LENGTH;
-
- static int getHeaderSize(const uint8_t *const dictBuf);
-
- static DictionaryFlags getFlags(const uint8_t *const dictBuf);
-
- static AK_FORCE_INLINE bool supportsDynamicUpdate(const DictionaryFlags flags) {
- return (flags & SUPPORTS_DYNAMIC_UPDATE_FLAG) != 0;
- }
-
- static AK_FORCE_INLINE bool requiresGermanUmlautProcessing(const DictionaryFlags flags) {
- return (flags & GERMAN_UMLAUT_PROCESSING_FLAG) != 0;
- }
-
- static AK_FORCE_INLINE bool requiresFrenchLigatureProcessing(const DictionaryFlags flags) {
- return (flags & FRENCH_LIGATURE_PROCESSING_FLAG) != 0;
- }
-
- static AK_FORCE_INLINE int getHeaderOptionsPosition() {
- return HEADER_MAGIC_NUMBER_SIZE + HEADER_DICTIONARY_VERSION_SIZE + HEADER_FLAG_SIZE
- + HEADER_SIZE_FIELD_SIZE;
- }
-
- static bool readHeaderValue(const uint8_t *const dictBuf,
- const char *const key, int *outValue, const int outValueSize);
-
- static int readHeaderValueInt(const uint8_t *const dictBuf, const char *const key);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderReadingUtils);
-
- static const int HEADER_MAGIC_NUMBER_SIZE;
- static const int HEADER_DICTIONARY_VERSION_SIZE;
- static const int HEADER_FLAG_SIZE;
- static const int HEADER_SIZE_FIELD_SIZE;
-
- static const DictionaryFlags NO_FLAGS;
- // Flags for special processing
- // Those *must* match the flags in makedict (FormatSpec#*_PROCESSING_FLAGS) or
- // something very bad (like, the apocalypse) will happen. Please update both at the same time.
- static const DictionaryFlags GERMAN_UMLAUT_PROCESSING_FLAG;
- static const DictionaryFlags SUPPORTS_DYNAMIC_UPDATE_FLAG;
- static const DictionaryFlags FRENCH_LIGATURE_PROCESSING_FLAG;
- static const DictionaryFlags CONTAINS_BIGRAMS_FLAG;
-};
-}
-#endif /* LATINIME_HEADER_READING_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
index 3e664a29b..8a84bd261 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
@@ -20,8 +20,8 @@
#include "defines.h"
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
-#include "suggest/policyimpl/dictionary/binary_format.h"
#include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/probability_utils.h"
namespace latinime {
@@ -31,31 +31,311 @@ void PatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode,
return;
}
int nextPos = dicNode->getChildrenPos();
- const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
+ if (nextPos < 0 || nextPos >= mDictBufferSize) {
+ AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %d",
+ nextPos, mDictBufferSize);
+ ASSERT(false);
+ return;
+ }
+ const int childCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
mDictRoot, &nextPos);
for (int i = 0; i < childCount; i++) {
+ if (nextPos < 0 || nextPos >= mDictBufferSize) {
+ AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %d, childCount: %d / %d",
+ nextPos, mDictBufferSize, i, childCount);
+ ASSERT(false);
+ return;
+ }
nextPos = createAndGetLeavingChildNode(dicNode, nextPos, childDicNodes);
}
}
+// This retrieves code points and the probability of the word by its terminal position.
+// Due to the fact that words are ordered in the dictionary in a strict breadth-first order,
+// it is possible to check for this with advantageous complexity. For each node, we search
+// for PtNodes with children and compare the children position with the position we look for.
+// When we shoot the position we look for, it means the word we look for is in the children
+// of the previous PtNode. The only tricky part is the fact that if we arrive at the end of a
+// PtNode array with the last PtNode's children position still less than what we are searching for,
+// we must descend the last PtNode's children (for example, if the word we are searching for starts
+// with a z, it's the last PtNode of the root array, so all children addresses will be smaller
+// than the position we look for, and we have to descend the z node).
+/* Parameters :
+ * ptNodePos: the byte position of the terminal PtNode of the word we are searching for (this is
+ * what is stored as the "bigram position" in each bigram)
+ * outCodePoints: an array to write the found word, with MAX_WORD_LENGTH size.
+ * outUnigramProbability: a pointer to an int to write the probability into.
+ * Return value : the code point count, of 0 if the word was not found.
+ */
+// TODO: Split this function to be more readable
int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
- const int nodePos, const int maxCodePointCount, int *const outCodePoints,
+ const int ptNodePos, const int maxCodePointCount, int *const outCodePoints,
int *const outUnigramProbability) const {
- return BinaryFormat::getCodePointsAndProbabilityAndReturnCodePointCount(mDictRoot, nodePos,
- maxCodePointCount, outCodePoints, outUnigramProbability);
+ int pos = getRootPosition();
+ int wordPos = 0;
+ // One iteration of the outer loop iterates through PtNode arrays. As stated above, we will
+ // only traverse nodes that are actually a part of the terminal we are searching, so each time
+ // we enter this loop we are one depth level further than last time.
+ // The only reason we count nodes is because we want to reduce the probability of infinite
+ // looping in case there is a bug. Since we know there is an upper bound to the depth we are
+ // supposed to traverse, it does not hurt to count iterations.
+ for (int loopCount = maxCodePointCount; loopCount > 0; --loopCount) {
+ int lastCandidatePtNodePos = 0;
+ // Let's loop through PtNodes in this PtNode array searching for either the terminal
+ // or one of its ascendants.
+ for (int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
+ mDictRoot, &pos); ptNodeCount > 0; --ptNodeCount) {
+ const int startPos = pos;
+ const PatriciaTrieReadingUtils::NodeFlags flags =
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
+ const int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &pos);
+ if (ptNodePos == startPos) {
+ // We found the position. Copy the rest of the code points in the buffer and return
+ // the length.
+ outCodePoints[wordPos] = character;
+ if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
+ int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &pos);
+ // We count code points in order to avoid infinite loops if the file is broken
+ // or if there is some other bug
+ int charCount = maxCodePointCount;
+ while (NOT_A_CODE_POINT != nextChar && --charCount > 0) {
+ outCodePoints[++wordPos] = nextChar;
+ nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &pos);
+ }
+ }
+ *outUnigramProbability =
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+ &pos);
+ return ++wordPos;
+ }
+ // We need to skip past this PtNode, so skip any remaining code points after the
+ // first and possibly the probability.
+ if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
+ PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
+ }
+ if (PatriciaTrieReadingUtils::isTerminal(flags)) {
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ }
+ // The fact that this PtNode has children is very important. Since we already know
+ // that this PtNode does not match, if it has no children we know it is irrelevant
+ // to what we are searching for.
+ const bool hasChildren = PatriciaTrieReadingUtils::hasChildrenInFlags(flags);
+ // We will write in `found' whether we have passed the children position we are
+ // searching for. For example if we search for "beer", the children of b are less
+ // than the address we are searching for and the children of c are greater. When we
+ // come here for c, we realize this is too big, and that we should descend b.
+ bool found;
+ if (hasChildren) {
+ int currentPos = pos;
+ // Here comes the tricky part. First, read the children position.
+ const int childrenPos = PatriciaTrieReadingUtils
+ ::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &currentPos);
+ if (childrenPos > ptNodePos) {
+ // If the children pos is greater than the position, it means the previous
+ // PtNode, which position is stored in lastCandidatePtNodePos, was the right
+ // one.
+ found = true;
+ } else if (1 >= ptNodeCount) {
+ // However if we are on the LAST PtNode of this array, and we have NOT shot the
+ // position we should descend THIS node. So we trick the lastCandidatePtNodePos
+ // so that we will descend this PtNode, not the previous one.
+ lastCandidatePtNodePos = startPos;
+ found = true;
+ } else {
+ // Else, we should continue looking.
+ found = false;
+ }
+ } else {
+ // Even if we don't have children here, we could still be on the last PtNode of /
+ // this array. If this is the case, we should descend the last PtNode that had
+ // children, and their position is already in lastCandidatePtNodePos.
+ found = (1 >= ptNodeCount);
+ }
+
+ if (found) {
+ // Okay, we found the PtNode we should descend. Its position is in
+ // the lastCandidatePtNodePos variable, so we just re-read it.
+ if (0 != lastCandidatePtNodePos) {
+ const PatriciaTrieReadingUtils::NodeFlags lastFlags =
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(
+ mDictRoot, &lastCandidatePtNodePos);
+ const int lastChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &lastCandidatePtNodePos);
+ // We copy all the characters in this PtNode to the buffer
+ outCodePoints[wordPos] = lastChar;
+ if (PatriciaTrieReadingUtils::hasMultipleChars(lastFlags)) {
+ int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &lastCandidatePtNodePos);
+ int charCount = maxCodePointCount;
+ while (-1 != nextChar && --charCount > 0) {
+ outCodePoints[++wordPos] = nextChar;
+ nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &lastCandidatePtNodePos);
+ }
+ }
+ ++wordPos;
+ // Now we only need to branch to the children address. Skip the probability if
+ // it's there, read pos, and break to resume the search at pos.
+ if (PatriciaTrieReadingUtils::isTerminal(lastFlags)) {
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+ &lastCandidatePtNodePos);
+ }
+ pos = PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
+ mDictRoot, lastFlags, &lastCandidatePtNodePos);
+ break;
+ } else {
+ // Here is a little tricky part: we come here if we found out that all children
+ // addresses in this PtNode are bigger than the address we are searching for.
+ // Should we conclude the word is not in the dictionary? No! It could still be
+ // one of the remaining PtNodes in this array, so we have to keep looking in
+ // this array until we find it (or we realize it's not there either, in which
+ // case it's actually not in the dictionary). Pass the end of this PtNode,
+ // ready to start the next one.
+ if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
+ PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
+ mDictRoot, flags, &pos);
+ }
+ if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
+ mShortcutListPolicy.skipAllShortcuts(&pos);
+ }
+ if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
+ mBigramListPolicy.skipAllBigrams(&pos);
+ }
+ }
+ } else {
+ // If we did not find it, we should record the last children address for the next
+ // iteration.
+ if (hasChildren) lastCandidatePtNodePos = startPos;
+ // Now skip the end of this PtNode (children pos and the attributes if any) so that
+ // our pos is after the end of this PtNode, at the start of the next one.
+ if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
+ PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
+ mDictRoot, flags, &pos);
+ }
+ if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
+ mShortcutListPolicy.skipAllShortcuts(&pos);
+ }
+ if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
+ mBigramListPolicy.skipAllBigrams(&pos);
+ }
+ }
+
+ }
+ }
+ // If we have looked through all the PtNodes and found no match, the ptNodePos is
+ // not the position of a terminal in this dictionary.
+ return 0;
}
+// This function gets the position of the terminal node of the exact matching word in the
+// dictionary. If no match is found, it returns NOT_A_DICT_POS.
int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
const int length, const bool forceLowerCaseSearch) const {
- return BinaryFormat::getTerminalPosition(mDictRoot, inWord,
- length, forceLowerCaseSearch);
+ int pos = getRootPosition();
+ int wordPos = 0;
+
+ while (true) {
+ // If we already traversed the tree further than the word is long, there means
+ // there was no match (or we would have found it).
+ if (wordPos >= length) return NOT_A_DICT_POS;
+ int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(mDictRoot,
+ &pos);
+ const int wChar = forceLowerCaseSearch
+ ? CharUtils::toLowerCase(inWord[wordPos]) : inWord[wordPos];
+ while (true) {
+ // If there are no more PtNodes in this array, it means we could not
+ // find a matching character for this depth, therefore there is no match.
+ if (0 >= ptNodeCount) return NOT_A_DICT_POS;
+ const int ptNodePos = pos;
+ const PatriciaTrieReadingUtils::NodeFlags flags =
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
+ int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(mDictRoot,
+ &pos);
+ if (character == wChar) {
+ // This is the correct PtNode. Only one PtNode may start with the same char within
+ // a PtNode array, so either we found our match in this array, or there is
+ // no match and we can return NOT_A_DICT_POS. So we will check all the
+ // characters in this PtNode indeed does match.
+ if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
+ character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(mDictRoot,
+ &pos);
+ while (NOT_A_CODE_POINT != character) {
+ ++wordPos;
+ // If we shoot the length of the word we search for, or if we find a single
+ // character that does not match, as explained above, it means the word is
+ // not in the dictionary (by virtue of this PtNode being the only one to
+ // match the word on the first character, but not matching the whole word).
+ if (wordPos >= length) return NOT_A_DICT_POS;
+ if (inWord[wordPos] != character) return NOT_A_DICT_POS;
+ character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
+ mDictRoot, &pos);
+ }
+ }
+ // If we come here we know that so far, we do match. Either we are on a terminal
+ // and we match the length, in which case we found it, or we traverse children.
+ // If we don't match the length AND don't have children, then a word in the
+ // dictionary fully matches a prefix of the searched word but not the full word.
+ ++wordPos;
+ if (PatriciaTrieReadingUtils::isTerminal(flags)) {
+ if (wordPos == length) {
+ return ptNodePos;
+ }
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ }
+ if (!PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
+ return NOT_A_DICT_POS;
+ }
+ // We have children and we are still shorter than the word we are searching for, so
+ // we need to traverse children. Put the pointer on the children position, and
+ // break
+ pos = PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot,
+ flags, &pos);
+ break;
+ } else {
+ // This PtNode does not match, so skip the remaining part and go to the next.
+ if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
+ PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH,
+ &pos);
+ }
+ if (PatriciaTrieReadingUtils::isTerminal(flags)) {
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ }
+ if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
+ PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot,
+ flags, &pos);
+ }
+ if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
+ mShortcutListPolicy.skipAllShortcuts(&pos);
+ }
+ if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
+ mBigramListPolicy.skipAllBigrams(&pos);
+ }
+ }
+ --ptNodeCount;
+ }
+ }
+}
+
+int PatriciaTriePolicy::getProbability(const int unigramProbability,
+ const int bigramProbability) const {
+ if (unigramProbability == NOT_A_PROBABILITY) {
+ return NOT_A_PROBABILITY;
+ } else if (bigramProbability == NOT_A_PROBABILITY) {
+ return ProbabilityUtils::backoff(unigramProbability);
+ } else {
+ return ProbabilityUtils::computeProbabilityForBigram(unigramProbability,
+ bigramProbability);
+ }
}
-int PatriciaTriePolicy::getUnigramProbability(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
- int pos = nodePos;
+ int pos = ptNodePos;
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
if (!PatriciaTrieReadingUtils::isTerminal(flags)) {
@@ -69,14 +349,15 @@ int PatriciaTriePolicy::getUnigramProbability(const int nodePos) const {
return NOT_A_PROBABILITY;
}
PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
- return PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ return getProbability(PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(
+ mDictRoot, &pos), NOT_A_PROBABILITY);
}
-int PatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
- int pos = nodePos;
+ int pos = ptNodePos;
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
if (!PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
@@ -92,11 +373,11 @@ int PatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
return pos;
}
-int PatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+int PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const {
+ if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
- int pos = nodePos;
+ int pos = ptNodePos;
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
if (!PatriciaTrieReadingUtils::hasBigrams(flags)) {
@@ -116,8 +397,8 @@ int PatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
}
int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNode,
- const int nodePos, DicNodeVector *childDicNodes) const {
- int pos = nodePos;
+ const int ptNodePos, DicNodeVector *childDicNodes) const {
+ int pos = ptNodePos;
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
int mergedNodeCodePoints[MAX_WORD_LENGTH];
@@ -135,7 +416,12 @@ int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNod
if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
getBigramsStructurePolicy()->skipAllBigrams(&pos);
}
- childDicNodes->pushLeavingChild(dicNode, nodePos, childrenPos, probability,
+ if (mergedNodeCodePointCount <= 0) {
+ AKLOGE("Empty PtNode is not allowed. Code point count: %d", mergedNodeCodePointCount);
+ ASSERT(false);
+ return pos;
+ }
+ childDicNodes->pushLeavingChild(dicNode, ptNodePos, childrenPos, probability,
PatriciaTrieReadingUtils::isTerminal(flags),
PatriciaTrieReadingUtils::hasChildrenInFlags(flags),
PatriciaTrieReadingUtils::isBlacklisted(flags) ||
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
index 0d85050f3..f1de914cb 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
@@ -24,7 +24,7 @@
#include "suggest/policyimpl/dictionary/bigram/bigram_list_policy.h"
#include "suggest/policyimpl/dictionary/header/header_policy.h"
#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_policy.h"
-#include "suggest/policyimpl/dictionary/utils/mmaped_buffer.h"
+#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
namespace latinime {
@@ -33,9 +33,10 @@ class DicNodeVector;
class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
public:
- PatriciaTriePolicy(const MmapedBuffer *const buffer)
- : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer()),
+ PatriciaTriePolicy(const MmappedBuffer *const buffer)
+ : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), buffer->getBufferSize()),
mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()),
+ mDictBufferSize(mBuffer->getBufferSize() - mHeaderPolicy.getSize()),
mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {}
~PatriciaTriePolicy() {
@@ -56,11 +57,13 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
int getTerminalNodePositionOfWord(const int *const inWord,
const int length, const bool forceLowerCaseSearch) const;
- int getUnigramProbability(const int nodePos) const;
+ int getProbability(const int unigramProbability, const int bigramProbability) const;
- int getShortcutPositionOfNode(const int nodePos) const;
+ int getUnigramProbabilityOfPtNode(const int ptNodePos) const;
- int getBigramsPositionOfNode(const int nodePos) const;
+ int getShortcutPositionOfPtNode(const int ptNodePos) const;
+
+ int getBigramsPositionOfPtNode(const int ptNodePos) const;
const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const {
return &mHeaderPolicy;
@@ -94,16 +97,33 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
return false;
}
+ void flush(const char *const filePath) {
+ // This method should not be called for non-updatable dictionary.
+ AKLOGI("Warning: flush() is called for non-updatable dictionary.");
+ }
+
+ void flushWithGC(const char *const filePath) {
+ // This method should not be called for non-updatable dictionary.
+ AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary.");
+ }
+
+ bool needsToRunGC() const {
+ // This method should not be called for non-updatable dictionary.
+ AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary.");
+ return false;
+ }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy);
- const MmapedBuffer *const mBuffer;
+ const MmappedBuffer *const mBuffer;
const HeaderPolicy mHeaderPolicy;
const uint8_t *const mDictRoot;
+ const int mDictBufferSize;
const BigramListPolicy mBigramListPolicy;
const ShortcutListPolicy mShortcutListPolicy;
- int createAndGetLeavingChildNode(const DicNode *const dicNode, const int nodePos,
+ int createAndGetLeavingChildNode(const DicNode *const dicNode, const int ptNodePos,
DicNodeVector *const childDicNodes) const;
};
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
index 003b9435b..7df55815f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
@@ -23,15 +23,15 @@ namespace latinime {
typedef PatriciaTrieReadingUtils PtReadingUtils;
-const PtReadingUtils::NodeFlags PtReadingUtils::MASK_GROUP_ADDRESS_TYPE = 0xC0;
-const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00;
-const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_GROUP_ADDRESS_TYPE_ONEBYTE = 0x40;
-const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_GROUP_ADDRESS_TYPE_TWOBYTES = 0x80;
-const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_GROUP_ADDRESS_TYPE_THREEBYTES = 0xC0;
+const PtReadingUtils::NodeFlags PtReadingUtils::MASK_CHILDREN_POSITION_TYPE = 0xC0;
+const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_CHILDREN_POSITION_TYPE_NOPOSITION = 0x00;
+const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_CHILDREN_POSITION_TYPE_ONEBYTE = 0x40;
+const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_CHILDREN_POSITION_TYPE_TWOBYTES = 0x80;
+const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_CHILDREN_POSITION_TYPE_THREEBYTES = 0xC0;
// Flag for single/multiple char group
const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_HAS_MULTIPLE_CHARS = 0x20;
-// Flag for terminal groups
+// Flag for terminal PtNodes
const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_TERMINAL = 0x10;
// Flag for shortcut targets presence
const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_HAS_SHORTCUT_TARGETS = 0x08;
@@ -42,18 +42,84 @@ const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_NOT_A_WORD = 0x02;
// Flag for blacklist
const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_BLACKLISTED = 0x01;
+/* static */ int PtReadingUtils::getPtNodeArraySizeAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ const uint8_t firstByte = ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+ if (firstByte < 0x80) {
+ return firstByte;
+ } else {
+ return ((firstByte & 0x7F) << 8) ^ ByteArrayUtils::readUint8AndAdvancePosition(
+ buffer, pos);
+ }
+}
+
+/* static */ PtReadingUtils::NodeFlags PtReadingUtils::getFlagsAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+}
+
+/* static */ int PtReadingUtils::getCodePointAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos) {
+ return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, pos);
+}
+
+// Returns the number of read characters.
+/* static */ int PtReadingUtils::getCharsAndAdvancePosition(const uint8_t *const buffer,
+ const NodeFlags flags, const int maxLength, int *const outBuffer, int *const pos) {
+ int length = 0;
+ if (hasMultipleChars(flags)) {
+ length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, outBuffer,
+ pos);
+ } else {
+ const int codePoint = getCodePointAndAdvancePosition(buffer, pos);
+ if (codePoint == NOT_A_CODE_POINT) {
+ // CAVEAT: codePoint == NOT_A_CODE_POINT means the code point is
+ // CHARACTER_ARRAY_TERMINATOR. The code point must not be CHARACTER_ARRAY_TERMINATOR
+ // when the PtNode has a single code point.
+ length = 0;
+ AKLOGE("codePoint is NOT_A_CODE_POINT. pos: %d, codePoint: 0x%x, buffer[pos - 1]: 0x%x",
+ *pos - 1, codePoint, buffer[*pos - 1]);
+ ASSERT(false);
+ } else if (maxLength > 0) {
+ outBuffer[0] = codePoint;
+ length = 1;
+ }
+ }
+ return length;
+}
+
+// Returns the number of skipped characters.
+/* static */ int PtReadingUtils::skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const pos) {
+ if (hasMultipleChars(flags)) {
+ return ByteArrayUtils::advancePositionToBehindString(buffer, maxLength, pos);
+ } else {
+ if (maxLength > 0) {
+ getCodePointAndAdvancePosition(buffer, pos);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+/* static */ int PtReadingUtils::readProbabilityAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+}
+
/* static */ int PtReadingUtils::readChildrenPositionAndAdvancePosition(
const uint8_t *const buffer, const NodeFlags flags, int *const pos) {
const int base = *pos;
int offset = 0;
- switch (MASK_GROUP_ADDRESS_TYPE & flags) {
- case FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
+ switch (MASK_CHILDREN_POSITION_TYPE & flags) {
+ case FLAG_CHILDREN_POSITION_TYPE_ONEBYTE:
offset = ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
break;
- case FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
+ case FLAG_CHILDREN_POSITION_TYPE_TWOBYTES:
offset = ByteArrayUtils::readUint16AndAdvancePosition(buffer, pos);
break;
- case FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
+ case FLAG_CHILDREN_POSITION_TYPE_THREEBYTES:
offset = ByteArrayUtils::readUint24AndAdvancePosition(buffer, pos);
break;
default:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
index 9f2fc2059..8420ee95a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,62 +27,21 @@ class PatriciaTrieReadingUtils {
public:
typedef uint8_t NodeFlags;
- static AK_FORCE_INLINE int getGroupCountAndAdvancePosition(
- const uint8_t *const buffer, int *const pos) {
- const uint8_t firstByte = ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- if (firstByte < 0x80) {
- return firstByte;
- } else {
- return ((firstByte & 0x7F) << 8) ^ ByteArrayUtils::readUint8AndAdvancePosition(
- buffer, pos);
- }
- }
+ static int getPtNodeArraySizeAndAdvancePosition(const uint8_t *const buffer, int *const pos);
- static AK_FORCE_INLINE NodeFlags getFlagsAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- }
+ static NodeFlags getFlagsAndAdvancePosition(const uint8_t *const buffer, int *const pos);
- static AK_FORCE_INLINE int getCodePointAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, pos);
- }
+ static int getCodePointAndAdvancePosition(const uint8_t *const buffer, int *const pos);
// Returns the number of read characters.
- static AK_FORCE_INLINE int getCharsAndAdvancePosition(const uint8_t *const buffer,
- const NodeFlags flags, const int maxLength, int *const outBuffer, int *const pos) {
- int length = 0;
- if (hasMultipleChars(flags)) {
- length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, outBuffer,
- pos);
- } else {
- if (maxLength > 0) {
- outBuffer[0] = getCodePointAndAdvancePosition(buffer, pos);
- length = 1;
- }
- }
- return length;
- }
+ static int getCharsAndAdvancePosition(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const outBuffer, int *const pos);
// Returns the number of skipped characters.
- static AK_FORCE_INLINE int skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
- const int maxLength, int *const pos) {
- if (hasMultipleChars(flags)) {
- return ByteArrayUtils::advancePositionToBehindString(buffer, maxLength, pos);
- } else {
- if (maxLength > 0) {
- getCodePointAndAdvancePosition(buffer, pos);
- return 1;
- } else {
- return 0;
- }
- }
- }
+ static int skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const pos);
- static AK_FORCE_INLINE int readProbabilityAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- }
+ static int readProbabilityAndAdvancePosition(const uint8_t *const buffer, int *const pos);
static int readChildrenPositionAndAdvancePosition(const uint8_t *const buffer,
const NodeFlags flags, int *const pos);
@@ -116,17 +74,40 @@ class PatriciaTrieReadingUtils {
}
static AK_FORCE_INLINE bool hasChildrenInFlags(const NodeFlags flags) {
- return FLAG_GROUP_ADDRESS_TYPE_NOADDRESS != (MASK_GROUP_ADDRESS_TYPE & flags);
+ return FLAG_CHILDREN_POSITION_TYPE_NOPOSITION != (MASK_CHILDREN_POSITION_TYPE & flags);
+ }
+
+ static AK_FORCE_INLINE NodeFlags createAndGetFlags(const bool isBlacklisted,
+ const bool isNotAWord, const bool isTerminal, const bool hasShortcutTargets,
+ const bool hasBigrams, const bool hasMultipleChars,
+ const int childrenPositionFieldSize) {
+ NodeFlags nodeFlags = 0;
+ nodeFlags = isBlacklisted ? (nodeFlags | FLAG_IS_BLACKLISTED) : nodeFlags;
+ nodeFlags = isNotAWord ? (nodeFlags | FLAG_IS_NOT_A_WORD) : nodeFlags;
+ nodeFlags = isTerminal ? (nodeFlags | FLAG_IS_TERMINAL) : nodeFlags;
+ nodeFlags = hasShortcutTargets ? (nodeFlags | FLAG_HAS_SHORTCUT_TARGETS) : nodeFlags;
+ nodeFlags = hasBigrams ? (nodeFlags | FLAG_HAS_BIGRAMS) : nodeFlags;
+ nodeFlags = hasMultipleChars ? (nodeFlags | FLAG_HAS_MULTIPLE_CHARS) : nodeFlags;
+ if (childrenPositionFieldSize == 1) {
+ nodeFlags |= FLAG_CHILDREN_POSITION_TYPE_ONEBYTE;
+ } else if (childrenPositionFieldSize == 2) {
+ nodeFlags |= FLAG_CHILDREN_POSITION_TYPE_TWOBYTES;
+ } else if (childrenPositionFieldSize == 3) {
+ nodeFlags |= FLAG_CHILDREN_POSITION_TYPE_THREEBYTES;
+ } else {
+ nodeFlags |= FLAG_CHILDREN_POSITION_TYPE_NOPOSITION;
+ }
+ return nodeFlags;
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTrieReadingUtils);
- static const NodeFlags MASK_GROUP_ADDRESS_TYPE;
- static const NodeFlags FLAG_GROUP_ADDRESS_TYPE_NOADDRESS;
- static const NodeFlags FLAG_GROUP_ADDRESS_TYPE_ONEBYTE;
- static const NodeFlags FLAG_GROUP_ADDRESS_TYPE_TWOBYTES;
- static const NodeFlags FLAG_GROUP_ADDRESS_TYPE_THREEBYTES;
+ static const NodeFlags MASK_CHILDREN_POSITION_TYPE;
+ static const NodeFlags FLAG_CHILDREN_POSITION_TYPE_NOPOSITION;
+ static const NodeFlags FLAG_CHILDREN_POSITION_TYPE_ONEBYTE;
+ static const NodeFlags FLAG_CHILDREN_POSITION_TYPE_TWOBYTES;
+ static const NodeFlags FLAG_CHILDREN_POSITION_TYPE_THREEBYTES;
static const NodeFlags FLAG_HAS_MULTIPLE_CHARS;
static const NodeFlags FLAG_IS_TERMINAL;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h
new file mode 100644
index 000000000..bd3211f6a
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/dynamic_shortcut_list_policy.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DYNAMIC_SHORTCUT_LIST_POLICY_H
+#define LATINIME_DYNAMIC_SHORTCUT_LIST_POLICY_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
+#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+/*
+ * This is a dynamic version of ShortcutListPolicy and supports an additional buffer.
+ */
+class DynamicShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
+ public:
+ explicit DynamicShortcutListPolicy(const BufferWithExtendableBuffer *const buffer)
+ : mBuffer(buffer) {}
+
+ ~DynamicShortcutListPolicy() {}
+
+ int getStartPos(const int pos) const {
+ if (pos == NOT_A_DICT_POS) {
+ return NOT_A_DICT_POS;
+ }
+ return pos + ShortcutListReadingUtils::getShortcutListSizeFieldSize();
+ }
+
+ void getNextShortcut(const int maxCodePointCount, int *const outCodePoint,
+ int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext,
+ int *const pos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *pos -= mBuffer->getOriginalBufferSize();
+ }
+ const ShortcutListReadingUtils::ShortcutFlags flags =
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(buffer, pos);
+ if (outHasNext) {
+ *outHasNext = ShortcutListReadingUtils::hasNext(flags);
+ }
+ if (outIsWhitelist) {
+ *outIsWhitelist = ShortcutListReadingUtils::isWhitelist(flags);
+ }
+ if (outCodePoint) {
+ *outCodePointCount = ShortcutListReadingUtils::readShortcutTarget(
+ buffer, maxCodePointCount, outCodePoint, pos);
+ }
+ if (usesAdditionalBuffer) {
+ *pos += mBuffer->getOriginalBufferSize();
+ }
+ }
+
+ void skipAllShortcuts(int *const pos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *pos -= mBuffer->getOriginalBufferSize();
+ }
+ const int shortcutListSize = ShortcutListReadingUtils
+ ::getShortcutListSizeAndForwardPointer(buffer, pos);
+ *pos += shortcutListSize;
+ if (usesAdditionalBuffer) {
+ *pos += mBuffer->getOriginalBufferSize();
+ }
+ }
+
+ // Copy shortcuts from the shortcut list that starts at fromPos in mBuffer to toPos in
+ // bufferToWrite and advance these positions after the shortcut lists. This returns whether
+ // the copy was succeeded or not.
+ bool copyAllShortcutsAndReturnIfSucceededOrNot(BufferWithExtendableBuffer *const bufferToWrite,
+ int *const fromPos, int *const toPos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*fromPos);
+ if (usesAdditionalBuffer) {
+ *fromPos -= mBuffer->getOriginalBufferSize();
+ }
+ const int shortcutListSize = ShortcutListReadingUtils
+ ::getShortcutListSizeAndForwardPointer(mBuffer->getBuffer(usesAdditionalBuffer),
+ fromPos);
+ // Copy shortcut list size.
+ if (!bufferToWrite->writeUintAndAdvancePosition(
+ shortcutListSize + ShortcutListReadingUtils::getShortcutListSizeFieldSize(),
+ ShortcutListReadingUtils::getShortcutListSizeFieldSize(), toPos)) {
+ return false;
+ }
+ // Copy shortcut list.
+ for (int i = 0; i < shortcutListSize; ++i) {
+ const uint8_t data = ByteArrayUtils::readUint8AndAdvancePosition(
+ mBuffer->getBuffer(usesAdditionalBuffer), fromPos);
+ if (!bufferToWrite->writeUintAndAdvancePosition(data, 1 /* size */, toPos)) {
+ return false;
+ }
+ }
+ if (usesAdditionalBuffer) {
+ *fromPos += mBuffer->getOriginalBufferSize();
+ }
+ return true;
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicShortcutListPolicy);
+
+ const BufferWithExtendableBuffer *const mBuffer;
+};
+} // namespace latinime
+#endif // LATINIME_DYNAMIC_SHORTCUT_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
index e70bb5071..847dcdee5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
@@ -16,6 +16,8 @@
#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+
namespace latinime {
// Flag for presence of more attributes
@@ -28,4 +30,22 @@ const int ShortcutListReadingUtils::SHORTCUT_LIST_SIZE_FIELD_SIZE = 2;
// The numeric value of the shortcut probability that means 'whitelist'.
const int ShortcutListReadingUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
+/* static */ ShortcutListReadingUtils::ShortcutFlags
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(const uint8_t *const dictRoot,
+ int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
+}
+
+/* static */ int ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(
+ const uint8_t *const dictRoot, int *const pos) {
+ // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
+ return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
+ - SHORTCUT_LIST_SIZE_FIELD_SIZE;
+}
+
+/* static */ int ShortcutListReadingUtils::readShortcutTarget(
+ const uint8_t *const dictRoot, const int maxLength, int *const outWord, int *const pos) {
+ return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
+}
+
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
index b5bb964d5..a83ed5a50 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,10 +27,7 @@ class ShortcutListReadingUtils {
public:
typedef uint8_t ShortcutFlags;
- static AK_FORCE_INLINE ShortcutFlags getFlagsAndForwardPointer(
- const uint8_t *const dictRoot, int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
- }
+ static ShortcutFlags getFlagsAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const ShortcutFlags flags) {
return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -43,11 +39,10 @@ class ShortcutListReadingUtils {
// This method returns the size of the shortcut list region excluding the shortcut list size
// field at the beginning.
- static AK_FORCE_INLINE int getShortcutListSizeAndForwardPointer(
- const uint8_t *const dictRoot, int *const pos) {
- // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
- return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
- - SHORTCUT_LIST_SIZE_FIELD_SIZE;
+ static int getShortcutListSizeAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
+
+ static AK_FORCE_INLINE int getShortcutListSizeFieldSize() {
+ return SHORTCUT_LIST_SIZE_FIELD_SIZE;
}
static AK_FORCE_INLINE void skipShortcuts(const uint8_t *const dictRoot, int *const pos) {
@@ -59,11 +54,8 @@ class ShortcutListReadingUtils {
return getProbabilityFromFlags(flags) == WHITELIST_SHORTCUT_PROBABILITY;
}
- static AK_FORCE_INLINE int readShortcutTarget(
- const uint8_t *const dictRoot, const int maxLength, int *const outWord,
- int *const pos) {
- return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
- }
+ static int readShortcutTarget(const uint8_t *const dictRoot, const int maxLength,
+ int *const outWord, int *const pos);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutListReadingUtils);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
new file mode 100644
index 000000000..f692882f2
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
@@ -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.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+
+namespace latinime {
+
+const size_t BufferWithExtendableBuffer::MAX_ADDITIONAL_BUFFER_SIZE = 1024 * 1024;
+const int BufferWithExtendableBuffer::NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE = 90;
+// TODO: Needs to allocate larger memory corresponding to the current vector size.
+const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 128 * 1024;
+
+bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data, const int size,
+ int *const pos) {
+ if (!(size >= 1 && size <= 4)) {
+ AKLOGI("writeUintAndAdvancePosition() is called with invalid size: %d", size);
+ ASSERT(false);
+ return false;
+ }
+ if (!checkAndPrepareWriting(*pos, size)) {
+ return false;
+ }
+ const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos);
+ uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer;
+ if (usesAdditionalBuffer) {
+ *pos -= mOriginalBufferSize;
+ }
+ ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos);
+ if (usesAdditionalBuffer) {
+ *pos += mOriginalBufferSize;
+ }
+ return true;
+}
+
+bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *const codePoints,
+ const int codePointCount, const bool writesTerminator ,int *const pos) {
+ const size_t size = ByteArrayUtils::calculateRequiredByteCountToStoreCodePoints(
+ codePoints, codePointCount, writesTerminator);
+ if (!checkAndPrepareWriting(*pos, size)) {
+ return false;
+ }
+ const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos);
+ uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer;
+ if (usesAdditionalBuffer) {
+ *pos -= mOriginalBufferSize;
+ }
+ ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount,
+ writesTerminator, pos);
+ if (usesAdditionalBuffer) {
+ *pos += mOriginalBufferSize;
+ }
+ return true;
+}
+
+bool BufferWithExtendableBuffer::extendBuffer() {
+ const size_t sizeAfterExtending =
+ mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP;
+ if (sizeAfterExtending > mMaxAdditionalBufferSize) {
+ return false;
+ }
+ mAdditionalBuffer.resize(mAdditionalBuffer.size() + EXTEND_ADDITIONAL_BUFFER_SIZE_STEP);
+ return true;
+}
+
+bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int size) {
+ if (isInAdditionalBuffer(pos)) {
+ const int tailPosition = getTailPosition();
+ if (pos == tailPosition) {
+ // Append data to the tail.
+ if (pos + size > static_cast<int>(mAdditionalBuffer.size()) + mOriginalBufferSize) {
+ // Need to extend buffer.
+ if (!extendBuffer()) {
+ return false;
+ }
+ }
+ mUsedAdditionalBufferSize += size;
+ } else if (pos + size > tailPosition) {
+ // The access will beyond the tail of used region.
+ return false;
+ }
+ } else {
+ if (pos < 0 || mOriginalBufferSize < pos + size) {
+ // Invalid position or violate the boundary.
+ return false;
+ }
+ }
+ return true;
+}
+
+}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
new file mode 100644
index 000000000..17d2e39c2
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
@@ -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.
+ */
+
+#ifndef LATINIME_BUFFER_WITH_EXTENDABLE_BUFFER_H
+#define LATINIME_BUFFER_WITH_EXTENDABLE_BUFFER_H
+
+#include <cstddef>
+#include <stdint.h>
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+
+namespace latinime {
+
+// This is used as a buffer that can be extended for updatable dictionaries.
+// To optimize performance, raw pointer is directly used for reading buffer. The position has to be
+// adjusted to access additional buffer. On the other hand, this class does not provide writable
+// raw pointer but provides several methods that handle boundary checking for writing data.
+class BufferWithExtendableBuffer {
+ public:
+ BufferWithExtendableBuffer(uint8_t *const originalBuffer, const int originalBufferSize,
+ const int maxAdditionalBufferSize = MAX_ADDITIONAL_BUFFER_SIZE)
+ : mOriginalBuffer(originalBuffer), mOriginalBufferSize(originalBufferSize),
+ mAdditionalBuffer(EXTEND_ADDITIONAL_BUFFER_SIZE_STEP), mUsedAdditionalBufferSize(0),
+ mMaxAdditionalBufferSize(maxAdditionalBufferSize) {}
+
+ AK_FORCE_INLINE int getTailPosition() const {
+ return mOriginalBufferSize + mUsedAdditionalBufferSize;
+ }
+
+ /**
+ * For reading.
+ */
+ AK_FORCE_INLINE bool isInAdditionalBuffer(const int position) const {
+ return position >= mOriginalBufferSize;
+ }
+
+ // TODO: Resolve the issue that the address can be changed when the vector is resized.
+ // CAVEAT!: Be careful about array out of bound access with buffers
+ AK_FORCE_INLINE const uint8_t *getBuffer(const bool usesAdditionalBuffer) const {
+ if (usesAdditionalBuffer) {
+ return &mAdditionalBuffer[0];
+ } else {
+ return mOriginalBuffer;
+ }
+ }
+
+ AK_FORCE_INLINE int getOriginalBufferSize() const {
+ return mOriginalBufferSize;
+ }
+
+ AK_FORCE_INLINE bool isNearSizeLimit() const {
+ return mAdditionalBuffer.size() >= ((mMaxAdditionalBufferSize
+ * NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE) / 100);
+ }
+
+ /**
+ * For writing.
+ *
+ * Writing is allowed for original buffer, already written region of additional buffer and the
+ * tail of additional buffer.
+ */
+ bool writeUintAndAdvancePosition(const uint32_t data, const int size, int *const pos);
+
+ bool writeCodePointsAndAdvancePosition(const int *const codePoints, const int codePointCount,
+ const bool writesTerminator, int *const pos);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BufferWithExtendableBuffer);
+
+ static const size_t MAX_ADDITIONAL_BUFFER_SIZE;
+ static const int NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE;
+ static const size_t EXTEND_ADDITIONAL_BUFFER_SIZE_STEP;
+
+ uint8_t *const mOriginalBuffer;
+ const int mOriginalBufferSize;
+ std::vector<uint8_t> mAdditionalBuffer;
+ int mUsedAdditionalBufferSize;
+ const size_t mMaxAdditionalBufferSize;
+
+ // Return if the buffer is successfully extended or not.
+ bool extendBuffer();
+
+ // Returns if it is possible to write size-bytes from pos. When pos is at the tail position of
+ // the additional buffer, try extending the buffer.
+ bool checkAndPrepareWriting(const int pos, const int size);
+};
+}
+#endif /* LATINIME_BUFFER_WITH_EXTENDABLE_BUFFER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.cpp
index a84cfb9d5..1833e8832 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.cpp
@@ -18,7 +18,8 @@
namespace latinime {
-const uint8_t ByteArrayUtils::MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
+const uint8_t ByteArrayUtils::MINIMUM_ONE_BYTE_CHARACTER_VALUE = 0x20;
+const uint8_t ByteArrayUtils::MAXIMUM_ONE_BYTE_CHARACTER_VALUE = 0xFF;
const uint8_t ByteArrayUtils::CHARACTER_ARRAY_TERMINATOR = 0x1F;
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
index 75ccfc766..0c1576818 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
@@ -29,7 +29,34 @@ namespace latinime {
class ByteArrayUtils {
public:
/**
- * Integer
+ * Integer writing
+ *
+ * Each method write a corresponding size integer in a big endian manner.
+ */
+ static AK_FORCE_INLINE void writeUintAndAdvancePosition(uint8_t *const buffer,
+ const uint32_t data, const int size, int *const pos) {
+ // size must be in 1 to 4.
+ ASSERT(size >= 1 && size <= 4);
+ switch (size) {
+ case 1:
+ ByteArrayUtils::writeUint8AndAdvancePosition(buffer, data, pos);
+ return;
+ case 2:
+ ByteArrayUtils::writeUint16AndAdvancePosition(buffer, data, pos);
+ return;
+ case 3:
+ ByteArrayUtils::writeUint24AndAdvancePosition(buffer, data, pos);
+ return;
+ case 4:
+ ByteArrayUtils::writeUint32AndAdvancePosition(buffer, data, pos);
+ return;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Integer reading
*
* Each method read a corresponding size integer in a big endian manner.
*/
@@ -88,7 +115,7 @@ class ByteArrayUtils {
}
/**
- * Code Point
+ * Code Point Reading
*
* 1 byte = bbbbbbbb match
* case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte
@@ -108,7 +135,7 @@ class ByteArrayUtils {
static AK_FORCE_INLINE int readCodePointAndAdvancePosition(
const uint8_t *const buffer, int *const pos) {
const uint8_t firstByte = readUint8(buffer, *pos);
- if (firstByte < MINIMAL_ONE_BYTE_CHARACTER_VALUE) {
+ if (firstByte < MINIMUM_ONE_BYTE_CHARACTER_VALUE) {
if (firstByte == CHARACTER_ARRAY_TERMINATOR) {
*pos += 1;
return NOT_A_CODE_POINT;
@@ -122,7 +149,7 @@ class ByteArrayUtils {
}
/**
- * String (array of code points)
+ * String (array of code points) Reading
*
* Reads code points until the terminator is found.
*/
@@ -145,48 +172,90 @@ class ByteArrayUtils {
int codePoint = readCodePointAndAdvancePosition(buffer, pos);
while (NOT_A_CODE_POINT != codePoint && length < maxLength) {
codePoint = readCodePointAndAdvancePosition(buffer, pos);
+ length++;
}
return length;
}
- // Returns an integer less than, equal to, or greater than zero when string starting from pos
- // in buffer is less than, match, or is greater than charArray.
- static AK_FORCE_INLINE int compareStringInBufferWithCharArray(const uint8_t *const buffer,
- const char *const charArray, const int maxLength, int *const pos) {
- int index = 0;
- int codePoint = readCodePointAndAdvancePosition(buffer, pos);
- const uint8_t *const uint8CharArrayForComparison =
- reinterpret_cast<const uint8_t *>(charArray);
- while (NOT_A_CODE_POINT != codePoint
- && '\0' != uint8CharArrayForComparison[index] && index < maxLength) {
- if (codePoint != uint8CharArrayForComparison[index]) {
- // Different character is found.
- // Skip the rest of the string in the buffer.
- advancePositionToBehindString(buffer, maxLength - index, pos);
- return codePoint - uint8CharArrayForComparison[index];
+ /**
+ * String (array of code points) Writing
+ */
+ static void writeCodePointsAndAdvancePosition(uint8_t *const buffer,
+ const int *const codePoints, const int codePointCount, const bool writesTerminator,
+ int *const pos) {
+ for (int i = 0; i < codePointCount; ++i) {
+ const int codePoint = codePoints[i];
+ if (codePoint == NOT_A_CODE_POINT || codePoint == CHARACTER_ARRAY_TERMINATOR) {
+ break;
+ } else if (codePoint < MINIMUM_ONE_BYTE_CHARACTER_VALUE
+ || codePoint > MAXIMUM_ONE_BYTE_CHARACTER_VALUE) {
+ // three bytes character.
+ writeUint24AndAdvancePosition(buffer, codePoint, pos);
+ } else {
+ // one byte character.
+ writeUint8AndAdvancePosition(buffer, codePoint, pos);
}
- // Advance
- codePoint = readCodePointAndAdvancePosition(buffer, pos);
- ++index;
}
- if (NOT_A_CODE_POINT != codePoint && index < maxLength) {
- // Skip the rest of the string in the buffer.
- advancePositionToBehindString(buffer, maxLength - index, pos);
+ if (writesTerminator) {
+ writeUint8AndAdvancePosition(buffer, CHARACTER_ARRAY_TERMINATOR, pos);
}
- if (NOT_A_CODE_POINT == codePoint && '\0' == uint8CharArrayForComparison[index]) {
- // When both of the last characters are terminals, we consider the string in the buffer
- // matches the given char array
- return 0;
- } else {
- return codePoint - uint8CharArrayForComparison[index];
+ }
+
+ static int calculateRequiredByteCountToStoreCodePoints(const int *const codePoints,
+ const int codePointCount, const bool writesTerminator) {
+ int byteCount = 0;
+ for (int i = 0; i < codePointCount; ++i) {
+ const int codePoint = codePoints[i];
+ if (codePoint == NOT_A_CODE_POINT || codePoint == CHARACTER_ARRAY_TERMINATOR) {
+ break;
+ } else if (codePoint < MINIMUM_ONE_BYTE_CHARACTER_VALUE
+ || codePoint > MAXIMUM_ONE_BYTE_CHARACTER_VALUE) {
+ // three bytes character.
+ byteCount += 3;
+ } else {
+ // one byte character.
+ byteCount += 1;
+ }
}
+ if (writesTerminator) {
+ // The terminator is one byte.
+ byteCount += 1;
+ }
+ return byteCount;
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArrayUtils);
- static const uint8_t MINIMAL_ONE_BYTE_CHARACTER_VALUE;
+ static const uint8_t MINIMUM_ONE_BYTE_CHARACTER_VALUE;
+ static const uint8_t MAXIMUM_ONE_BYTE_CHARACTER_VALUE;
static const uint8_t CHARACTER_ARRAY_TERMINATOR;
+
+ static AK_FORCE_INLINE void writeUint32AndAdvancePosition(uint8_t *const buffer,
+ const uint32_t data, int *const pos) {
+ buffer[(*pos)++] = (data >> 24) & 0xFF;
+ buffer[(*pos)++] = (data >> 16) & 0xFF;
+ buffer[(*pos)++] = (data >> 8) & 0xFF;
+ buffer[(*pos)++] = data & 0xFF;
+ }
+
+ static AK_FORCE_INLINE void writeUint24AndAdvancePosition(uint8_t *const buffer,
+ const uint32_t data, int *const pos) {
+ buffer[(*pos)++] = (data >> 16) & 0xFF;
+ buffer[(*pos)++] = (data >> 8) & 0xFF;
+ buffer[(*pos)++] = data & 0xFF;
+ }
+
+ static AK_FORCE_INLINE void writeUint16AndAdvancePosition(uint8_t *const buffer,
+ const uint16_t data, int *const pos) {
+ buffer[(*pos)++] = (data >> 8) & 0xFF;
+ buffer[(*pos)++] = data & 0xFF;
+ }
+
+ static AK_FORCE_INLINE void writeUint8AndAdvancePosition(uint8_t *const buffer,
+ const uint8_t data, int *const pos) {
+ buffer[(*pos)++] = data & 0xFF;
+ }
};
} // namespace latinime
#endif /* LATINIME_BYTE_ARRAY_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
new file mode 100644
index 000000000..2e4ec2e1d
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
+
+#include <cstdio>
+#include <cstring>
+
+#include "suggest/policyimpl/dictionary/header/header_policy.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_utils.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+#include "suggest/policyimpl/dictionary/utils/format_utils.h"
+
+namespace latinime {
+
+const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = ".tmp";
+
+/* static */ bool DictFileWritingUtils::createEmptyDictFile(const char *const filePath,
+ const int dictVersion, const HeaderReadWriteUtils::AttributeMap *const attributeMap) {
+ switch (dictVersion) {
+ case 3:
+ return createEmptyV3DictFile(filePath, attributeMap);
+ default:
+ // Only version 3 dictionary is supported for now.
+ return false;
+ }
+}
+
+/* static */ bool DictFileWritingUtils::createEmptyV3DictFile(const char *const filePath,
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap) {
+ BufferWithExtendableBuffer headerBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */);
+ HeaderPolicy headerPolicy(FormatUtils::VERSION_3, attributeMap);
+ headerPolicy.writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */);
+ BufferWithExtendableBuffer bodyBuffer(0 /* originalBuffer */, 0 /* originalBufferSize */);
+ if (!DynamicPatriciaTrieWritingUtils::writeEmptyDictionary(&bodyBuffer, 0 /* rootPos */)) {
+ return false;
+ }
+ return flushAllHeaderAndBodyToFile(filePath, &headerBuffer, &bodyBuffer);
+}
+
+/* static */ bool DictFileWritingUtils::flushAllHeaderAndBodyToFile(const char *const filePath,
+ BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody) {
+ const int tmpFileNameBufSize = strlen(filePath)
+ + strlen(TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE) + 1 /* terminator */;
+ // Name of a temporary file used for writing that is a connected string of original name and
+ // TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE.
+ char tmpFileName[tmpFileNameBufSize];
+ snprintf(tmpFileName, tmpFileNameBufSize, "%s%s", filePath,
+ TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE);
+ FILE *const file = fopen(tmpFileName, "wb");
+ if (!file) {
+ AKLOGE("Dictionary file %s cannnot be opened.", tmpFileName);
+ ASSERT(false);
+ return false;
+ }
+ // Write the dictionary header.
+ if (!writeBufferToFile(file, dictHeader)) {
+ remove(tmpFileName);
+ AKLOGE("Dictionary header cannnot be written. size: %d", dictHeader->getTailPosition());
+ ASSERT(false);
+ return false;
+ }
+ // Write the dictionary body.
+ if (!writeBufferToFile(file, dictBody)) {
+ remove(tmpFileName);
+ AKLOGE("Dictionary body cannnot be written. size: %d", dictBody->getTailPosition());
+ ASSERT(false);
+ return false;
+ }
+ fclose(file);
+ rename(tmpFileName, filePath);
+ return true;
+}
+
+// This closes file pointer when an error is caused and returns whether the writing was succeeded
+// or not.
+/* static */ bool DictFileWritingUtils::writeBufferToFile(FILE *const file,
+ const BufferWithExtendableBuffer *const buffer) {
+ const int originalBufSize = buffer->getOriginalBufferSize();
+ if (originalBufSize > 0 && fwrite(buffer->getBuffer(false /* usesAdditionalBuffer */),
+ originalBufSize, 1, file) < 1) {
+ fclose(file);
+ return false;
+ }
+ const int additionalBufSize = buffer->getTailPosition() - buffer->getOriginalBufferSize();
+ if (additionalBufSize > 0 && fwrite(buffer->getBuffer(true /* usesAdditionalBuffer */),
+ additionalBufSize, 1, file) < 1) {
+ fclose(file);
+ return false;
+ }
+ return true;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h
new file mode 100644
index 000000000..bd4ac66fd
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_DICT_FILE_WRITING_UTILS_H
+#define LATINIME_DICT_FILE_WRITING_UTILS_H
+
+#include <cstdio>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/header/header_read_write_utils.h"
+
+namespace latinime {
+
+class BufferWithExtendableBuffer;
+
+class DictFileWritingUtils {
+ public:
+ static bool createEmptyDictFile(const char *const filePath, const int dictVersion,
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap);
+
+ static bool flushAllHeaderAndBodyToFile(const char *const filePath,
+ BufferWithExtendableBuffer *const dictHeader,
+ BufferWithExtendableBuffer *const dictBody);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DictFileWritingUtils);
+
+ static const char *const TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE;
+
+ static bool createEmptyV3DictFile(const char *const filePath,
+ const HeaderReadWriteUtils::AttributeMap *const attributeMap);
+
+ static bool writeBufferToFile(FILE *const file,
+ const BufferWithExtendableBuffer *const buffer);
+};
+} // namespace latinime
+#endif /* LATINIME_DICT_FILE_WRITING_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
index 3796c7b7b..1d77d5c27 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
@@ -20,20 +20,10 @@
namespace latinime {
-/**
- * Dictionary size
- */
-// Any file smaller than this is not a dictionary.
-const int FormatUtils::DICTIONARY_MINIMUM_SIZE = 4;
+const uint32_t FormatUtils::MAGIC_NUMBER = 0x9BC13AFE;
-/**
- * Format versions
- */
-// 32 bit magic number is stored at the beginning of the dictionary header to reject unsupported
-// or obsolete dictionary formats.
-const uint32_t FormatUtils::HEADER_VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
-// Magic number (4 bytes), version (2 bytes), options (2 bytes), header size (4 bytes) = 12
-const int FormatUtils::HEADER_VERSION_2_MINIMUM_SIZE = 12;
+// Magic number (4 bytes), version (2 bytes), flags (2 bytes), header size (4 bytes) = 12
+const int FormatUtils::DICTIONARY_MINIMUM_SIZE = 12;
/* static */ FormatUtils::FORMAT_VERSION FormatUtils::detectFormatVersion(
const uint8_t *const dict, const int dictSize) {
@@ -45,16 +35,10 @@ const int FormatUtils::HEADER_VERSION_2_MINIMUM_SIZE = 12;
}
const uint32_t magicNumber = ByteArrayUtils::readUint32(dict, 0);
switch (magicNumber) {
- case HEADER_VERSION_2_MAGIC_NUMBER:
- // Version 2 header are at least 12 bytes long.
- // If this header has the version 2 magic number but is less than 12 bytes long,
- // then it's an unknown format and we need to avoid confidently reading the next bytes.
- if (dictSize < HEADER_VERSION_2_MINIMUM_SIZE) {
- return UNKNOWN_VERSION;
- }
+ case MAGIC_NUMBER:
// Version 2 header is as follows:
// Magic number (4 bytes) 0x9B 0xC1 0x3A 0xFE
- // Version number (2 bytes)
+ // Dictionary format version number (2 bytes)
// Options (2 bytes)
// Header size (4 bytes) : integer, big endian
if (ByteArrayUtils::readUint16(dict, 4) == 2) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
index f84321577..79ed0de29 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
@@ -34,14 +34,16 @@ class FormatUtils {
UNKNOWN_VERSION
};
+ // 32 bit magic number is stored at the beginning of the dictionary header to reject
+ // unsupported or obsolete dictionary formats.
+ static const uint32_t MAGIC_NUMBER;
+
static FORMAT_VERSION detectFormatVersion(const uint8_t *const dict, const int dictSize);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FormatUtils);
static const int DICTIONARY_MINIMUM_SIZE;
- static const uint32_t HEADER_VERSION_2_MAGIC_NUMBER;
- static const int HEADER_VERSION_2_MINIMUM_SIZE;
};
} // namespace latinime
#endif /* LATINIME_FORMAT_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmaped_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
index e3aabb084..6b69116eb 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/mmaped_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef LATINIME_MMAPED_BUFFER_H
-#define LATINIME_MMAPED_BUFFER_H
+#ifndef LATINIME_MMAPPED_BUFFER_H
+#define LATINIME_MMAPPED_BUFFER_H
#include <cerrno>
#include <fcntl.h>
@@ -27,39 +27,40 @@
namespace latinime {
-class MmapedBuffer {
+class MmappedBuffer {
public:
- static MmapedBuffer* openBuffer(const char *const path, const int pathLength,
- const int bufOffset, const int size, const bool isUpdatable) {
+ static MmappedBuffer* openBuffer(const char *const path, const int bufferOffset,
+ const int bufferSize, const bool isUpdatable) {
const int openMode = isUpdatable ? O_RDWR : O_RDONLY;
- const int fd = open(path, openMode);
- if (fd < 0) {
+ const int mmapFd = open(path, openMode);
+ if (mmapFd < 0) {
AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno);
return 0;
}
const int pagesize = getpagesize();
- const int offset = bufOffset % pagesize;
- int adjOffset = bufOffset - offset;
- int adjSize = size + offset;
+ const int offset = bufferOffset % pagesize;
+ int alignedOffset = bufferOffset - offset;
+ int alignedSize = bufferSize + offset;
const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ;
- void *const mmapedBuffer = mmap(0, adjSize, protMode, MAP_PRIVATE, fd, adjOffset);
- if (mmapedBuffer == MAP_FAILED) {
+ void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd,
+ alignedOffset);
+ if (mmappedBuffer == MAP_FAILED) {
AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno);
- close(fd);
+ close(mmapFd);
return 0;
}
- uint8_t *const buffer = static_cast<uint8_t *>(mmapedBuffer) + bufOffset;
+ uint8_t *const buffer = static_cast<uint8_t *>(mmappedBuffer) + offset;
if (!buffer) {
AKLOGE("DICT: buffer is null");
- close(fd);
+ close(mmapFd);
return 0;
}
- return new MmapedBuffer(buffer, adjSize, fd, adjOffset, isUpdatable);
+ return new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, mmapFd,
+ isUpdatable);
}
- ~MmapedBuffer() {
- int ret = munmap(static_cast<void *>(mBuffer - mBufferOffset),
- mBufferSize + mBufferOffset);
+ ~MmappedBuffer() {
+ int ret = munmap(mMmappedBuffer, mAlignedSize);
if (ret != 0) {
AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno);
}
@@ -82,18 +83,20 @@ class MmapedBuffer {
}
private:
- AK_FORCE_INLINE MmapedBuffer(uint8_t *const buffer, const int bufferSize, const int mmapFd,
- const int bufferOffset, const bool isUpdatable)
- : mBuffer(buffer), mBufferSize(bufferSize), mMmapFd(mmapFd),
- mBufferOffset(bufferOffset), mIsUpdatable(isUpdatable) {}
+ AK_FORCE_INLINE MmappedBuffer(uint8_t *const buffer, const int bufferSize,
+ void *const mmappedBuffer, const int alignedSize, const int mmapFd,
+ const bool isUpdatable)
+ : mBuffer(buffer), mBufferSize(bufferSize), mMmappedBuffer(mmappedBuffer),
+ mAlignedSize(alignedSize), mMmapFd(mmapFd), mIsUpdatable(isUpdatable) {}
- DISALLOW_IMPLICIT_CONSTRUCTORS(MmapedBuffer);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MmappedBuffer);
uint8_t *const mBuffer;
const int mBufferSize;
+ void *const mMmappedBuffer;
+ const int mAlignedSize;
const int mMmapFd;
- const int mBufferOffset;
const bool mIsUpdatable;
};
}
-#endif /* LATINIME_MMAPED_BUFFER_H */
+#endif /* LATINIME_MMAPPED_BUFFER_H */
diff --git a/native/jni/src/suggest/core/dictionary/probability_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h
index 219213574..21fe355b8 100644
--- a/native/jni/src/suggest/core/dictionary/probability_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/probability_utils.h
@@ -41,7 +41,7 @@ class ProbabilityUtils {
// the unigram probability to be the median value of the 17th step from the top. A value of
// 0 for the bigram probability represents the middle of the 16th step from the top,
// while a value of 15 represents the middle of the top step.
- // See makedict.BinaryDictDecoder for details.
+ // See makedict.BinaryDictEncoder#makeBigramFlags for details.
const float stepSize = static_cast<float>(MAX_PROBABILITY - unigramProbability)
/ (1.5f + MAX_BIGRAM_ENCODED_PROBABILITY);
return unigramProbability
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
index b6aa85896..9f0a331e3 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -74,7 +74,8 @@ class TypingWeighting : public Weighting {
// Note: min() required since length can be MAX_POINT_TO_KEY_LENGTH for characters not on
// the keyboard (like accented letters)
const float normalizedSquaredLength = traverseSession->getProximityInfoState(0)
- ->getPointToKeyLength(pointIndex, dicNode->getNodeCodePoint());
+ ->getPointToKeyLength(pointIndex,
+ CharUtils::toBaseLowerCase(dicNode->getNodeCodePoint()));
const float normalizedDistance = TouchPositionCorrectionUtils::getSweetSpotFactor(
traverseSession->isTouchPositionCorrectionEnabled(), normalizedSquaredLength);
const float weightedDistance = ScoringParams::DISTANCE_WEIGHT_LENGTH * normalizedDistance;
@@ -113,10 +114,10 @@ class TypingWeighting : public Weighting {
const int16_t parentPointIndex = parentDicNode->getInputIndex(0);
const int prevCodePoint = parentDicNode->getNodeCodePoint();
const float distance1 = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
- parentPointIndex + 1, prevCodePoint);
+ parentPointIndex + 1, CharUtils::toBaseLowerCase(prevCodePoint));
const int codePoint = dicNode->getNodeCodePoint();
const float distance2 = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
- parentPointIndex, codePoint);
+ parentPointIndex, CharUtils::toBaseLowerCase(codePoint));
const float distance = distance1 + distance2;
const float weightedLengthDistance =
distance * ScoringParams::DISTANCE_WEIGHT_LENGTH;
@@ -133,7 +134,7 @@ class TypingWeighting : public Weighting {
const bool existsAdjacentProximityChars = traverseSession->getProximityInfoState(0)
->existsAdjacentProximityChars(insertedPointIndex);
const float dist = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
- insertedPointIndex + 1, dicNode->getNodeCodePoint());
+ insertedPointIndex + 1, CharUtils::toBaseLowerCase(dicNode->getNodeCodePoint()));
const float weightedDistance = dist * ScoringParams::DISTANCE_WEIGHT_LENGTH;
const bool singleChar = dicNode->getNodeCodePointCount() == 1;
float cost = (singleChar ? ScoringParams::INSERTION_COST_FIRST_CHAR : 0.0f);
diff --git a/native/jni/src/utils/autocorrection_threshold_utils.cpp b/native/jni/src/utils/autocorrection_threshold_utils.cpp
index 3406e0f8e..1f8ee0814 100644
--- a/native/jni/src/utils/autocorrection_threshold_utils.cpp
+++ b/native/jni/src/utils/autocorrection_threshold_utils.cpp
@@ -83,9 +83,12 @@ const int AutocorrectionThresholdUtils::FULL_WORD_MULTIPLIER = 2;
return 0.0f;
}
+ if (score <= 0 || distance >= afterLength) {
+ // normalizedScore must be 0.0f (the minimum value) if the score is less than or equal to 0,
+ // or if the edit distance is larger than or equal to afterLength.
+ return 0.0f;
+ }
// add a weight based on edit distance.
- // distance <= max(afterLength, beforeLength) == afterLength,
- // so, 0 <= distance / afterLength <= 1
const float weight = 1.0f - static_cast<float>(distance) / static_cast<float>(afterLength);
// TODO: Revise the following logic thoroughly by referring to...
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index db3997651..6e3e37add 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -120,6 +120,11 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
}
@Override
+ public void setEmojiKeyboard() {
+ // Just ignore.
+ }
+
+ @Override
public void requestUpdatingShiftState() {
mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
}
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
new file mode 100644
index 000000000..7ed3ee180
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Pair;
+
+import com.android.inputmethod.latin.makedict.CodePointUtils;
+import com.android.inputmethod.latin.makedict.FormatSpec;
+
+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.Random;
+
+@LargeTest
+public class BinaryDictionaryTests extends AndroidTestCase {
+ private static final String TEST_DICT_FILE_EXTENSION = ".testDict";
+ private static final String TEST_LOCALE = "test";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private File createEmptyDictionaryAndGetFile(final String filename) throws IOException {
+ final File file = File.createTempFile(filename, TEST_DICT_FILE_EXTENSION,
+ getContext().getCacheDir());
+ Map<String, String> attributeMap = new HashMap<String, String>();
+ attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE,
+ FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE);
+ if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(),
+ 3 /* dictVersion */, attributeMap)) {
+ return file;
+ } else {
+ throw new IOException("Empty dictionary cannot be created.");
+ }
+ }
+
+ public void testIsValidDictionary() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ assertTrue("binaryDictionary must be valid for existing valid dictionary file.",
+ binaryDictionary.isValidDictionary());
+ binaryDictionary.close();
+ assertFalse("binaryDictionary must be invalid after closing.",
+ binaryDictionary.isValidDictionary());
+ dictFile.delete();
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), 0 /* offset */,
+ dictFile.length(), true /* useFullEditDistance */, Locale.getDefault(),
+ TEST_LOCALE, true /* isUpdatable */);
+ assertFalse("binaryDictionary must be invalid for not existing dictionary file.",
+ binaryDictionary.isValidDictionary());
+ binaryDictionary.close();
+ }
+
+ public void testAddUnigramWord() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ final int probability = 100;
+ binaryDictionary.addUnigramWord("aaa", probability);
+ // Reallocate and create.
+ binaryDictionary.addUnigramWord("aab", probability);
+ // Insert into children.
+ binaryDictionary.addUnigramWord("aac", probability);
+ // Make terminal.
+ binaryDictionary.addUnigramWord("aa", probability);
+ // Create children.
+ binaryDictionary.addUnigramWord("aaaa", probability);
+ // Reallocate and make termianl.
+ binaryDictionary.addUnigramWord("a", probability);
+
+ final int updatedProbability = 200;
+ // Update.
+ binaryDictionary.addUnigramWord("aaa", updatedProbability);
+
+ assertEquals(probability, binaryDictionary.getFrequency("aab"));
+ assertEquals(probability, binaryDictionary.getFrequency("aac"));
+ assertEquals(probability, binaryDictionary.getFrequency("aa"));
+ assertEquals(probability, binaryDictionary.getFrequency("aaaa"));
+ assertEquals(probability, binaryDictionary.getFrequency("a"));
+ assertEquals(updatedProbability, binaryDictionary.getFrequency("aaa"));
+
+ dictFile.delete();
+ }
+
+ public void testRandomlyAddUnigramWord() {
+ final int wordCount = 1000;
+ final int codePointSetSize = 50;
+ final int seed = 123456789;
+
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ final HashMap<String, Integer> probabilityMap = new HashMap<String, Integer>();
+ // Test a word that isn't contained within the dictionary.
+ final Random random = new Random(seed);
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
+ for (int i = 0; i < wordCount; ++i) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ probabilityMap.put(word, random.nextInt(0xFF));
+ }
+ for (String word : probabilityMap.keySet()) {
+ binaryDictionary.addUnigramWord(word, probabilityMap.get(word));
+ }
+ for (String word : probabilityMap.keySet()) {
+ assertEquals(word, (int)probabilityMap.get(word), binaryDictionary.getFrequency(word));
+ }
+ dictFile.delete();
+ }
+
+ public void testAddBigramWords() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ final int unigramProbability = 100;
+ final int bigramProbability = 10;
+ final int updatedBigramProbability = 15;
+ binaryDictionary.addUnigramWord("aaa", unigramProbability);
+ binaryDictionary.addUnigramWord("abb", unigramProbability);
+ binaryDictionary.addUnigramWord("bcc", unigramProbability);
+ binaryDictionary.addBigramWords("aaa", "abb", bigramProbability);
+ binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "aaa", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "bcc", bigramProbability);
+
+ final int probability = binaryDictionary.calculateProbability(unigramProbability,
+ bigramProbability);
+ assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb"));
+ assertEquals(true, binaryDictionary.isValidBigram("aaa", "bcc"));
+ assertEquals(true, binaryDictionary.isValidBigram("abb", "aaa"));
+ assertEquals(true, binaryDictionary.isValidBigram("abb", "bcc"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("aaa", "abb"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("aaa", "bcc"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("abb", "aaa"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("abb", "bcc"));
+
+ binaryDictionary.addBigramWords("aaa", "abb", updatedBigramProbability);
+ final int updatedProbability = binaryDictionary.calculateProbability(unigramProbability,
+ updatedBigramProbability);
+ assertEquals(updatedProbability, binaryDictionary.getBigramProbability("aaa", "abb"));
+
+ assertEquals(false, binaryDictionary.isValidBigram("bcc", "aaa"));
+ assertEquals(false, binaryDictionary.isValidBigram("bcc", "bbc"));
+ assertEquals(false, binaryDictionary.isValidBigram("aaa", "aaa"));
+ assertEquals(Dictionary.NOT_A_PROBABILITY,
+ binaryDictionary.getBigramProbability("bcc", "aaa"));
+ assertEquals(Dictionary.NOT_A_PROBABILITY,
+ binaryDictionary.getBigramProbability("bcc", "bbc"));
+ assertEquals(Dictionary.NOT_A_PROBABILITY,
+ binaryDictionary.getBigramProbability("aaa", "aaa"));
+
+ // Testing bigram link.
+ binaryDictionary.addUnigramWord("abcde", unigramProbability);
+ binaryDictionary.addUnigramWord("fghij", unigramProbability);
+ binaryDictionary.addBigramWords("abcde", "fghij", bigramProbability);
+ binaryDictionary.addUnigramWord("fgh", unigramProbability);
+ binaryDictionary.addUnigramWord("abc", unigramProbability);
+ binaryDictionary.addUnigramWord("f", unigramProbability);
+ assertEquals(probability, binaryDictionary.getBigramProbability("abcde", "fghij"));
+ assertEquals(Dictionary.NOT_A_PROBABILITY,
+ binaryDictionary.getBigramProbability("abcde", "fgh"));
+ binaryDictionary.addBigramWords("abcde", "fghij", updatedBigramProbability);
+ assertEquals(updatedProbability, binaryDictionary.getBigramProbability("abcde", "fghij"));
+
+ dictFile.delete();
+ }
+
+ public void testRandomlyAddBigramWords() {
+ final int wordCount = 100;
+ final int bigramCount = 1000;
+ final int codePointSetSize = 50;
+ final int seed = 11111;
+
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ final ArrayList<String> words = new ArrayList<String>();
+ // Test a word that isn't contained within the dictionary.
+ final Random random = new Random(seed);
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
+ final int[] unigramProbabilities = new int[wordCount];
+ for (int i = 0; i < wordCount; ++i) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ words.add(word);
+ final int unigramProbability = random.nextInt(0xFF);
+ unigramProbabilities[i] = unigramProbability;
+ binaryDictionary.addUnigramWord(word, unigramProbability);
+ }
+
+ final int[][] probabilities = new int[wordCount][wordCount];
+
+ for (int i = 0; i < wordCount; ++i) {
+ for (int j = 0; j < wordCount; ++j) {
+ probabilities[i][j] = Dictionary.NOT_A_PROBABILITY;
+ }
+ }
+
+ for (int i = 0; i < bigramCount; i++) {
+ final int word0Index = random.nextInt(wordCount);
+ final int word1Index = random.nextInt(wordCount);
+ final String word0 = words.get(word0Index);
+ final String word1 = words.get(word1Index);
+ final int bigramProbability = random.nextInt(0xF);
+ probabilities[word0Index][word1Index] = binaryDictionary.calculateProbability(
+ unigramProbabilities[word1Index], bigramProbability);
+ binaryDictionary.addBigramWords(word0, word1, bigramProbability);
+ }
+
+ for (int i = 0; i < words.size(); i++) {
+ for (int j = 0; j < words.size(); j++) {
+ assertEquals(probabilities[i][j],
+ binaryDictionary.getBigramProbability(words.get(i), words.get(j)));
+ }
+ }
+
+ dictFile.delete();
+ }
+
+ public void testRemoveBigramWords() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ final int unigramProbability = 100;
+ final int bigramProbability = 10;
+ binaryDictionary.addUnigramWord("aaa", unigramProbability);
+ binaryDictionary.addUnigramWord("abb", unigramProbability);
+ binaryDictionary.addUnigramWord("bcc", unigramProbability);
+ binaryDictionary.addBigramWords("aaa", "abb", bigramProbability);
+ binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "aaa", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "bcc", bigramProbability);
+
+ assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb"));
+ assertEquals(true, binaryDictionary.isValidBigram("aaa", "bcc"));
+ assertEquals(true, binaryDictionary.isValidBigram("abb", "aaa"));
+ assertEquals(true, binaryDictionary.isValidBigram("abb", "bcc"));
+
+ binaryDictionary.removeBigramWords("aaa", "abb");
+ assertEquals(false, binaryDictionary.isValidBigram("aaa", "abb"));
+ binaryDictionary.addBigramWords("aaa", "abb", bigramProbability);
+ assertEquals(true, binaryDictionary.isValidBigram("aaa", "abb"));
+
+
+ binaryDictionary.removeBigramWords("aaa", "bcc");
+ assertEquals(false, binaryDictionary.isValidBigram("aaa", "bcc"));
+ binaryDictionary.removeBigramWords("abb", "aaa");
+ assertEquals(false, binaryDictionary.isValidBigram("abb", "aaa"));
+ binaryDictionary.removeBigramWords("abb", "bcc");
+ assertEquals(false, binaryDictionary.isValidBigram("abb", "bcc"));
+
+ binaryDictionary.removeBigramWords("aaa", "abb");
+ // Test remove non-existing bigram operation.
+ binaryDictionary.removeBigramWords("aaa", "abb");
+ binaryDictionary.removeBigramWords("bcc", "aaa");
+
+ dictFile.delete();
+ }
+
+ public void testFlushDictionary() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ final int probability = 100;
+ binaryDictionary.addUnigramWord("aaa", probability);
+ binaryDictionary.addUnigramWord("abcd", probability);
+ // Close without flushing.
+ binaryDictionary.close();
+
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("aaa"));
+ assertEquals(Dictionary.NOT_A_PROBABILITY, binaryDictionary.getFrequency("abcd"));
+
+ binaryDictionary.addUnigramWord("aaa", probability);
+ binaryDictionary.addUnigramWord("abcd", probability);
+ binaryDictionary.flush();
+ binaryDictionary.close();
+
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ assertEquals(probability, binaryDictionary.getFrequency("aaa"));
+ assertEquals(probability, binaryDictionary.getFrequency("abcd"));
+ binaryDictionary.addUnigramWord("bcde", probability);
+ binaryDictionary.flush();
+ binaryDictionary.close();
+
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ assertEquals(probability, binaryDictionary.getFrequency("bcde"));
+ binaryDictionary.close();
+
+ dictFile.delete();
+ }
+
+ public void testFlushWithGCDictionary() {
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ final int unigramProbability = 100;
+ final int bigramProbability = 10;
+ binaryDictionary.addUnigramWord("aaa", unigramProbability);
+ binaryDictionary.addUnigramWord("abb", unigramProbability);
+ binaryDictionary.addUnigramWord("bcc", unigramProbability);
+ binaryDictionary.addBigramWords("aaa", "abb", bigramProbability);
+ binaryDictionary.addBigramWords("aaa", "bcc", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "aaa", bigramProbability);
+ binaryDictionary.addBigramWords("abb", "bcc", bigramProbability);
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ final int probability = binaryDictionary.calculateProbability(unigramProbability,
+ bigramProbability);
+ assertEquals(unigramProbability, binaryDictionary.getFrequency("aaa"));
+ assertEquals(unigramProbability, binaryDictionary.getFrequency("abb"));
+ assertEquals(unigramProbability, binaryDictionary.getFrequency("bcc"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("aaa", "abb"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("aaa", "bcc"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("abb", "aaa"));
+ assertEquals(probability, binaryDictionary.getBigramProbability("abb", "bcc"));
+ assertEquals(false, binaryDictionary.isValidBigram("bcc", "aaa"));
+ assertEquals(false, binaryDictionary.isValidBigram("bcc", "bbc"));
+ assertEquals(false, binaryDictionary.isValidBigram("aaa", "aaa"));
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+
+ dictFile.delete();
+ }
+
+ // TODO: Evaluate performance of GC
+ public void testAddBigramWordsAndFlashWithGC() {
+ final int wordCount = 100;
+ final int bigramCount = 1000;
+ final int codePointSetSize = 30;
+ // TODO: Use various seeds such as a current timestamp to make this test more random.
+ final int seed = 314159265;
+
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ final ArrayList<String> words = new ArrayList<String>();
+ // Test a word that isn't contained within the dictionary.
+ final Random random = new Random(seed);
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
+ final int[] unigramProbabilities = new int[wordCount];
+ for (int i = 0; i < wordCount; ++i) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ words.add(word);
+ final int unigramProbability = random.nextInt(0xFF);
+ unigramProbabilities[i] = unigramProbability;
+ binaryDictionary.addUnigramWord(word, unigramProbability);
+ }
+
+ final int[][] probabilities = new int[wordCount][wordCount];
+
+ for (int i = 0; i < wordCount; ++i) {
+ for (int j = 0; j < wordCount; ++j) {
+ probabilities[i][j] = Dictionary.NOT_A_PROBABILITY;
+ }
+ }
+
+ for (int i = 0; i < bigramCount; i++) {
+ final int word0Index = random.nextInt(wordCount);
+ final int word1Index = random.nextInt(wordCount);
+ final String word0 = words.get(word0Index);
+ final String word1 = words.get(word1Index);
+ final int bigramProbability = random.nextInt(0xF);
+ probabilities[word0Index][word1Index] = binaryDictionary.calculateProbability(
+ unigramProbabilities[word1Index], bigramProbability);
+ binaryDictionary.addBigramWords(word0, word1, bigramProbability);
+ }
+
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+
+ for (int i = 0; i < words.size(); i++) {
+ for (int j = 0; j < words.size(); j++) {
+ assertEquals(probabilities[i][j],
+ binaryDictionary.getBigramProbability(words.get(i), words.get(j)));
+ }
+ }
+ dictFile.delete();
+ }
+
+ public void testRandomOperetionsAndFlashWithGC() {
+ final int flashWithGCIterationCount = 50;
+ final int operationCountInEachIteration = 200;
+ final int initialUnigramCount = 100;
+ final float addUnigramProb = 0.5f;
+ final float addBigramProb = 0.8f;
+ final float removeBigramProb = 0.2f;
+ final int codePointSetSize = 30;
+ final int seed = 141421356;
+
+ final Random random = new Random(seed);
+
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+
+ BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ final ArrayList<String> words = new ArrayList<String>();
+ final ArrayList<Pair<String, String>> bigramWords = new ArrayList<Pair<String,String>>();
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
+ final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>();
+ final HashMap<Pair<String, String>, Integer> bigramProbabilities =
+ new HashMap<Pair<String, String>, Integer>();
+ for (int i = 0; i < initialUnigramCount; ++i) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ words.add(word);
+ final int unigramProbability = random.nextInt(0xFF);
+ unigramProbabilities.put(word, unigramProbability);
+ binaryDictionary.addUnigramWord(word, unigramProbability);
+ }
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+
+ for (int gcCount = 0; gcCount < flashWithGCIterationCount; gcCount++) {
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ for (int opCount = 0; opCount < operationCountInEachIteration; opCount++) {
+ // Add unigram.
+ if (random.nextFloat() < addUnigramProb) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ words.add(word);
+ final int unigramProbability = random.nextInt(0xFF);
+ unigramProbabilities.put(word, unigramProbability);
+ binaryDictionary.addUnigramWord(word, unigramProbability);
+ }
+ // Add bigram.
+ if (random.nextFloat() < addBigramProb && words.size() > 2) {
+ final int word0Index = random.nextInt(words.size());
+ int word1Index = random.nextInt(words.size() - 1);
+ if (word0Index <= word1Index) {
+ word1Index++;
+ }
+ final String word0 = words.get(word0Index);
+ final String word1 = words.get(word1Index);
+ final int bigramProbability = random.nextInt(0xF);
+ final Pair<String, String> bigram = new Pair<String, String>(word0, word1);
+ bigramWords.add(bigram);
+ bigramProbabilities.put(bigram, bigramProbability);
+ binaryDictionary.addBigramWords(word0, word1, bigramProbability);
+ }
+ // Remove bigram.
+ if (random.nextFloat() < removeBigramProb && !bigramWords.isEmpty()) {
+ final int bigramIndex = random.nextInt(bigramWords.size());
+ final Pair<String, String> bigram = bigramWords.get(bigramIndex);
+ bigramWords.remove(bigramIndex);
+ bigramProbabilities.remove(bigram);
+ binaryDictionary.removeBigramWords(bigram.first, bigram.second);
+ }
+ }
+
+ // Test whether the all unigram operations are collectlly handled.
+ for (int i = 0; i < words.size(); i++) {
+ final String word = words.get(i);
+ final int unigramProbability = unigramProbabilities.get(word);
+ assertEquals(word, unigramProbability, binaryDictionary.getFrequency(word));
+ }
+ // Test whether the all bigram operations are collectlly handled.
+ for (int i = 0; i < bigramWords.size(); i++) {
+ final Pair<String, String> bigram = bigramWords.get(i);
+ final int unigramProbability = unigramProbabilities.get(bigram.second);
+ final int probability;
+ if (bigramProbabilities.containsKey(bigram)) {
+ final int bigramProbability = bigramProbabilities.get(bigram);
+ probability = binaryDictionary.calculateProbability(unigramProbability,
+ bigramProbability);
+ } else {
+ probability = Dictionary.NOT_A_PROBABILITY;
+ }
+ assertEquals(probability,
+ binaryDictionary.getBigramProbability(bigram.first, bigram.second));
+ }
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+ }
+
+ dictFile.delete();
+ }
+
+ public void testAddManyUnigramsAndFlushWithGC() {
+ final int flashWithGCIterationCount = 3;
+ final int codePointSetSize = 50;
+ final int seed = 22360679;
+
+ final Random random = new Random(seed);
+
+ File dictFile = null;
+ try {
+ dictFile = createEmptyDictionaryAndGetFile("TestBinaryDictionary");
+ } catch (IOException e) {
+ fail("IOException while writing an initial dictionary : " + e);
+ }
+
+ final ArrayList<String> words = new ArrayList<String>();
+ final HashMap<String, Integer> unigramProbabilities = new HashMap<String, Integer>();
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
+
+ BinaryDictionary binaryDictionary;
+ for (int i = 0; i < flashWithGCIterationCount; i++) {
+ binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(),
+ 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
+ Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
+ while(!binaryDictionary.needsToRunGC()) {
+ final String word = CodePointUtils.generateWord(random, codePointSet);
+ words.add(word);
+ final int unigramProbability = random.nextInt(0xFF);
+ unigramProbabilities.put(word, unigramProbability);
+ binaryDictionary.addUnigramWord(word, unigramProbability);
+ }
+
+ for (int j = 0; j < words.size(); j++) {
+ final String word = words.get(j);
+ final int unigramProbability = unigramProbabilities.get(word);
+ assertEquals(word, unigramProbability, binaryDictionary.getFrequency(word));
+ }
+
+ binaryDictionary.flushWithGC();
+ binaryDictionary.close();
+ }
+
+ dictFile.delete();
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java b/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java
new file mode 100644
index 000000000..ecf3af736
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/ExpandableDictionaryTests.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit test for ExpandableDictionary
+ */
+@SmallTest
+public class ExpandableDictionaryTests extends AndroidTestCase {
+
+ private final static int UNIGRAM_FREQ = 50;
+
+ public void testAddWordAndGetWordFrequency() {
+ final ExpandableDictionary dict = new ExpandableDictionary(Dictionary.TYPE_USER);
+
+ // Add words
+ dict.addWord("abcde", "abcde", UNIGRAM_FREQ);
+ dict.addWord("abcef", null, UNIGRAM_FREQ + 1);
+
+ // Check words
+ assertFalse(dict.isValidWord("abcde"));
+ assertEquals(UNIGRAM_FREQ, dict.getWordFrequency("abcde"));
+ assertTrue(dict.isValidWord("abcef"));
+ assertEquals(UNIGRAM_FREQ+1, dict.getWordFrequency("abcef"));
+
+ dict.addWord("abc", null, UNIGRAM_FREQ + 2);
+ assertTrue(dict.isValidWord("abc"));
+ assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc"));
+
+ // Add existing word with lower frequency
+ dict.addWord("abc", null, UNIGRAM_FREQ);
+ assertEquals(UNIGRAM_FREQ + 2, dict.getWordFrequency("abc"));
+
+ // Add existing word with higher frequency
+ dict.addWord("abc", null, UNIGRAM_FREQ + 3);
+ assertEquals(UNIGRAM_FREQ + 3, dict.getWordFrequency("abc"));
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
index 65dfd2dde..cadd0f8f3 100644
--- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
@@ -20,7 +20,7 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import java.util.HashMap;
@@ -30,21 +30,21 @@ import java.util.HashMap;
@SmallTest
public class FusionDictionaryTests extends AndroidTestCase {
public void testFindWordInTree() {
- FusionDictionary dict = new FusionDictionary(new Node(),
+ FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false));
dict.add("abc", 10, null, false /* isNotAWord */);
- assertNull(FusionDictionary.findWordInTree(dict.mRoot, "aaa"));
- assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "abc"));
+ assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
+ assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc"));
dict.add("aa", 10, null, false /* isNotAWord */);
- assertNull(FusionDictionary.findWordInTree(dict.mRoot, "aaa"));
- assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "aa"));
+ assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
+ assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa"));
dict.add("babcd", 10, null, false /* isNotAWord */);
dict.add("bacde", 10, null, false /* isNotAWord */);
- assertNull(FusionDictionary.findWordInTree(dict.mRoot, "ba"));
- assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "babcd"));
- assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "bacde"));
+ assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba"));
+ assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd"));
+ assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "bacde"));
}
}
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index d27a7a903..cc2569f5e 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.test.suitebuilder.annotation.LargeTest;
+import android.view.inputmethod.BaseInputConnection;
@LargeTest
public class InputLogicTests extends InputTestsBase {
@@ -133,6 +134,13 @@ public class InputLogicTests extends InputTestsBase {
assertEquals("simple auto-correct", EXPECTED_RESULT, mEditText.getText().toString());
}
+ public void testAutoCorrectWithQuote() {
+ final String STRING_TO_TYPE = "didn' ";
+ final String EXPECTED_RESULT = "didn't ";
+ type(STRING_TO_TYPE);
+ assertEquals("auto-correct with quote", EXPECTED_RESULT, mEditText.getText().toString());
+ }
+
public void testAutoCorrectWithPeriod() {
final String STRING_TO_TYPE = "tgis.";
final String EXPECTED_RESULT = "this.";
@@ -290,5 +298,47 @@ public class InputLogicTests extends InputTestsBase {
}
assertEquals("delete whole composing word", "", mEditText.getText().toString());
}
+
+ public void testResumeSuggestionOnBackspace() {
+ final String WORD_TO_TYPE = "and this ";
+ type(WORD_TO_TYPE);
+ assertEquals("resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ type(Constants.CODE_DELETE);
+ assertEquals("resume suggestion on backspace", 4,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("resume suggestion on backspace", 8,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ }
+
+ private void helperTestComposing(final String wordToType, final boolean shouldBeComposing) {
+ mEditText.setText("");
+ type(wordToType);
+ assertEquals("start composing inside text", shouldBeComposing ? 0 : -1,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("start composing inside text", shouldBeComposing ? wordToType.length() : -1,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ }
+
+ public void testStartComposing() {
+ // Should start composing on a letter
+ helperTestComposing("a", true);
+ type(" "); // To reset the composing state
+ // Should not start composing on quote
+ helperTestComposing("'", false);
+ type(" ");
+ helperTestComposing("'-", false);
+ type(" ");
+ // Should not start composing on dash
+ helperTestComposing("-", false);
+ type(" ");
+ helperTestComposing("-'", false);
+ type(" ");
+ helperTestComposing("a-", true);
+ type(" ");
+ helperTestComposing("a'", true);
+ }
// TODO: Add some tests for non-BMP characters
}
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
new file mode 100644
index 000000000..0f0ebafb9
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.inputmethod.BaseInputConnection;
+
+import com.android.inputmethod.latin.suggestions.SuggestionStripView;
+
+@LargeTest
+public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase {
+ public void testAutoCorrectForLanguageWithoutSpaces() {
+ final String STRING_TO_TYPE = "tgis is";
+ final String EXPECTED_RESULT = "thisis";
+ changeKeyboardLocaleAndDictLocale("th", "en_US");
+ type(STRING_TO_TYPE);
+ assertEquals("simple auto-correct for language without spaces", EXPECTED_RESULT,
+ mEditText.getText().toString());
+ }
+
+ public void testRevertAutoCorrectForLanguageWithoutSpaces() {
+ final String STRING_TO_TYPE = "tgis ";
+ final String EXPECTED_INTERMEDIATE_RESULT = "this";
+ final String EXPECTED_FINAL_RESULT = "tgis";
+ changeKeyboardLocaleAndDictLocale("th", "en_US");
+ type(STRING_TO_TYPE);
+ assertEquals("simple auto-correct for language without spaces",
+ EXPECTED_INTERMEDIATE_RESULT, mEditText.getText().toString());
+ type(Constants.CODE_DELETE);
+ assertEquals("simple auto-correct for language without spaces",
+ EXPECTED_FINAL_RESULT, mEditText.getText().toString());
+ // Check we are back to composing the word
+ assertEquals("don't resume suggestion on backspace", 0,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("don't resume suggestion on backspace", 4,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ }
+
+ public void testDontResumeSuggestionOnBackspace() {
+ final String WORD_TO_TYPE = "and this ";
+ changeKeyboardLocaleAndDictLocale("th", "en_US");
+ type(WORD_TO_TYPE);
+ assertEquals("don't resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("don't resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ type(" ");
+ type(Constants.CODE_DELETE);
+ assertEquals("don't resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("don't resume suggestion on backspace", -1,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ }
+
+ public void testStartComposingInsideText() {
+ final String WORD_TO_TYPE = "abcdefgh ";
+ final int typedLength = WORD_TO_TYPE.length() - 1; // -1 because space gets eaten
+ final int CURSOR_POS = 4;
+ changeKeyboardLocaleAndDictLocale("th", "en_US");
+ type(WORD_TO_TYPE);
+ mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
+ mInputConnection.setSelection(CURSOR_POS, CURSOR_POS);
+ mLatinIME.onUpdateSelection(typedLength, typedLength,
+ CURSOR_POS, CURSOR_POS, -1, -1);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ runMessages();
+ assertEquals("start composing inside text", -1,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("start composing inside text", -1,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ type("xxxx");
+ assertEquals("start composing inside text", 4,
+ BaseInputConnection.getComposingSpanStart(mEditText.getText()));
+ assertEquals("start composing inside text", 8,
+ BaseInputConnection.getComposingSpanEnd(mEditText.getText()));
+ }
+
+ public void testPredictions() {
+ final String WORD_TO_TYPE = "Barack ";
+ changeKeyboardLocaleAndDictLocale("th", "en_US");
+ type(WORD_TO_TYPE);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ runMessages();
+ // Make sure there is no space
+ assertEquals("predictions in lang without spaces", "Barack",
+ mEditText.getText().toString());
+ // Test the first prediction is displayed
+ assertEquals("predictions in lang without spaces", "Obama",
+ mLatinIME.getFirstSuggestedWord());
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
index f0b6acc75..5095f9606 100644
--- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
@@ -244,4 +244,20 @@ public class InputPointersTests extends AndroidTestCase {
expecteds[i + expectedPos], actuals[i + actualPos]);
}
}
+
+ public void testShift() {
+ final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
+ final int limit = 100;
+ final int shiftAmount = 20;
+ for (int i = 0; i < limit; i++) {
+ src.addPointer(i, i * 2, i * 3, i * 4);
+ }
+ src.shift(shiftAmount);
+ for (int i = 0; i < limit - shiftAmount; ++i) {
+ assertEquals("xCoordinates at " + i, i + shiftAmount, src.getXCoordinates()[i]);
+ assertEquals("yCoordinates at " + i, (i + shiftAmount) * 2, src.getYCoordinates()[i]);
+ assertEquals("pointerIds at " + i, (i + shiftAmount) * 3, src.getPointerIds()[i]);
+ assertEquals("times at " + i, (i + shiftAmount) * 4, src.getTimes()[i]);
+ }
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index cc3e0d74d..234bb1b31 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -44,8 +44,10 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
private static final String PREF_DEBUG_MODE = "debug_mode";
- // The message that sets the underline is posted with a 100 ms delay
+ // The message that sets the underline is posted with a 200 ms delay
protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 200;
+ // The message that sets predictions is posted with a 200 ms delay
+ protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200;
protected LatinIME mLatinIME;
protected Keyboard mKeyboard;
@@ -233,9 +235,6 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
--remainingAttempts;
}
}
- if (!mLatinIME.hasMainDictionary()) {
- throw new RuntimeException("Can't initialize the main dictionary");
- }
}
protected void changeLanguage(final String locale) {
@@ -247,9 +246,21 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
waitForDictionaryToBeLoaded();
}
+ protected void changeKeyboardLocaleAndDictLocale(final String keyboardLocale,
+ final String dictLocale) {
+ changeLanguage(keyboardLocale);
+ if (!keyboardLocale.equals(dictLocale)) {
+ mLatinIME.replaceMainDictionaryForTest(
+ LocaleUtils.constructLocaleFromString(dictLocale));
+ }
+ waitForDictionaryToBeLoaded();
+ }
+
protected void pickSuggestionManually(final int index, final String suggestion) {
mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1,
- SuggestedWordInfo.KIND_CORRECTION, "main"));
+ SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
// Helper to avoid writing the try{}catch block each time
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 8d0fe014c..a594baf0b 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -34,9 +34,14 @@ public class SuggestedWordsTests extends AndroidTestCase {
final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList();
list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
- SuggestedWordInfo.KIND_TYPED, ""));
+ SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
- list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION, ""));
+ list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
+ null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
final SuggestedWords words = new SuggestedWords(
@@ -59,4 +64,37 @@ public class SuggestedWordsTests extends AndroidTestCase {
assertEquals("0", wordsWithoutTyped.getWord(0));
assertEquals(SuggestedWordInfo.KIND_CORRECTION, wordsWithoutTyped.getInfo(0).mKind);
}
+
+ // Helper for testGetTransformedWordInfo
+ private SuggestedWordInfo createWordInfo(final String s) {
+ // Use 100 as the frequency because the numerical value does not matter as
+ // long as it's > 1 and < INT_MAX.
+ return new SuggestedWordInfo(s, 100,
+ SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
+ }
+
+ // Helper for testGetTransformedWordInfo
+ private SuggestedWordInfo transformWordInfo(final String info,
+ final int trailingSingleQuotesCount) {
+ return Suggest.getTransformedSuggestedWordInfo(createWordInfo(info),
+ Locale.ENGLISH, false /* isAllUpperCase */, false /* isFirstCharCapitalized */,
+ trailingSingleQuotesCount);
+ }
+
+ public void testGetTransformedSuggestedWordInfo() {
+ SuggestedWordInfo result = transformWordInfo("word", 0);
+ assertEquals(result.mWord, "word");
+ result = transformWordInfo("word", 1);
+ assertEquals(result.mWord, "word'");
+ result = transformWordInfo("word", 3);
+ assertEquals(result.mWord, "word'''");
+ result = transformWordInfo("didn't", 0);
+ assertEquals(result.mWord, "didn't");
+ result = transformWordInfo("didn't", 1);
+ assertEquals(result.mWord, "didn't");
+ result = transformWordInfo("didn't", 3);
+ assertEquals(result.mWord, "didn't''");
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 9664779f0..a4d94262f 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -22,29 +22,32 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import android.util.SparseArray;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
+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.FusionDictionary.CharGroup;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+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.ByteArrayDictBuffer;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
+import java.util.TreeMap;
/**
- * Unit tests for BinaryDictDecoder and BinaryDictEncoder.
+ * Unit tests for BinaryDictDecoderUtils and BinaryDictEncoderUtils.
*/
@LargeTest
public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
@@ -54,22 +57,31 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
private static final int UNIGRAM_FREQ = 10;
private static final int BIGRAM_FREQ = 50;
private static final int TOLERANCE_OF_BIGRAM_FREQ = 5;
+ private static final int NUM_OF_NODES_HAVING_SHORTCUTS = 50;
+ private static final int NUM_OF_SHORTCUTS = 5;
private static final int USE_BYTE_ARRAY = 1;
private static final int USE_BYTE_BUFFER = 2;
- private static final List<String> sWords = CollectionUtils.newArrayList();
+ private static final ArrayList<String> sWords = CollectionUtils.newArrayList();
private static final SparseArray<List<Integer>> sEmptyBigrams =
CollectionUtils.newSparseArray();
private static final SparseArray<List<Integer>> sStarBigrams = CollectionUtils.newSparseArray();
private static final SparseArray<List<Integer>> sChainBigrams =
CollectionUtils.newSparseArray();
+ private static final HashMap<String, List<String>> sShortcuts = CollectionUtils.newHashMap();
private static final FormatSpec.FormatOptions VERSION2 = new FormatSpec.FormatOptions(2);
private static final FormatSpec.FormatOptions VERSION3_WITHOUT_DYNAMIC_UPDATE =
new FormatSpec.FormatOptions(3, false /* supportsDynamicUpdate */);
private static final FormatSpec.FormatOptions VERSION3_WITH_DYNAMIC_UPDATE =
new FormatSpec.FormatOptions(3, true /* supportsDynamicUpdate */);
+ private static final FormatSpec.FormatOptions VERSION4_WITHOUT_DYNAMIC_UPDATE =
+ new FormatSpec.FormatOptions(4, false /* supportsDynamicUpdate */);
+ private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE =
+ new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */);
+
+ private static final String TEST_DICT_FILE_EXTENSION = ".testDict";
public BinaryDictDecoderEncoderTests() {
this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS);
@@ -80,7 +92,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
Log.e(TAG, "Testing dictionary: seed is " + seed);
final Random random = new Random(seed);
sWords.clear();
- final int[] codePointSet = generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, random);
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE,
+ random);
generateWords(maxUnigrams, random, codePointSet);
for (int i = 0; i < sWords.size(); ++i) {
@@ -94,65 +107,33 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
for (int i = 1; i < sWords.size(); ++i) {
sStarBigrams.get(0).add(i);
}
- }
-
- private int[] generateCodePointSet(final int codePointSetSize, final Random random) {
- final int[] codePointSet = new int[codePointSetSize];
- for (int i = codePointSet.length - 1; i >= 0; ) {
- final int r = Math.abs(random.nextInt());
- if (r < 0) continue;
- // Don't insert 0~0x20, but insert any other code point.
- // Code points are in the range 0~0x10FFFF.
- final int candidateCodePoint = (int)(0x20 + r % (Character.MAX_CODE_POINT - 0x20));
- // Code points between MIN_ and MAX_SURROGATE are not valid on their own.
- if (candidateCodePoint >= Character.MIN_SURROGATE
- && candidateCodePoint <= Character.MAX_SURROGATE) continue;
- codePointSet[i] = candidateCodePoint;
- --i;
- }
- return codePointSet;
- }
-
- // Utilities for test
- /**
- * Makes new buffer according to BUFFER_TYPE.
- */
- private void getBuffer(final BinaryDictReader reader, final int bufferType)
- throws FileNotFoundException, IOException {
- if (bufferType == USE_BYTE_BUFFER) {
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteBufferFactory());
- } else if (bufferType == USE_BYTE_ARRAY) {
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ sShortcuts.clear();
+ for (int i = 0; i < NUM_OF_NODES_HAVING_SHORTCUTS; ++i) {
+ final int from = Math.abs(random.nextInt()) % sWords.size();
+ sShortcuts.put(sWords.get(from), new ArrayList<String>());
+ for (int j = 0; j < NUM_OF_SHORTCUTS; ++j) {
+ final int to = Math.abs(random.nextInt()) % sWords.size();
+ sShortcuts.get(sWords.get(from)).add(sWords.get(to));
+ }
}
}
- /**
- * Generates a random word.
- */
- private String generateWord(final Random random, final int[] codePointSet) {
- StringBuilder builder = new StringBuilder();
- // 8 * 4 = 32 chars max, but we do it the following way so as to bias the random toward
- // longer words. This should be closer to natural language, and more importantly, it will
- // exercise the algorithms in dicttool much more.
- final int count = 1 + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5)
- + (Math.abs(random.nextInt()) % 5);
- while (builder.length() < count) {
- builder.appendCodePoint(codePointSet[Math.abs(random.nextInt()) % codePointSet.length]);
- }
- return builder.toString();
+ private DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) {
+ if (formatOptions.mVersion == FormatSpec.VERSION4) {
+ return new Ver4DictEncoder(getContext().getCacheDir());
+ } else if (formatOptions.mVersion == 3 || formatOptions.mVersion == 2) {
+ return new Ver3DictEncoder(file);
+ } else {
+ throw new RuntimeException("The format option has a wrong version : "
+ + formatOptions.mVersion);
+ }
}
private void generateWords(final int number, final Random random, final int[] codePointSet) {
final Set<String> wordSet = CollectionUtils.newHashSet();
while (wordSet.size() < number) {
- wordSet.add(generateWord(random, codePointSet));
+ wordSet.add(CodePointUtils.generateWord(random, codePointSet));
}
sWords.addAll(wordSet);
}
@@ -161,7 +142,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
* Adds unigrams to the dictionary.
*/
private void addUnigrams(final int number, final FusionDictionary dict,
- final List<String> words, final Map<String, List<String>> shortcutMap) {
+ final List<String> words, final HashMap<String, List<String>> shortcutMap) {
for (int i = 0; i < number; ++i) {
final String word = words.get(i);
final ArrayList<WeightedString> shortcuts = CollectionUtils.newArrayList();
@@ -200,17 +181,14 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
long now = -1, diff = -1;
try {
- final FileOutputStream out = new FileOutputStream(file);
+ final DictEncoder dictEncoder = getDictEncoder(file, formatOptions);
now = System.currentTimeMillis();
// If you need to dump the dict to a textual file, uncomment the line below and the
// function above
// dumpToCombinedFileForDebug(file, "/tmp/foo");
- BinaryDictEncoder.writeDictionaryBinary(out, dict, formatOptions);
+ dictEncoder.writeDictionary(dict, formatOptions);
diff = System.currentTimeMillis() - now;
-
- out.flush();
- out.close();
} catch (IOException e) {
Log.e(TAG, "IO exception while writing file", e);
} catch (UnsupportedFormatException e) {
@@ -221,31 +199,35 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
private void checkDictionary(final FusionDictionary dict, final List<String> words,
- final SparseArray<List<Integer>> bigrams, final Map<String, List<String>> shortcutMap) {
+ final SparseArray<List<Integer>> bigrams,
+ final HashMap<String, List<String>> shortcutMap) {
assertNotNull(dict);
// check unigram
for (final String word : words) {
- final CharGroup cg = FusionDictionary.findWordInTree(dict.mRoot, word);
- assertNotNull(cg);
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word);
+ assertNotNull(ptNode);
}
// check bigram
for (int i = 0; i < bigrams.size(); ++i) {
final int w1 = bigrams.keyAt(i);
for (final int w2 : bigrams.valueAt(i)) {
- final CharGroup cg = FusionDictionary.findWordInTree(dict.mRoot, words.get(w1));
- assertNotNull(words.get(w1) + "," + words.get(w2), cg.getBigram(words.get(w2)));
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray,
+ words.get(w1));
+ assertNotNull(words.get(w1) + "," + words.get(w2), ptNode.getBigram(words.get(w2)));
}
}
// check shortcut
if (shortcutMap != null) {
- for (final Map.Entry<String, List<String>> entry : shortcutMap.entrySet()) {
- final CharGroup group = FusionDictionary.findWordInTree(dict.mRoot, entry.getKey());
+ for (final Entry<String, List<String>> entry : shortcutMap.entrySet()) {
+ assertTrue(words.contains(entry.getKey()));
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray,
+ entry.getKey());
for (final String word : entry.getValue()) {
assertNotNull("shortcut not found: " + entry.getKey() + ", " + word,
- group.getShortcut(word));
+ ptNode.getShortcut(word));
}
}
}
@@ -259,20 +241,51 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
return result + ", supportsDynamicUpdate = " + formatOptions.mSupportsDynamicUpdate;
}
+ private DictionaryOptions getDictionaryOptions(final String id, final String version) {
+ final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>(),
+ false, false);
+ options.mAttributes.put("version", version);
+ options.mAttributes.put("dictionary", id);
+ return options;
+ }
+
+ private File setUpDictionaryFile(final String name, final String version) {
+ File file = null;
+ try {
+ file = new File(getContext().getCacheDir(), name + "." + version
+ + TEST_DICT_FILE_EXTENSION);
+ file.createNewFile();
+ } catch (IOException e) {
+ // do nothing
+ }
+ assertTrue("Failed to create the dictionary file.", file.exists());
+ return file;
+ }
+
+ private DictDecoder getDictDecoder(final File file, final int bufferType,
+ final FormatOptions formatOptions, final DictionaryOptions dictOptions) {
+ if (formatOptions.mVersion == FormatSpec.VERSION4) {
+ final FileHeader header = new FileHeader(0, dictOptions, formatOptions);
+ return FormatSpec.getDictDecoder(new File(getContext().getCacheDir(),
+ header.getId() + "." + header.getVersion()), bufferType);
+ } else {
+ return FormatSpec.getDictDecoder(file, bufferType);
+ }
+ }
// Tests for readDictionaryBinary and writeDictionaryBinary
private long timeReadingAndCheckDict(final File file, final List<String> words,
- final SparseArray<List<Integer>> bigrams, final Map<String, List<String>> shortcutMap,
- final int bufferType) {
+ final SparseArray<List<Integer>> bigrams,
+ final HashMap<String, List<String>> shortcutMap, final int bufferType,
+ final FormatOptions formatOptions, final DictionaryOptions dictOptions) {
long now, diff = -1;
- final BinaryDictReader reader = new BinaryDictReader(file);
FusionDictionary dict = null;
try {
- getBuffer(reader, bufferType);
- assertNotNull(reader.getBuffer());
+ final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions,
+ dictOptions);
now = System.currentTimeMillis();
- dict = BinaryDictDecoder.readDictionaryBinary(reader, null);
+ dict = dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
diff = System.currentTimeMillis() - now;
} catch (IOException e) {
Log.e(TAG, "IOException while reading dictionary", e);
@@ -286,25 +299,23 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
// Tests for readDictionaryBinary and writeDictionaryBinary
private String runReadAndWrite(final List<String> words,
- final SparseArray<List<Integer>> bigrams, final Map<String, List<String>> shortcuts,
+ final SparseArray<List<Integer>> bigrams, final HashMap<String, List<String>> shortcuts,
final int bufferType, final FormatSpec.FormatOptions formatOptions,
final String message) {
- File file = null;
- try {
- file = File.createTempFile("runReadAndWrite", ".dict", getContext().getCacheDir());
- } catch (IOException e) {
- Log.e(TAG, "IOException", e);
- }
- assertNotNull(file);
- final FusionDictionary dict = new FusionDictionary(new Node(),
- new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false));
+ final String dictName = "runReadAndWrite";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
+
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(words.size(), dict, words, shortcuts);
addBigrams(dict, words, bigrams);
checkDictionary(dict, words, bigrams, shortcuts);
final long write = timeWritingDictToFile(file, dict, formatOptions);
- final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType);
+ final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType,
+ formatOptions, dict.mOptions);
return "PROF: read=" + read + "ms, write=" + write + "ms :" + message
+ " : " + outputOptions(bufferType, formatOptions);
@@ -318,6 +329,28 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
formatOptions, "chain"));
results.add(runReadAndWrite(sWords, sStarBigrams, null /* shortcuts */, bufferType,
formatOptions, "star"));
+ results.add(runReadAndWrite(sWords, sEmptyBigrams, sShortcuts, bufferType, formatOptions,
+ "unigram with shortcuts"));
+ results.add(runReadAndWrite(sWords, sChainBigrams, sShortcuts, bufferType, formatOptions,
+ "chain with shortcuts"));
+ results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions,
+ "star with shortcuts"));
+ }
+
+ // Unit test for CharEncoding.readString and CharEncoding.writeString.
+ public void testCharEncoding() {
+ // the max length of a word in sWords is less than 50.
+ // See generateWords.
+ final byte[] buffer = new byte[50 * 3];
+ final DictBuffer dictBuffer = new ByteArrayDictBuffer(buffer);
+ for (final String word : sWords) {
+ Log.d("testReadAndWriteString", "write : " + word);
+ Arrays.fill(buffer, (byte)0);
+ CharEncoding.writeString(buffer, 0, word);
+ dictBuffer.position(0);
+ final String str = CharEncoding.readString(dictBuffer);
+ assertEquals(word, str);
+ }
}
public void testReadAndWriteWithByteBuffer() {
@@ -326,6 +359,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION2);
runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE);
runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
+ runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
for (final String result : results) {
Log.d(TAG, result);
@@ -338,6 +373,8 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION2);
runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE);
runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
+ runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
for (final String result : results) {
Log.d(TAG, result);
@@ -348,9 +385,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
private void checkWordMap(final List<String> expectedWords,
final SparseArray<List<Integer>> expectedBigrams,
- final Map<Integer, String> resultWords,
- final Map<Integer, Integer> resultFrequencies,
- final Map<Integer, ArrayList<PendingAttribute>> resultBigrams) {
+ final TreeMap<Integer, String> resultWords,
+ final TreeMap<Integer, Integer> resultFrequencies,
+ final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams) {
// check unigrams
final Set<String> actualWordsSet = new HashSet<String>(resultWords.values());
final Set<String> expectedWordsSet = new HashSet<String>(expectedWords);
@@ -361,7 +398,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
// check bigrams
- final Map<String, List<String>> expBigrams = new HashMap<String, List<String>>();
+ final HashMap<String, List<String>> expBigrams = new HashMap<String, List<String>>();
for (int i = 0; i < expectedBigrams.size(); ++i) {
final String word1 = expectedWords.get(expectedBigrams.keyAt(i));
for (int w2 : expectedBigrams.valueAt(i)) {
@@ -372,7 +409,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
}
- final Map<String, List<String>> actBigrams = new HashMap<String, List<String>>();
+ final HashMap<String, List<String>> actBigrams = new HashMap<String, List<String>>();
for (Entry<Integer, ArrayList<PendingAttribute>> entry : resultBigrams.entrySet()) {
final String word1 = resultWords.get(entry.getKey());
final int unigramFreq = resultFrequencies.get(entry.getKey());
@@ -383,7 +420,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
actBigrams.get(word1).add(word2);
- final int bigramFreq = BinaryDictDecoder.reconstructBigramFrequency(
+ final int bigramFreq = BinaryDictIOUtils.reconstructBigramFrequency(
unigramFreq, attr.mFrequency);
assertTrue(Math.abs(bigramFreq - BIGRAM_FREQ) < TOLERANCE_OF_BIGRAM_FREQ);
}
@@ -393,22 +430,21 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
private long timeAndCheckReadUnigramsAndBigramsBinary(final File file, final List<String> words,
- final SparseArray<List<Integer>> bigrams, final int bufferType) {
+ final SparseArray<List<Integer>> bigrams, final int bufferType,
+ final FormatOptions formatOptions, final DictionaryOptions dictOptions) {
FileInputStream inStream = null;
- final Map<Integer, String> resultWords = CollectionUtils.newTreeMap();
- final Map<Integer, ArrayList<PendingAttribute>> resultBigrams =
+ final TreeMap<Integer, String> resultWords = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams =
CollectionUtils.newTreeMap();
- final Map<Integer, Integer> resultFreqs = CollectionUtils.newTreeMap();
+ final TreeMap<Integer, Integer> resultFreqs = CollectionUtils.newTreeMap();
long now = -1, diff = -1;
- final BinaryDictReader reader = new BinaryDictReader(file);
try {
- getBuffer(reader, bufferType);
- assertNotNull("Can't get buffer.", reader.getBuffer());
+ final DictDecoder dictDecoder = getDictDecoder(file, bufferType, formatOptions,
+ dictOptions);
now = System.currentTimeMillis();
- BinaryDictIOUtils.readUnigramsAndBigramsBinary(reader, resultWords, resultFreqs,
- resultBigrams);
+ dictDecoder.readUnigramsAndBigramsBinary(resultWords, resultFreqs, resultBigrams);
diff = System.currentTimeMillis() - now;
} catch (IOException e) {
Log.e(TAG, "IOException", e);
@@ -428,50 +464,48 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
return diff;
}
- private String runReadUnigramsAndBigramsBinary(final List<String> words,
+ private String runReadUnigramsAndBigramsBinary(final ArrayList<String> words,
final SparseArray<List<Integer>> bigrams, final int bufferType,
final FormatSpec.FormatOptions formatOptions, final String message) {
- File file = null;
- try {
- file = File.createTempFile("runReadUnigrams", ".dict", getContext().getCacheDir());
- } catch (IOException e) {
- Log.e(TAG, "IOException", e);
- }
- assertNotNull(file);
+ final String dictName = "runReadUnigrams";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
// making the dictionary from lists of words.
- final FusionDictionary dict = new FusionDictionary(new Node(),
- new FusionDictionary.DictionaryOptions(
- new HashMap<String, String>(), false, false));
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(words.size(), dict, words, null /* shortcutMap */);
addBigrams(dict, words, bigrams);
timeWritingDictToFile(file, dict, formatOptions);
- long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType);
+ long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType,
+ formatOptions, dict.mOptions);
long fullReading = timeReadingAndCheckDict(file, words, bigrams, null /* shortcutMap */,
- bufferType);
+ bufferType, formatOptions, dict.mOptions);
return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap
+ " : " + message + " : " + outputOptions(bufferType, formatOptions);
}
- private void runReadUnigramsAndBigramsTests(final List<String> results, final int bufferType,
- final FormatSpec.FormatOptions formatOptions) {
+ private void runReadUnigramsAndBigramsTests(final ArrayList<String> results,
+ final int bufferType, final FormatSpec.FormatOptions formatOptions) {
results.add(runReadUnigramsAndBigramsBinary(sWords, sEmptyBigrams, bufferType,
formatOptions, "unigram"));
results.add(runReadUnigramsAndBigramsBinary(sWords, sChainBigrams, bufferType,
formatOptions, "chain"));
- results.add(runReadUnigramsAndBigramsBinary(sWords, sChainBigrams, bufferType,
+ results.add(runReadUnigramsAndBigramsBinary(sWords, sStarBigrams, bufferType,
formatOptions, "star"));
}
public void testReadUnigramsAndBigramsBinaryWithByteBuffer() {
- final List<String> results = CollectionUtils.newArrayList();
+ final ArrayList<String> results = CollectionUtils.newArrayList();
runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION2);
runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE);
runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
+ runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
for (final String result : results) {
Log.d(TAG, result);
@@ -479,11 +513,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
public void testReadUnigramsAndBigramsBinaryWithByteArray() {
- final List<String> results = CollectionUtils.newArrayList();
+ final ArrayList<String> results = CollectionUtils.newArrayList();
runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION2);
runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE);
runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
+ runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
for (final String result : results) {
Log.d(TAG, result);
@@ -491,31 +527,30 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
// Tests for getTerminalPosition
- private String getWordFromBinary(final FusionDictionaryBufferInterface buffer,
- final int address) {
- if (buffer.position() != 0) buffer.position(0);
+ private String getWordFromBinary(final DictDecoder dictDecoder, final int address) {
+ if (dictDecoder.getPosition() != 0) dictDecoder.setPosition(0);
- FileHeader header = null;
+ FileHeader fileHeader = null;
try {
- header = BinaryDictDecoder.readHeader(buffer);
+ fileHeader = dictDecoder.readHeader();
} catch (IOException e) {
return null;
} catch (UnsupportedFormatException e) {
return null;
}
- if (header == null) return null;
- return BinaryDictDecoder.getWordAtAddress(buffer, header.mHeaderSize,
- address - header.mHeaderSize, header.mFormatOptions).mWord;
+ if (fileHeader == null) return null;
+ return BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize,
+ address, fileHeader.mFormatOptions).mWord;
}
- private long runGetTerminalPosition(final FusionDictionaryBufferInterface buffer,
- final String word, int index, boolean contained) {
+ private long checkGetTerminalPosition(final DictDecoder dictDecoder, final String word,
+ int index, boolean contained) {
final int expectedFrequency = (UNIGRAM_FREQ + index) % 255;
long diff = -1;
int position = -1;
try {
final long now = System.nanoTime();
- position = BinaryDictIOUtils.getTerminalPosition(buffer, word);
+ position = dictDecoder.getTerminalPosition(word);
diff = System.nanoTime() - now;
} catch (IOException e) {
Log.e(TAG, "IOException while getTerminalPosition", e);
@@ -524,50 +559,43 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
assertEquals(FormatSpec.NOT_VALID_WORD != position, contained);
- if (contained) assertEquals(getWordFromBinary(buffer, position), word);
+ if (contained) assertEquals(getWordFromBinary(dictDecoder, position), word);
return diff;
}
- public void testGetTerminalPosition() {
- File file = null;
- try {
- file = File.createTempFile("testGetTerminalPosition", ".dict",
- getContext().getCacheDir());
- } catch (IOException e) {
- // do nothing
- }
- assertNotNull(file);
+ private void runGetTerminalPosition(final ArrayList<String> words,
+ final SparseArray<List<Integer>> bigrams, final int bufferType,
+ final FormatOptions formatOptions, final String message) {
+ final String dictName = "testGetTerminalPosition";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
- final FusionDictionary dict = new FusionDictionary(new Node(),
- new FusionDictionary.DictionaryOptions(
- new HashMap<String, String>(), false, false));
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */);
- timeWritingDictToFile(file, dict, VERSION3_WITH_DYNAMIC_UPDATE);
+ addBigrams(dict, words, bigrams);
+ timeWritingDictToFile(file, dict, formatOptions);
- final BinaryDictReader reader = new BinaryDictReader(file);
- FusionDictionaryBufferInterface buffer = null;
+ final DictDecoder dictDecoder = getDictDecoder(file, DictDecoder.USE_BYTEARRAY,
+ formatOptions, dict.mOptions);
try {
- buffer = reader.openAndGetBuffer(
- new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ dictDecoder.openDictBuffer();
} catch (IOException e) {
// ignore
Log.e(TAG, "IOException while opening the buffer", e);
}
- assertNotNull("Can't get the buffer", buffer);
+ assertTrue("Can't get the buffer", dictDecoder.isDictBufferOpen());
try {
// too long word
final String longWord = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
- assertEquals(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, longWord));
+ assertEquals(FormatSpec.NOT_VALID_WORD, dictDecoder.getTerminalPosition(longWord));
// null
- assertEquals(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, null));
+ assertEquals(FormatSpec.NOT_VALID_WORD, dictDecoder.getTerminalPosition(null));
// empty string
- assertEquals(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, ""));
+ assertEquals(FormatSpec.NOT_VALID_WORD, dictDecoder.getTerminalPosition(""));
} catch (IOException e) {
} catch (UnsupportedFormatException e) {
}
@@ -575,59 +603,80 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
// Test a word that is contained within the dictionary.
long sum = 0;
for (int i = 0; i < sWords.size(); ++i) {
- final long time = runGetTerminalPosition(buffer, sWords.get(i), i, true);
+ final long time = checkGetTerminalPosition(dictDecoder, sWords.get(i), i, true);
sum += time == -1 ? 0 : time;
}
- Log.d(TAG, "per a search : " + (((double)sum) / sWords.size() / 1000000));
+ Log.d(TAG, "per search : " + (((double)sum) / sWords.size() / 1000000) + " : " + message
+ + " : " + outputOptions(bufferType, formatOptions));
// Test a word that isn't contained within the dictionary.
final Random random = new Random((int)System.currentTimeMillis());
- final int[] codePointSet = generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, random);
+ final int[] codePointSet = CodePointUtils.generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE,
+ random);
for (int i = 0; i < 1000; ++i) {
- final String word = generateWord(random, codePointSet);
+ final String word = CodePointUtils.generateWord(random, codePointSet);
if (sWords.indexOf(word) != -1) continue;
- runGetTerminalPosition(buffer, word, i, false);
+ checkGetTerminalPosition(dictDecoder, word, i, false);
}
}
- public void testDeleteWord() {
- File file = null;
- try {
- file = File.createTempFile("testDeleteWord", ".dict", getContext().getCacheDir());
- } catch (IOException e) {
- // do nothing
+ private void runGetTerminalPositionTests(final ArrayList<String> results, final int bufferType,
+ final FormatOptions formatOptions) {
+ runGetTerminalPosition(sWords, sEmptyBigrams, bufferType, formatOptions, "unigram");
+ }
+
+ public void testGetTerminalPosition() {
+ final ArrayList<String> results = CollectionUtils.newArrayList();
+
+ runGetTerminalPositionTests(results, USE_BYTE_ARRAY, VERSION2);
+ runGetTerminalPositionTests(results, USE_BYTE_ARRAY, VERSION3_WITHOUT_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
+
+ runGetTerminalPositionTests(results, USE_BYTE_BUFFER, VERSION2);
+ runGetTerminalPositionTests(results, USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
+ runGetTerminalPositionTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
+
+ for (final String result : results) {
+ Log.d(TAG, result);
}
- assertNotNull(file);
+ }
+
+ public void testDeleteWord() {
+ final String dictName = "testDeleteWord";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(
new HashMap<String, String>(), false, false));
addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */);
timeWritingDictToFile(file, dict, VERSION3_WITH_DYNAMIC_UPDATE);
- final BinaryDictReader reader = new BinaryDictReader(file);
- FusionDictionaryBufferInterface buffer = null;
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file, DictDecoder.USE_BYTEARRAY);
try {
- buffer = reader.openAndGetBuffer(
- new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ dictDecoder.openDictBuffer();
} catch (IOException e) {
// ignore
Log.e(TAG, "IOException while opening the buffer", e);
}
- assertNotNull("Can't get the buffer", buffer);
+ assertTrue("Can't get the buffer", dictDecoder.isDictBufferOpen());
try {
MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, sWords.get(0)));
- DynamicBinaryDictIOUtils.deleteWord(buffer, sWords.get(0));
+ dictDecoder.getTerminalPosition(sWords.get(0)));
+ DynamicBinaryDictIOUtils.deleteWord(dictDecoder, sWords.get(0));
assertEquals(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, sWords.get(0)));
+ dictDecoder.getTerminalPosition(sWords.get(0)));
MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, sWords.get(5)));
- DynamicBinaryDictIOUtils.deleteWord(buffer, sWords.get(5));
+ dictDecoder.getTerminalPosition(sWords.get(5)));
+ DynamicBinaryDictIOUtils.deleteWord(dictDecoder, sWords.get(5));
assertEquals(FormatSpec.NOT_VALID_WORD,
- BinaryDictIOUtils.getTerminalPosition(buffer, sWords.get(5)));
+ dictDecoder.getTerminalPosition(sWords.get(5)));
} catch (IOException e) {
} catch (UnsupportedFormatException e) {
}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
index f2476b2e6..a83749499 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
@@ -21,20 +21,16 @@ import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.ByteBufferWrapper;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
@@ -49,6 +45,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
public static final int DEFAULT_MAX_UNIGRAMS = 1500;
private final int mMaxUnigrams;
+ private static final String TEST_DICT_FILE_EXTENSION = ".testDict";
+
private static final String[] CHARACTERS = {
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
@@ -86,8 +84,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
return builder.toString();
}
- private static void printCharGroup(final CharGroupInfo info) {
- Log.d(TAG, " CharGroup at " + info.mOriginalAddress);
+ private static void printPtNode(final PtNodeInfo info) {
+ Log.d(TAG, " PtNode at " + info.mOriginalAddress);
Log.d(TAG, " flags = " + info.mFlags);
Log.d(TAG, " parentAddress = " + info.mParentAddress);
Log.d(TAG, " characters = " + new String(info.mCharacters, 0,
@@ -111,70 +109,75 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
Log.d(TAG, " end address = " + info.mEndAddress);
}
- private static void printNode(final FusionDictionaryBufferInterface buffer,
+ private static void printNode(final Ver3DictDecoder dictDecoder,
final FormatSpec.FormatOptions formatOptions) {
- Log.d(TAG, "Node at " + buffer.position());
- final int count = BinaryDictDecoder.readCharGroupCount(buffer);
- Log.d(TAG, " charGroupCount = " + count);
+ final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
+ Log.d(TAG, "Node at " + dictBuffer.position());
+ final int count = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer);
+ Log.d(TAG, " ptNodeCount = " + count);
for (int i = 0; i < count; ++i) {
- final CharGroupInfo currentInfo = BinaryDictDecoder.readCharGroup(buffer,
- buffer.position(), formatOptions);
- printCharGroup(currentInfo);
+ final PtNodeInfo currentInfo = dictDecoder.readPtNode(dictBuffer.position(),
+ formatOptions);
+ printPtNode(currentInfo);
}
if (formatOptions.mSupportsDynamicUpdate) {
- final int forwardLinkAddress = buffer.readUnsignedInt24();
+ final int forwardLinkAddress = dictBuffer.readUnsignedInt24();
Log.d(TAG, " forwardLinkAddress = " + forwardLinkAddress);
}
}
- private static void printBinaryFile(final FusionDictionaryBufferInterface buffer)
+ @SuppressWarnings("unused")
+ private static void printBinaryFile(final Ver3DictDecoder dictDecoder)
throws IOException, UnsupportedFormatException {
- FileHeader header = BinaryDictDecoder.readHeader(buffer);
- while (buffer.position() < buffer.limit()) {
- printNode(buffer, header.mFormatOptions);
+ final FileHeader fileHeader = dictDecoder.readHeader();
+ final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
+ while (dictBuffer.position() < dictBuffer.limit()) {
+ printNode(dictDecoder, fileHeader.mFormatOptions);
}
}
private int getWordPosition(final File file, final String word) {
int position = FormatSpec.NOT_VALID_WORD;
- FileInputStream inStream = null;
+
try {
- inStream = new FileInputStream(file);
- final FusionDictionaryBufferInterface buffer = new ByteBufferWrapper(
- inStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()));
- position = BinaryDictIOUtils.getTerminalPosition(buffer, word);
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file,
+ DictDecoder.USE_READONLY_BYTEBUFFER);
+ position = dictDecoder.getTerminalPosition(word);
} catch (IOException e) {
} catch (UnsupportedFormatException e) {
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
}
return position;
}
- private CharGroupInfo findWordFromFile(final File file, final String word) {
- FileInputStream inStream = null;
- CharGroupInfo info = null;
+ /**
+ * Find a word using the DictDecoder.
+ *
+ * @param dictDecoder the dict decoder
+ * @param word the word searched
+ * @return the found ptNodeInfo
+ * @throws IOException
+ * @throws UnsupportedFormatException
+ */
+ private static PtNodeInfo findWordByBinaryDictReader(final DictDecoder dictDecoder,
+ final String word) throws IOException, UnsupportedFormatException {
+ int position = dictDecoder.getTerminalPosition(word);
+ if (position != FormatSpec.NOT_VALID_WORD) {
+ dictDecoder.setPosition(0);
+ final FileHeader header = dictDecoder.readHeader();
+ dictDecoder.setPosition(position);
+ return dictDecoder.readPtNode(position, header.mFormatOptions);
+ }
+ return null;
+ }
+
+ private PtNodeInfo findWordFromFile(final File file, final String word) {
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file);
+ PtNodeInfo info = null;
try {
- inStream = new FileInputStream(file);
- final FusionDictionaryBufferInterface buffer = new ByteBufferWrapper(
- inStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()));
- info = BinaryDictIOUtils.findWordFromBuffer(buffer, word);
+ dictDecoder.openDictBuffer();
+ info = findWordByBinaryDictReader(dictDecoder, word);
} catch (IOException e) {
} catch (UnsupportedFormatException e) {
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
}
return info;
}
@@ -183,42 +186,34 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
private long insertAndCheckWord(final File file, final String word, final int frequency,
final boolean exist, final ArrayList<WeightedString> bigrams,
final ArrayList<WeightedString> shortcuts) {
- RandomAccessFile raFile = null;
BufferedOutputStream outStream = null;
- FusionDictionaryBufferInterface buffer = null;
long amountOfTime = -1;
try {
- raFile = new RandomAccessFile(file, "rw");
- buffer = new ByteBufferWrapper(raFile.getChannel().map(
- FileChannel.MapMode.READ_WRITE, 0, file.length()));
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file,
+ DictDecoder.USE_WRITABLE_BYTEBUFFER);
+ dictDecoder.openDictBuffer();
outStream = new BufferedOutputStream(new FileOutputStream(file, true));
if (!exist) {
assertEquals(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word));
}
final long now = System.nanoTime();
- DynamicBinaryDictIOUtils.insertWord(buffer, outStream, word, frequency, bigrams,
+ DynamicBinaryDictIOUtils.insertWord(dictDecoder, outStream, word, frequency, bigrams,
shortcuts, false, false);
amountOfTime = System.nanoTime() - now;
outStream.flush();
MoreAsserts.assertNotEqual(FormatSpec.NOT_VALID_WORD, getWordPosition(file, word));
outStream.close();
- raFile.close();
} catch (IOException e) {
+ Log.e(TAG, "Raised an IOException while inserting a word", e);
} catch (UnsupportedFormatException e) {
+ Log.e(TAG, "Raised an UnsupportedFormatException error while inserting a word", e);
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
- // do nothing
- }
- }
- if (raFile != null) {
- try {
- raFile.close();
- } catch (IOException e) {
- // do nothing
+ Log.e(TAG, "Failed to close the output stream", e);
}
}
}
@@ -226,65 +221,48 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
}
private void deleteWord(final File file, final String word) {
- RandomAccessFile raFile = null;
- FusionDictionaryBufferInterface buffer = null;
try {
- raFile = new RandomAccessFile(file, "rw");
- buffer = new ByteBufferWrapper(raFile.getChannel().map(
- FileChannel.MapMode.READ_WRITE, 0, file.length()));
- DynamicBinaryDictIOUtils.deleteWord(buffer, word);
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(file,
+ DictDecoder.USE_WRITABLE_BYTEBUFFER);
+ dictDecoder.openDictBuffer();
+ DynamicBinaryDictIOUtils.deleteWord(dictDecoder, word);
} catch (IOException e) {
} catch (UnsupportedFormatException e) {
- } finally {
- if (raFile != null) {
- try {
- raFile.close();
- } catch (IOException e) {
- // do nothing
- }
- }
}
}
private void checkReverseLookup(final File file, final String word, final int position) {
- FileInputStream inStream = null;
+
try {
- inStream = new FileInputStream(file);
- final FusionDictionaryBufferInterface buffer = new ByteBufferWrapper(
- inStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()));
- final FileHeader header = BinaryDictDecoder.readHeader(buffer);
- assertEquals(word, BinaryDictDecoder.getWordAtAddress(buffer, header.mHeaderSize,
- position - header.mHeaderSize, header.mFormatOptions).mWord);
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file);
+ final FileHeader fileHeader = dictDecoder.readHeader();
+ assertEquals(word,
+ BinaryDictDecoderUtils.getWordAtPosition(dictDecoder, fileHeader.mHeaderSize,
+ position, fileHeader.mFormatOptions).mWord);
} catch (IOException e) {
+ Log.e(TAG, "Raised an IOException while looking up a word", e);
} catch (UnsupportedFormatException e) {
- } finally {
- if (inStream != null) {
- try {
- inStream.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ Log.e(TAG, "Raised an UnsupportedFormatException error while looking up a word", e);
}
}
public void testInsertWord() {
File file = null;
try {
- file = File.createTempFile("testInsertWord", ".dict", getContext().getCacheDir());
+ file = File.createTempFile("testInsertWord", TEST_DICT_FILE_EXTENSION,
+ getContext().getCacheDir());
} catch (IOException e) {
fail("IOException while creating temporary file: " + e);
}
// set an initial dictionary.
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false));
dict.add("abcd", 10, null, false);
try {
- final FileOutputStream out = new FileOutputStream(file);
- BinaryDictEncoder.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
- out.close();
+ final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+ dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
} catch (IOException e) {
fail("IOException while writing an initial dictionary : " + e);
} catch (UnsupportedFormatException e) {
@@ -321,22 +299,21 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
public void testInsertWordWithBigrams() {
File file = null;
try {
- file = File.createTempFile("testInsertWordWithBigrams", ".dict",
+ file = File.createTempFile("testInsertWordWithBigrams", TEST_DICT_FILE_EXTENSION,
getContext().getCacheDir());
} catch (IOException e) {
fail("IOException while creating temporary file: " + e);
}
// set an initial dictionary.
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false));
dict.add("abcd", 10, null, false);
dict.add("efgh", 15, null, false);
try {
- final FileOutputStream out = new FileOutputStream(file);
- BinaryDictEncoder.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
- out.close();
+ final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+ dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
} catch (IOException e) {
fail("IOException while writing an initial dictionary : " + e);
} catch (UnsupportedFormatException e) {
@@ -349,7 +326,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
insertAndCheckWord(file, "banana", 0, false, null, null);
insertAndCheckWord(file, "recursive", 60, true, banana, null);
- final CharGroupInfo info = findWordFromFile(file, "recursive");
+ final PtNodeInfo info = findWordFromFile(file, "recursive");
int bananaPos = getWordPosition(file, "banana");
assertNotNull(info.mBigrams);
assertEquals(info.mBigrams.size(), 1);
@@ -359,21 +336,21 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
public void testRandomWords() {
File file = null;
try {
- file = File.createTempFile("testRandomWord", ".dict", getContext().getCacheDir());
+ file = File.createTempFile("testRandomWord", TEST_DICT_FILE_EXTENSION,
+ getContext().getCacheDir());
} catch (IOException e) {
}
assertNotNull(file);
// set an initial dictionary.
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(new HashMap<String, String>(), false,
false));
dict.add("initial", 10, null, false);
try {
- final FileOutputStream out = new FileOutputStream(file);
- BinaryDictEncoder.writeDictionaryBinary(out, dict, FORMAT_OPTIONS);
- out.close();
+ final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+ dictEncoder.writeDictionary(dict, FORMAT_OPTIONS);
} catch (IOException e) {
assertTrue(false);
} catch (UnsupportedFormatException e) {
diff --git a/tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java b/tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java
new file mode 100644
index 000000000..36b958af8
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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 java.util.Random;
+
+// Utility methods related with code points used for tests.
+public class CodePointUtils {
+ private CodePointUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static int[] generateCodePointSet(final int codePointSetSize, final Random random) {
+ final int[] codePointSet = new int[codePointSetSize];
+ for (int i = codePointSet.length - 1; i >= 0; ) {
+ final int r = Math.abs(random.nextInt());
+ if (r < 0) continue;
+ // Don't insert 0~0x20, but insert any other code point.
+ // Code points are in the range 0~0x10FFFF.
+ final int candidateCodePoint = 0x20 + r % (Character.MAX_CODE_POINT - 0x20);
+ // Code points between MIN_ and MAX_SURROGATE are not valid on their own.
+ if (candidateCodePoint >= Character.MIN_SURROGATE
+ && candidateCodePoint <= Character.MAX_SURROGATE) continue;
+ codePointSet[i] = candidateCodePoint;
+ --i;
+ }
+ return codePointSet;
+ }
+
+ /**
+ * Generates a random word.
+ */
+ public static String generateWord(final Random random, final int[] codePointSet) {
+ StringBuilder builder = new StringBuilder();
+ // 8 * 4 = 32 chars max, but we do it the following way so as to bias the random toward
+ // longer words. This should be closer to natural language, and more importantly, it will
+ // exercise the algorithms in dicttool much more.
+ final int count = 1 + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5);
+ while (builder.length() < count) {
+ builder.appendCodePoint(codePointSet[Math.abs(random.nextInt()) % codePointSet.length]);
+ }
+ return builder.toString();
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java b/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java
new file mode 100644
index 000000000..132483d5e
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/makedict/SparseTableTests.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * Unit tests for SparseTable.
+ */
+@LargeTest
+public class SparseTableTests extends AndroidTestCase {
+ private static final String TAG = SparseTableTests.class.getSimpleName();
+
+ private static final int[] SMALL_INDEX = { SparseTable.NOT_EXIST, 0 };
+ private static final int[] BIG_INDEX = { SparseTable.NOT_EXIST, 1, 2, 3, 4, 5, 6, 7};
+
+ private final Random mRandom;
+ private final ArrayList<Integer> mRandomIndex;
+
+ private static final int DEFAULT_SIZE = 10000;
+ private static final int BLOCK_SIZE = 8;
+
+ public SparseTableTests() {
+ this(System.currentTimeMillis(), DEFAULT_SIZE);
+ }
+
+ public SparseTableTests(final long seed, final int tableSize) {
+ super();
+ Log.d(TAG, "Seed for test is " + seed + ", size is " + tableSize);
+ mRandom = new Random(seed);
+ mRandomIndex = new ArrayList<Integer>(tableSize);
+ for (int i = 0; i < tableSize; ++i) {
+ mRandomIndex.add(SparseTable.NOT_EXIST);
+ }
+ }
+
+ public void testInitializeWithArray() {
+ final SparseTable table = new SparseTable(SMALL_INDEX, BIG_INDEX, BLOCK_SIZE);
+ for (int i = 0; i < 8; ++i) {
+ assertEquals(SparseTable.NOT_EXIST, table.get(i));
+ }
+ assertEquals(SparseTable.NOT_EXIST, table.get(8));
+ for (int i = 9; i < 16; ++i) {
+ assertEquals(i - 8, table.get(i));
+ }
+ }
+
+ public void testSet() {
+ final SparseTable table = new SparseTable(16, BLOCK_SIZE);
+ table.set(3, 6);
+ table.set(8, 16);
+ for (int i = 0; i < 16; ++i) {
+ if (i == 3 || i == 8) {
+ assertEquals(i * 2, table.get(i));
+ } else {
+ assertEquals(SparseTable.NOT_EXIST, table.get(i));
+ }
+ }
+ }
+
+ private void generateRandomIndex(final int size, final int prop) {
+ for (int i = 0; i < DEFAULT_SIZE; ++i) {
+ if (mRandom.nextInt(100) < prop) {
+ mRandomIndex.set(i, mRandom.nextInt());
+ } else {
+ mRandomIndex.set(i, SparseTable.NOT_EXIST);
+ }
+ }
+ }
+
+ private void runTestRandomSet() {
+ final SparseTable table = new SparseTable(DEFAULT_SIZE, BLOCK_SIZE);
+ int elementCount = 0;
+ for (int i = 0; i < DEFAULT_SIZE; ++i) {
+ if (mRandomIndex.get(i) != SparseTable.NOT_EXIST) {
+ table.set(i, mRandomIndex.get(i));
+ elementCount++;
+ }
+ }
+
+ Log.d(TAG, "table size = " + table.getLookupTableSize() + " + "
+ + table.getContentTableSize());
+ Log.d(TAG, "the table has " + elementCount + " elements");
+ for (int i = 0; i < DEFAULT_SIZE; ++i) {
+ assertEquals(table.get(i), (int)mRandomIndex.get(i));
+ }
+
+ // flush and reload
+ OutputStream lookupOutStream = null;
+ OutputStream contentOutStream = null;
+ InputStream lookupInStream = null;
+ InputStream contentInStream = null;
+ try {
+ final File lookupIndexFile = File.createTempFile("testRandomSet", ".small");
+ final File contentFile = File.createTempFile("testRandomSet", ".big");
+ lookupOutStream = new FileOutputStream(lookupIndexFile);
+ contentOutStream = new FileOutputStream(contentFile);
+ table.write(lookupOutStream, contentOutStream);
+ lookupInStream = new FileInputStream(lookupIndexFile);
+ contentInStream = new FileInputStream(contentFile);
+ final byte[] lookupArray = new byte[(int) lookupIndexFile.length()];
+ final byte[] contentArray = new byte[(int) contentFile.length()];
+ lookupInStream.read(lookupArray);
+ contentInStream.read(contentArray);
+ final SparseTable newTable = new SparseTable(lookupArray, contentArray, BLOCK_SIZE);
+ for (int i = 0; i < DEFAULT_SIZE; ++i) {
+ assertEquals(table.get(i), newTable.get(i));
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "IOException while flushing and realoding", e);
+ } finally {
+ if (lookupOutStream != null) {
+ try {
+ lookupOutStream.close();
+ } catch (IOException e) {
+ Log.d(TAG, "IOException while closing the stream", e);
+ }
+ }
+ if (contentOutStream != null) {
+ try {
+ contentOutStream.close();
+ } catch (IOException e) {
+ Log.d(TAG, "IOException while closing contentStream.", e);
+ }
+ }
+ }
+ }
+
+ public void testRandomSet() {
+ for (int i = 0; i <= 100; i += 10) {
+ generateRandomIndex(DEFAULT_SIZE, i);
+ runTestRandomSet();
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictReaderTests.java b/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java
index 1c6de50f0..9611599b9 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictReaderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java
@@ -16,14 +16,13 @@
package com.android.inputmethod.latin.makedict;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder.FusionDictionaryBufferInterface;
-import com.android.inputmethod.latin.makedict.BinaryDictReader.FusionDictionaryBufferFactory;
-import com.android.inputmethod.latin.makedict.BinaryDictReader.
- FusionDictionaryBufferFromByteArrayFactory;
-import com.android.inputmethod.latin.makedict.BinaryDictReader.
- FusionDictionaryBufferFromByteBufferFactory;
-import com.android.inputmethod.latin.makedict.BinaryDictReader.
- FusionDictionaryBufferFromWritableByteBufferFactory;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
+import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory;
+import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFromByteArrayFactory;
+import com.android.inputmethod.latin.makedict.DictDecoder.
+ DictionaryBufferFromReadOnlyByteBufferFactory;
+import com.android.inputmethod.latin.makedict.DictDecoder.
+ DictionaryBufferFromWritableByteBufferFactory;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -33,10 +32,10 @@ import java.io.FileOutputStream;
import java.io.IOException;
/**
- * Unit tests for BinaryDictReader
+ * Unit tests for Ver3DictDecoder
*/
-public class BinaryDictReaderTests extends AndroidTestCase {
- private static final String TAG = BinaryDictReaderTests.class.getSimpleName();
+public class Ver3DictDecoderTests extends AndroidTestCase {
+ private static final String TAG = Ver3DictDecoderTests.class.getSimpleName();
private final byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
@@ -60,8 +59,7 @@ public class BinaryDictReaderTests extends AndroidTestCase {
}
@SuppressWarnings("null")
- public void runTestOpenBuffer(final String testName,
- final FusionDictionaryBufferFactory factory) {
+ public void runTestOpenBuffer(final String testName, final DictionaryBufferFactory factory) {
File testFile = null;
try {
testFile = File.createTempFile(testName, ".tmp", getContext().getCacheDir());
@@ -70,9 +68,9 @@ public class BinaryDictReaderTests extends AndroidTestCase {
}
assertNotNull(testFile);
- final BinaryDictReader reader = new BinaryDictReader(testFile);
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory);
try {
- reader.openBuffer(factory);
+ dictDecoder.openDictBuffer();
} catch (Exception e) {
Log.e(TAG, "Failed to open the buffer", e);
}
@@ -80,32 +78,31 @@ public class BinaryDictReaderTests extends AndroidTestCase {
writeDataToFile(testFile);
try {
- reader.openBuffer(factory);
+ dictDecoder.openDictBuffer();
} catch (Exception e) {
Log.e(TAG, "Raised the exception while opening buffer", e);
}
- assertEquals(testFile.length(), reader.getBuffer().capacity());
+ assertEquals(testFile.length(), dictDecoder.getDictBuffer().capacity());
}
public void testOpenBufferWithByteBuffer() {
runTestOpenBuffer("testOpenBufferWithByteBuffer",
- new FusionDictionaryBufferFromByteBufferFactory());
+ new DictionaryBufferFromReadOnlyByteBufferFactory());
}
public void testOpenBufferWithByteArray() {
runTestOpenBuffer("testOpenBufferWithByteArray",
- new FusionDictionaryBufferFromByteArrayFactory());
+ new DictionaryBufferFromByteArrayFactory());
}
public void testOpenBufferWithWritableByteBuffer() {
runTestOpenBuffer("testOpenBufferWithWritableByteBuffer",
- new FusionDictionaryBufferFromWritableByteBufferFactory());
+ new DictionaryBufferFromWritableByteBufferFactory());
}
@SuppressWarnings("null")
- public void runTestGetBuffer(final String testName,
- final FusionDictionaryBufferFactory factory) {
+ public void runTestGetBuffer(final String testName, final DictionaryBufferFactory factory) {
File testFile = null;
try {
testFile = File.createTempFile(testName, ".tmp", getContext().getCacheDir());
@@ -113,40 +110,41 @@ public class BinaryDictReaderTests extends AndroidTestCase {
Log.e(TAG, "IOException while the creating temporary file", e);
}
- final BinaryDictReader reader = new BinaryDictReader(testFile);
+ final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory);
// the default return value of getBuffer() must be null.
- assertNull("the default return value of getBuffer() is not null", reader.getBuffer());
+ assertNull("the default return value of getBuffer() is not null",
+ dictDecoder.getDictBuffer());
writeDataToFile(testFile);
assertTrue(testFile.exists());
Log.d(TAG, "file length = " + testFile.length());
- FusionDictionaryBufferInterface buffer = null;
+ DictBuffer dictBuffer = null;
try {
- buffer = reader.openAndGetBuffer(factory);
+ dictBuffer = dictDecoder.openAndGetDictBuffer();
} catch (IOException e) {
Log.e(TAG, "Failed to open and get the buffer", e);
}
- assertNotNull("the buffer must not be null", buffer);
+ assertNotNull("the buffer must not be null", dictBuffer);
for (int i = 0; i < data.length; ++i) {
- assertEquals(data[i], buffer.readUnsignedByte());
+ assertEquals(data[i], dictBuffer.readUnsignedByte());
}
}
public void testGetBufferWithByteBuffer() {
runTestGetBuffer("testGetBufferWithByteBuffer",
- new FusionDictionaryBufferFromByteBufferFactory());
+ new DictionaryBufferFromReadOnlyByteBufferFactory());
}
public void testGetBufferWithByteArray() {
runTestGetBuffer("testGetBufferWithByteArray",
- new FusionDictionaryBufferFromByteArrayFactory());
+ new DictionaryBufferFromByteArrayFactory());
}
public void testGetBufferWithWritableByteBuffer() {
runTestGetBuffer("testGetBufferWithWritableByteBuffer",
- new FusionDictionaryBufferFromWritableByteBufferFactory());
+ new DictionaryBufferFromWritableByteBufferFactory());
}
}
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index b3e2ee0ff..d605cdb84 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -22,6 +22,7 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.io.File;
@@ -29,6 +30,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* Unit tests for UserHistoryDictionary
@@ -43,6 +45,9 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
};
+ private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000;
+ private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100;
+
@Override
public void setUp() {
mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
@@ -73,48 +78,74 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
private void addToDict(final UserHistoryPredictionDictionary dict, final List<String> words) {
String prevWord = null;
for (String word : words) {
- dict.forceAddWordForTest(prevWord, word, true);
+ dict.addToPersonalizationPredictionDictionary(prevWord, word, true);
prevWord = word;
}
}
- public void testRandomWords() {
- File dictFile = null;
- try {
- Log.d(TAG, "This test can be used for profiling.");
- Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
- final int numberOfWords = 1000;
- final Random random = new Random(123456);
- List<String> words = generateWords(numberOfWords, random);
-
- final String locale = "testRandomWords";
- final String fileName = "UserHistoryDictionary." + locale + ".dict";
- dictFile = new File(getContext().getFilesDir(), fileName);
- final UserHistoryPredictionDictionary dict =
- PersonalizationDictionaryHelper.getUserHistoryPredictionDictionary(
- getContext(), locale, mPrefs);
- dict.mIsTest = true;
-
- addToDict(dict, words);
-
+ /**
+ * @param checksContents if true, checks whether written words are actually in the dictionary
+ * or not.
+ */
+ private void addAndWriteRandomWords(final String testFilenameSuffix, final int numberOfWords,
+ final Random random, final boolean checksContents) {
+ final List<String> words = generateWords(numberOfWords, random);
+ final UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffix /* locale */, mPrefs);
+ // Add random words to the user history dictionary.
+ addToDict(dict, words);
+ if (checksContents) {
try {
- Log.d(TAG, "waiting for adding the word ...");
- Thread.sleep(2000);
+ Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
- Log.d(TAG, "InterruptedException: " + e);
}
+ // Limit word count to check when using a Java on memory dictionary.
+ final int wordCountToCheck =
+ ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ?
+ numberOfWords : 10;
+ for (int i = 0; i < wordCountToCheck; ++i) {
+ final String word = words.get(i);
+ // This may fail as long as we use tryLock on inserting the bigram words
+ assertTrue(dict.isInDictionaryForTests(word));
+ }
+ }
+ // write to file.
+ dict.close();
+ }
- // write to file
- dict.close();
+ public void testRandomWords() {
+ File dictFile = null;
+ Log.d(TAG, "This test can be used for profiling.");
+ Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
+ final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis();
+ final int numberOfWords = 1000;
+ final Random random = new Random(123456);
+ try {
+ addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
+ true /* checksContents */);
+ } finally {
try {
+ final UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffix, mPrefs);
Log.d(TAG, "waiting for writing ...");
- Thread.sleep(5000);
+ dict.shutdownExecutorForTests();
+ while (!dict.isTerminatedForTests()) {
+ Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+ }
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e);
}
- } finally {
+
+ final String fileName = UserHistoryPredictionDictionary.NAME + "." + testFilenameSuffix
+ + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
+ dictFile = new File(getContext().getFilesDir(), fileName);
+
if (dictFile != null) {
+ assertTrue(dictFile.exists());
+ assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
dictFile.delete();
}
}
@@ -122,52 +153,94 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
public void testStressTestForSwitchingLanguagesAndAddingWords() {
final int numberOfLanguages = 2;
- final int numberOfLanguageSwitching = 100;
- final int numberOfWordsIntertedForEachLanguageSwitch = 100;
+ final int numberOfLanguageSwitching = 80;
+ final int numberOfWordsInsertedForEachLanguageSwitch = 100;
final File dictFiles[] = new File[numberOfLanguages];
+ final String testFilenameSuffixes[] = new String[numberOfLanguages];
try {
final Random random = new Random(123456);
- // Create locales for this test.
- String locales[] = new String[numberOfLanguages];
+ // Create filename suffixes for this test.
for (int i = 0; i < numberOfLanguages; i++) {
- locales[i] = "testSwitchingLanguages" + i;
- final String fileName = "UserHistoryDictionary." + locales[i] + ".dict";
+ testFilenameSuffixes[i] = "testSwitchingLanguages" + i;
+ final String fileName = UserHistoryPredictionDictionary.NAME + "." +
+ testFilenameSuffixes[i] + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
dictFiles[i] = new File(getContext().getFilesDir(), fileName);
}
- final long now = System.currentTimeMillis();
+ final long start = System.currentTimeMillis();
for (int i = 0; i < numberOfLanguageSwitching; i++) {
final int index = i % numberOfLanguages;
- // Switch languages to locales[index].
- final UserHistoryPredictionDictionary dict =
- PersonalizationDictionaryHelper.getUserHistoryPredictionDictionary(
- getContext(), locales[index], mPrefs);
- final List<String> words = generateWords(
- numberOfWordsIntertedForEachLanguageSwitch, random);
- // Add random words to the user history dictionary.
- addToDict(dict, words);
- // write to file
- dict.close();
+ // Switch languages to testFilenameSuffixes[index].
+ addAndWriteRandomWords(testFilenameSuffixes[index],
+ numberOfWordsInsertedForEachLanguageSwitch, random,
+ false /* checksContents */);
}
final long end = System.currentTimeMillis();
Log.d(TAG, "testStressTestForSwitchingLanguageAndAddingWords took "
- + (end - now) + " ms");
+ + (end - start) + " ms");
+ } finally {
try {
Log.d(TAG, "waiting for writing ...");
- Thread.sleep(5000);
+ for (int i = 0; i < numberOfLanguages; i++) {
+ final UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffixes[i], mPrefs);
+ dict.shutdownExecutorForTests();
+ while (!dict.isTerminatedForTests()) {
+ Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+ }
+ }
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e);
}
- } finally {
for (final File file : dictFiles) {
if (file != null) {
+ assertTrue(file.exists());
+ assertTrue(file.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
file.delete();
}
}
}
}
+
+ public void testAddManyWords() {
+ File dictFile = null;
+ final String testFilenameSuffix = "testRandomWords" + System.currentTimeMillis();
+ final int numberOfWords =
+ ExpandableBinaryDictionary.ENABLE_BINARY_DICTIONARY_DYNAMIC_UPDATE ?
+ 10000 : 1000;
+ final Random random = new Random(123456);
+
+ UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffix, mPrefs);
+ try {
+ addAndWriteRandomWords(testFilenameSuffix, numberOfWords, random,
+ true /* checksContents */);
+ dict.close();
+ } finally {
+ try {
+ Log.d(TAG, "waiting for writing ...");
+ dict.shutdownExecutorForTests();
+ while (!dict.isTerminatedForTests()) {
+ Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+ }
+ } catch (InterruptedException e) {
+ Log.d(TAG, "InterruptedException: ", e);
+ }
+ final String fileName = UserHistoryPredictionDictionary.NAME + "." + testFilenameSuffix
+ + ExpandableBinaryDictionary.DICT_FILE_EXTENSION;
+ dictFile = new File(getContext().getFilesDir(), fileName);
+ if (dictFile != null) {
+ assertTrue(dictFile.exists());
+ assertTrue(dictFile.length() >= MIN_USER_HISTORY_DICTIONARY_FILE_SIZE);
+ dictFile.delete();
+ }
+ }
+ }
+
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java b/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java
new file mode 100644
index 000000000..7fd167977
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+@MediumTest
+public class AsyncResultHolderTests extends AndroidTestCase {
+ private static final String TAG = AsyncResultHolderTests.class.getSimpleName();
+
+ private static final int TIMEOUT_IN_MILLISECONDS = 500;
+ private static final int MARGIN_IN_MILLISECONDS = 250;
+ private static final int DEFAULT_VALUE = 2;
+ private static final int SET_VALUE = 1;
+
+ private <T> void setAfterGivenTime(final AsyncResultHolder<T> holder, final T value,
+ final long time) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping", e);
+ }
+ holder.set(value);
+ }
+ }).start();
+ }
+
+ public void testGetWithoutSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(DEFAULT_VALUE, resultValue);
+ }
+
+ public void testGetBeforeSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
+ setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS + MARGIN_IN_MILLISECONDS);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(DEFAULT_VALUE, resultValue);
+ }
+
+ public void testGetAfterSet() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
+ holder.set(SET_VALUE);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(SET_VALUE, resultValue);
+ }
+
+ public void testGetBeforeTimeout() {
+ final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
+ setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS - MARGIN_IN_MILLISECONDS);
+ final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
+ assertEquals(SET_VALUE, resultValue);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutorTests.java b/tests/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutorTests.java
new file mode 100644
index 000000000..e0755483c
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutorTests.java
@@ -0,0 +1,105 @@
+/*
+ * 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.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unit tests for PrioritizedSerialExecutor.
+ * TODO: Add more detailed tests to make use of priorities, etc.
+ */
+@MediumTest
+public class PrioritizedSerialExecutorTests extends AndroidTestCase {
+ private static final String TAG = PrioritizedSerialExecutorTests.class.getSimpleName();
+
+ private static final int NUM_OF_TASKS = 10;
+ private static final int DELAY_FOR_WAITING_TASKS_MILLISECONDS = 500;
+
+ public void testExecute() {
+ final PrioritizedSerialExecutor executor = new PrioritizedSerialExecutor();
+ final AtomicInteger v = new AtomicInteger(0);
+ for (int i = 0; i < NUM_OF_TASKS; ++i) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ v.incrementAndGet();
+ }
+ });
+ }
+ try {
+ Thread.sleep(DELAY_FOR_WAITING_TASKS_MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping.", e);
+ }
+
+ assertEquals(NUM_OF_TASKS, v.get());
+ }
+
+ public void testExecutePrioritized() {
+ final PrioritizedSerialExecutor executor = new PrioritizedSerialExecutor();
+ final AtomicInteger v = new AtomicInteger(0);
+ for (int i = 0; i < NUM_OF_TASKS; ++i) {
+ executor.executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ v.incrementAndGet();
+ }
+ });
+ }
+ try {
+ Thread.sleep(DELAY_FOR_WAITING_TASKS_MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping.", e);
+ }
+
+ assertEquals(NUM_OF_TASKS, v.get());
+ }
+
+ public void testExecuteCombined() {
+ final PrioritizedSerialExecutor executor = new PrioritizedSerialExecutor();
+ final AtomicInteger v = new AtomicInteger(0);
+ for (int i = 0; i < NUM_OF_TASKS; ++i) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ v.incrementAndGet();
+ }
+ });
+ }
+
+ for (int i = 0; i < NUM_OF_TASKS; ++i) {
+ executor.executePrioritized(new Runnable() {
+ @Override
+ public void run() {
+ v.incrementAndGet();
+ }
+ });
+ }
+
+ try {
+ Thread.sleep(DELAY_FOR_WAITING_TASKS_MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Exception while sleeping.", e);
+ }
+
+ assertEquals(2 * NUM_OF_TASKS, v.get());
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
index cfff61ef8..cad80d5ce 100644
--- a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
@@ -340,4 +340,18 @@ public class ResizableIntArrayTests extends AndroidTestCase {
expecteds[i + expectedPos], actuals[i + actualPos]);
}
}
+
+ public void testShift() {
+ final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
+ final int limit = DEFAULT_CAPACITY * 10;
+ final int shiftAmount = 20;
+ for (int i = 0; i < limit; ++i) {
+ src.add(i, i);
+ assertEquals("length after add at " + i, i + 1, src.getLength());
+ }
+ src.shift(shiftAmount);
+ for (int i = 0; i < limit - shiftAmount; ++i) {
+ assertEquals("value at " + i, i + shiftAmount, src.get(i));
+ }
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/SpannableStringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpannableStringUtilsTests.java
new file mode 100644
index 000000000..fa6ad16c1
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/SpannableStringUtilsTests.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.latin.utils;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.style.SuggestionSpan;
+import android.text.style.URLSpan;
+import android.text.SpannableStringBuilder;
+import android.text.Spannable;
+import android.text.Spanned;
+
+@SmallTest
+public class SpannableStringUtilsTests extends AndroidTestCase {
+ public void testConcatWithSuggestionSpansOnly() {
+ SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n"
+ + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n"
+ + "test string\ntest string\n");
+ final int N = 10;
+ for (int i = 0; i < N; ++i) {
+ // Put a PARAGRAPH-flagged span that should not be found in the result.
+ s.setSpan(new SuggestionSpan(getContext(),
+ new String[] {"" + i}, Spannable.SPAN_PARAGRAPH),
+ i * 12, i * 12 + 12, Spannable.SPAN_PARAGRAPH);
+ // Put a normal suggestion span that should be found in the result.
+ s.setSpan(new SuggestionSpan(getContext(), new String[] {"" + i}, 0), i, i * 2, 0);
+ // Put a URL span than should not be found in the result.
+ s.setSpan(new URLSpan("http://a"), i, i * 2, 0);
+ }
+
+ final CharSequence a = s.subSequence(0, 15);
+ final CharSequence b = s.subSequence(15, s.length());
+ final Spanned result =
+ (Spanned)SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b);
+
+ Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class);
+ for (int i = 0; i < spans.length; i++) {
+ final int flags = result.getSpanFlags(spans[i]);
+ assertEquals("Should not find a span with PARAGRAPH flag",
+ flags & Spannable.SPAN_PARAGRAPH, 0);
+ assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan);
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
index 175e511b0..4e396a1cf 100644
--- a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
@@ -21,6 +21,8 @@ import com.android.inputmethod.latin.settings.SettingsValues;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
@SmallTest
@@ -256,4 +258,26 @@ public class StringUtilsTests extends AndroidTestCase {
// code for now True is acceptable.
assertTrue(StringUtils.lastPartLooksLikeURL(".abc/def"));
}
+
+ public void testHexStringUtils() {
+ final byte[] bytes = new byte[] { (byte)0x01, (byte)0x11, (byte)0x22, (byte)0x33,
+ (byte)0x55, (byte)0x88, (byte)0xEE };
+ final String bytesStr = StringUtils.byteArrayToHexString(bytes);
+ final byte[] bytes2 = StringUtils.hexStringToByteArray(bytesStr);
+ for (int i = 0; i < bytes.length; ++i) {
+ assertTrue(bytes[i] == bytes2[i]);
+ }
+ final String bytesStr2 = StringUtils.byteArrayToHexString(bytes2);
+ assertTrue(bytesStr.equals(bytesStr2));
+ }
+
+ public void testJsonStringUtils() {
+ final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 };
+ final List<Object> objArray = Arrays.asList(objs);
+ final String str = StringUtils.listToJsonStr(objArray);
+ final List<Object> newObjArray = StringUtils.jsonStrToList(str);
+ for (int i = 0; i < objs.length; ++i) {
+ assertEquals(objs[i], newObjArray.get(i));
+ }
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index baebda2ed..856b2dbda 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -214,7 +214,7 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA));
assertEquals("de ", "Allemand",
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE));
- assertEquals("zz ", "Alphabet (QWERTY)",
+ assertEquals("zz ", "Alphabet latin (QWERTY)",
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ));
return null;
}
@@ -236,7 +236,7 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase {
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(EN_UK_DVORAK));
assertEquals("es_US colemak","Espagnol (États-Unis) (Colemak)",
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ES_US_COLEMAK));
- assertEquals("zz pc", "Alphabet (PC)",
+ assertEquals("zz pc", "Alphabet latin (PC)",
SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC));
return null;
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
index ce62bf21a..3eabe2b3c 100644
--- a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
@@ -21,17 +21,19 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
+import com.android.inputmethod.latin.makedict.DictDecoder;
+import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.Ver3DictDecoder;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList;
import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface;
import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener;
import java.io.File;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -49,6 +51,7 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase
private static final int BIGRAM_FREQUENCY = 100;
private static final ArrayList<String> NOT_HAVE_BIGRAM = new ArrayList<String>();
private static final FormatSpec.FormatOptions FORMAT_OPTIONS = new FormatSpec.FormatOptions(2);
+ private static final String TEST_DICT_FILE_EXTENSION = ".testDict";
/**
* Return same frequency for all words and bigrams
@@ -86,12 +89,12 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase
private void checkWordInFusionDict(final FusionDictionary dict, final String word,
final ArrayList<String> expectedBigrams) {
- final CharGroup group = FusionDictionary.findWordInTree(dict.mRoot, word);
- assertNotNull(group);
- assertTrue(group.isTerminal());
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word);
+ assertNotNull(ptNode);
+ assertTrue(ptNode.isTerminal());
for (final String bigram : expectedBigrams) {
- assertNotNull(group.getBigram(bigram));
+ assertNotNull(ptNode.getBigram(bigram));
}
}
@@ -135,26 +138,20 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase
private void writeDictToFile(final File file,
final UserHistoryDictionaryBigramList bigramList) {
- try {
- final FileOutputStream out = new FileOutputStream(file);
- UserHistoryDictIOUtils.writeDictionaryBinary(out, this, bigramList, FORMAT_OPTIONS);
- out.flush();
- out.close();
- } catch (IOException e) {
- Log.e(TAG, "IO exception while writing file", e);
- }
+ final DictEncoder dictEncoder = new Ver3DictEncoder(file);
+ UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, bigramList, FORMAT_OPTIONS);
}
private void readDictFromFile(final File file, final OnAddWordListener listener) {
- final BinaryDictReader reader = new BinaryDictReader(file);
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, DictDecoder.USE_BYTEARRAY);
try {
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ dictDecoder.openDictBuffer();
} catch (FileNotFoundException e) {
Log.e(TAG, "file not found", e);
} catch (IOException e) {
Log.e(TAG, "IOException", e);
}
- UserHistoryDictIOUtils.readDictionaryBinary(reader, listener);
+ UserHistoryDictIOUtils.readDictionaryBinary(dictDecoder, listener);
}
public void testGenerateFusionDictionary() {
@@ -177,7 +174,8 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase
File file = null;
try {
- file = File.createTempFile("testReadAndWrite", ".dict", getContext().getCacheDir());
+ file = File.createTempFile("testReadAndWrite", TEST_DICT_FILE_EXTENSION,
+ getContext().getCacheDir());
} catch (IOException e) {
Log.d(TAG, "IOException while creating a temporary file", e);
}
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index f076ef277..3d09c0508 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -28,7 +28,7 @@ LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annot
LATINIME_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin
MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_CORE_SOURCE_DIRECTORY)/makedict
USED_TARGETTED_UTILS := \
- $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayWrapper.java \
+ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \
$(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \
$(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java
diff --git a/tools/dicttool/NativeLib.mk b/tools/dicttool/NativeLib.mk
index 84e54a931..a3d3c0295 100644
--- a/tools/dicttool/NativeLib.mk
+++ b/tools/dicttool/NativeLib.mk
@@ -34,7 +34,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(LATINIME_NATIVE_SRC_DIR)
# Used in jni_common.cpp to avoid registering useless methods.
LATIN_IME_JNI_SRC_FILES := \
- com_android_inputmethod_latin_makedict_BinaryDictDecoder.cpp \
+ com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \
jni_common.cpp
LATIN_IME_CORE_SRC_FILES :=
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
index f9a599c8e..6c4cbcf9d 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
@@ -16,8 +16,9 @@
package com.android.inputmethod.latin.dicttool;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
+import com.android.inputmethod.latin.makedict.DictDecoder;
+import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
@@ -31,8 +32,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
@@ -99,7 +98,7 @@ public final class BinaryDictOffdeviceUtils {
// over and over, ending in a stack overflow. Hence we limit the depth at which we try
// decoding the file.
if (depth > MAX_DECODE_DEPTH) return null;
- if (BinaryDictDecoder.isBinaryDictionary(src)) {
+ if (BinaryDictDecoderUtils.isBinaryDictionary(src)) {
spec.mFile = src;
return spec;
}
@@ -186,15 +185,14 @@ public final class BinaryDictOffdeviceUtils {
crash(filename, new RuntimeException(
filename + " does not seem to be a dictionary file"));
} else {
- final BinaryDictReader reader = new BinaryDictReader(decodedSpec.mFile);
- reader.openBuffer(
- new BinaryDictReader.FusionDictionaryBufferFromByteArrayFactory());
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodedSpec.mFile,
+ DictDecoder.USE_BYTEARRAY);
if (report) {
System.out.println("Format : Binary dictionary format");
System.out.println("Packaging : " + decodedSpec.describeChain());
System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
}
- return BinaryDictDecoder.readDictionaryBinary(reader, null);
+ return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
}
}
} catch (IOException e) {
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
index 092ee767f..4b6716936 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java
@@ -19,7 +19,7 @@ package com.android.inputmethod.latin.dicttool;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.makedict.Word;
@@ -117,7 +117,7 @@ public class CombinedInputOutput {
final boolean processLigatures =
FRENCH_LIGATURE_PROCESSING_OPTION.equals(attributes.get(OPTIONS_TAG));
attributes.remove(OPTIONS_TAG);
- final FusionDictionary dict = new FusionDictionary(new Node(), new DictionaryOptions(
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), new DictionaryOptions(
attributes, processUmlauts, processLigatures));
String line;
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
index fa267f155..5c7e8b4f2 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -16,23 +16,22 @@
package com.android.inputmethod.latin.dicttool;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoder;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
+import com.android.inputmethod.latin.makedict.DictDecoder;
+import com.android.inputmethod.latin.makedict.DictEncoder;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.MakedictLog;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
+import com.android.inputmethod.latin.makedict.Ver4DictEncoder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.LinkedList;
@@ -46,9 +45,9 @@ import org.xml.sax.SAXException;
public class DictionaryMaker {
static class Arguments {
- private static final String OPTION_VERSION_1 = "-1";
private static final String OPTION_VERSION_2 = "-2";
private static final String OPTION_VERSION_3 = "-3";
+ private static final String OPTION_VERSION_4 = "-4";
private static final String OPTION_INPUT_SOURCE = "-s";
private static final String OPTION_INPUT_BIGRAM_XML = "-b";
private static final String OPTION_INPUT_SHORTCUT_XML = "-c";
@@ -129,12 +128,12 @@ public class DictionaryMaker {
+ "| [-s <combined format input]"
+ "| [-s <binary input>] [-d <binary output>] [-x <xml output>] "
+ " [-o <combined output>]"
- + "[-1] [-2] [-3]\n"
+ + "[-2] [-3] [-4]\n"
+ "\n"
+ " Converts a source dictionary file to one or several outputs.\n"
+ " Source can be an XML file, with an optional XML bigrams file, or a\n"
+ " binary dictionary file.\n"
- + " Binary version 1 (Ice Cream Sandwich), 2 (Jelly Bean), 3, XML and\n"
+ + " Binary version 2 (Jelly Bean), 3, 4, XML and\n"
+ " combined format outputs are supported.";
}
@@ -161,8 +160,8 @@ public class DictionaryMaker {
// Do nothing, this is the default
} else if (OPTION_VERSION_3.equals(arg)) {
outputBinaryFormatVersion = 3;
- } else if (OPTION_VERSION_1.equals(arg)) {
- outputBinaryFormatVersion = 1;
+ } else if (OPTION_VERSION_4.equals(arg)) {
+ outputBinaryFormatVersion = 4;
} else if (OPTION_HELP.equals(arg)) {
displayHelp();
} else {
@@ -178,7 +177,7 @@ public class DictionaryMaker {
inputUnigramXml = filename;
} else if (CombinedInputOutput.isCombinedDictionary(filename)) {
inputCombined = filename;
- } else if (BinaryDictDecoder.isBinaryDictionary(filename)) {
+ } else if (BinaryDictDecoderUtils.isBinaryDictionary(filename)) {
inputBinary = filename;
} else {
throw new IllegalArgumentException(
@@ -200,7 +199,7 @@ public class DictionaryMaker {
}
} else {
if (null == inputBinary && null == inputUnigramXml) {
- if (BinaryDictDecoder.isBinaryDictionary(arg)) {
+ if (BinaryDictDecoderUtils.isBinaryDictionary(arg)) {
inputBinary = arg;
} else if (CombinedInputOutput.isCombinedDictionary(arg)) {
inputCombined = arg;
@@ -268,9 +267,8 @@ public class DictionaryMaker {
private static FusionDictionary readBinaryFile(final String binaryFilename)
throws FileNotFoundException, IOException, UnsupportedFormatException {
final File file = new File(binaryFilename);
- final BinaryDictReader reader = new BinaryDictReader(file);
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteBufferFactory());
- return BinaryDictDecoder.readDictionaryBinary(reader, null);
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file);
+ return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
}
/**
@@ -359,8 +357,13 @@ public class DictionaryMaker {
throws FileNotFoundException, IOException, UnsupportedFormatException {
final File outputFile = new File(outputFilename);
final FormatSpec.FormatOptions formatOptions = new FormatSpec.FormatOptions(version);
- BinaryDictEncoder.writeDictionaryBinary(new FileOutputStream(outputFilename), dict,
- formatOptions);
+ final DictEncoder dictEncoder;
+ if (version == 4) {
+ dictEncoder = new Ver4DictEncoder(outputFile);
+ } else {
+ dictEncoder = new Ver3DictEncoder(outputFile);
+ }
+ dictEncoder.writeDictionary(dict, formatOptions);
}
/**
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java
index 5c3e87e10..66fd084cd 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java
@@ -17,7 +17,7 @@
package com.android.inputmethod.latin.dicttool;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.makedict.Word;
@@ -121,7 +121,8 @@ public class Diff extends Dicttool.Command {
private static void diffWords(final FusionDictionary dict0, final FusionDictionary dict1) {
boolean hasDifferences = false;
for (final Word word0 : dict0) {
- final CharGroup word1 = FusionDictionary.findWordInTree(dict1.mRoot, word0.mWord);
+ final PtNode word1 = FusionDictionary.findWordInTree(dict1.mRootNodeArray,
+ word0.mWord);
if (null == word1) {
// This word is not in dict1
System.out.println("Deleted: " + word0.mWord + " " + word0.mFrequency);
@@ -150,7 +151,8 @@ public class Diff extends Dicttool.Command {
}
}
for (final Word word1 : dict1) {
- final CharGroup word0 = FusionDictionary.findWordInTree(dict0.mRoot, word1.mWord);
+ final PtNode word0 = FusionDictionary.findWordInTree(dict0.mRootNodeArray,
+ word1.mWord);
if (null == word0) {
// This word is not in dict0
System.out.println("Added: " + word1.mWord + " " + word1.mFrequency);
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
index f2894544f..350f42772 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Info.java
@@ -18,7 +18,7 @@ package com.android.inputmethod.latin.dicttool;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.makedict.Word;
@@ -65,20 +65,20 @@ public class Info extends Dicttool.Command {
private static void showWordInfo(final FusionDictionary dict, final String word,
final boolean plumbing) {
- final CharGroup group = FusionDictionary.findWordInTree(dict.mRoot, word);
- if (null == group) {
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word);
+ if (null == ptNode) {
System.out.println(word + " is not in the dictionary");
return;
}
System.out.println("Word: " + word);
- System.out.println(" Freq: " + group.getFrequency());
- if (group.getIsNotAWord()) {
+ System.out.println(" Freq: " + ptNode.getFrequency());
+ if (ptNode.getIsNotAWord()) {
System.out.println(" Is not a word");
}
- if (group.getIsBlacklistEntry()) {
+ if (ptNode.getIsBlacklistEntry()) {
System.out.println(" Is a blacklist entry");
}
- final ArrayList<WeightedString> shortcutTargets = group.getShortcutTargets();
+ final ArrayList<WeightedString> shortcutTargets = ptNode.getShortcutTargets();
if (null == shortcutTargets || shortcutTargets.isEmpty()) {
System.out.println(" No shortcuts");
} else {
@@ -88,7 +88,7 @@ public class Info extends Dicttool.Command {
? "whitelist" : shortcutTarget.mFrequency) + ")");
}
}
- final ArrayList<WeightedString> bigrams = group.getBigrams();
+ final ArrayList<WeightedString> bigrams = ptNode.getBigrams();
if (null == bigrams || bigrams.isEmpty()) {
System.out.println(" No bigrams");
} else {
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
index 967e21eb2..9174238da 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
@@ -37,9 +37,9 @@ public class Test extends Dicttool.Command {
private static final Class<?>[] sClassesToTest = {
BinaryDictOffdeviceUtilsTests.class,
FusionDictionaryTest.class,
- BinaryDictDecoderEncoderTests.class
+ BinaryDictDecoderEncoderTests.class,
BinaryDictEncoderFlattenTreeTests.class,
- BinaryDictIOUtilsTests.class,
+ BinaryDictIOUtilsTests.class
};
private ArrayList<Method> mAllTestMethods = new ArrayList<Method>();
private ArrayList<String> mUsedTestMethods = new ArrayList<String>();
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
index 1fd2cba7a..4e99bf979 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java
@@ -18,7 +18,7 @@ package com.android.inputmethod.latin.dicttool;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
import com.android.inputmethod.latin.makedict.Word;
@@ -124,8 +124,8 @@ public class XmlDictInputOutput {
GERMAN_UMLAUT_PROCESSING_OPTION.equals(optionsString);
final boolean processLigatures =
FRENCH_LIGATURE_PROCESSING_OPTION.equals(optionsString);
- mDictionary = new FusionDictionary(new Node(), new DictionaryOptions(attributes,
- processUmlauts, processLigatures));
+ mDictionary = new FusionDictionary(new PtNodeArray(),
+ new DictionaryOptions(attributes, processUmlauts, processLigatures));
} else {
mState = UNKNOWN;
}
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
index 5490aff4d..1eff497c1 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -16,26 +16,23 @@
package com.android.inputmethod.latin.dicttool;
-import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
-import com.android.inputmethod.latin.makedict.BinaryDictEncoder;
-import com.android.inputmethod.latin.makedict.BinaryDictReader;
+import com.android.inputmethod.latin.makedict.DictDecoder;
+import com.android.inputmethod.latin.makedict.DictEncoder;
+import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.makedict.Ver3DictEncoder;
import junit.framework.TestCase;
import java.io.File;
import java.io.BufferedOutputStream;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -46,7 +43,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
public void testGetRawDictWorks() throws IOException, UnsupportedFormatException {
// Create a thrice-compressed dictionary file.
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new DictionaryOptions(new HashMap<String, String>(),
false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */));
dict.add("foo", TEST_FREQ, null, false /* isNotAWord */);
@@ -57,12 +54,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
final File dst = File.createTempFile("testGetRawDict", ".tmp");
dst.deleteOnExit();
+
final OutputStream out = Compress.getCompressedStream(
Compress.getCompressedStream(
Compress.getCompressedStream(
new BufferedOutputStream(new FileOutputStream(dst)))));
-
- BinaryDictEncoder.writeDictionaryBinary(out, dict, new FormatOptions(2, false));
+ final DictEncoder dictEncoder = new Ver3DictEncoder(out);
+ dictEncoder.writeDictionary(dict, new FormatOptions(2, false));
// Test for an actually compressed dictionary and its contents
final BinaryDictOffdeviceUtils.DecoderChainSpec decodeSpec =
@@ -71,12 +69,13 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase {
assertEquals("Wrong decode spec", BinaryDictOffdeviceUtils.COMPRESSION, step);
}
assertEquals("Wrong decode spec", 3, decodeSpec.mDecoderSpec.size());
- final BinaryDictReader reader = new BinaryDictReader(decodeSpec.mFile);
- reader.openBuffer(new BinaryDictReader.FusionDictionaryBufferFromByteBufferFactory());
- final FusionDictionary resultDict = BinaryDictDecoder.readDictionaryBinary(reader,
- null /* dict : an optional dictionary to add words to, or null */);
+ final DictDecoder dictDecoder = FormatSpec.getDictDecoder(decodeSpec.mFile);
+ final FusionDictionary resultDict = dictDecoder.readDictionaryBinary(
+ null /* dict : an optional dictionary to add words to, or null */,
+ false /* deleteDictIfBroken */);
assertEquals("Dictionary can't be read back correctly",
- resultDict.findWordInTree(resultDict.mRoot, "foo").getFrequency(), TEST_FREQ);
+ FusionDictionary.findWordInTree(resultDict.mRootNodeArray, "foo").getFrequency(),
+ TEST_FREQ);
}
public void testGetRawDictFails() throws IOException {
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java
index 2fcfb5e15..55058238c 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java
@@ -17,7 +17,7 @@
package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import junit.framework.TestCase;
@@ -25,13 +25,13 @@ import java.util.ArrayList;
import java.util.HashMap;
/**
- * Unit tests for BinaryDictEncoder.flattenTree().
+ * Unit tests for BinaryDictEncoderUtils.flattenTree().
*/
public class BinaryDictEncoderFlattenTreeTests extends TestCase {
// Test the flattened array contains the expected number of nodes, and
// that it does not contain any duplicates.
public void testFlattenNodes() {
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new DictionaryOptions(new HashMap<String, String>(),
false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */));
dict.add("foo", 1, null, false /* isNotAWord */);
@@ -39,10 +39,11 @@ public class BinaryDictEncoderFlattenTreeTests extends TestCase {
dict.add("ftb", 1, null, false /* isNotAWord */);
dict.add("bar", 1, null, false /* isNotAWord */);
dict.add("fool", 1, null, false /* isNotAWord */);
- final ArrayList<Node> result = BinaryDictEncoder.flattenTree(dict.mRoot);
+ final ArrayList<PtNodeArray> result =
+ BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray);
assertEquals(4, result.size());
while (!result.isEmpty()) {
- final Node n = result.remove(0);
+ final PtNodeArray n = result.remove(0);
assertFalse("Flattened array contained the same node twice", result.contains(n));
}
}
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
index 8efb4a4b9..659650a05 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
@@ -17,9 +17,9 @@
package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.Word;
import junit.framework.TestCase;
@@ -72,8 +72,8 @@ public class FusionDictionaryTest extends TestCase {
assertNotNull(dict);
for (final String word : words) {
if (--limit < 0) return;
- final CharGroup cg = FusionDictionary.findWordInTree(dict.mRoot, word);
- assertNotNull(cg);
+ final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray, word);
+ assertNotNull(ptNode);
}
}
@@ -95,7 +95,7 @@ public class FusionDictionaryTest extends TestCase {
// Test the flattened array contains the expected number of nodes, and
// that it does not contain any duplicates.
public void testFusion() {
- final FusionDictionary dict = new FusionDictionary(new Node(),
+ final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new DictionaryOptions(new HashMap<String, String>(),
false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */));
final long time = System.currentTimeMillis();
diff --git a/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml
index 8624dfb65..9728c9963 100644
--- a/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-ca/donottranslate-more-keys.xml
@@ -71,7 +71,7 @@
U+0142: "ł" LATIN SMALL LETTER L WITH STROKE -->
<string name="more_keys_for_l">l&#x00B7;l,&#x0142;</string>
<!-- U+00B7: "·" MIDDLE DOT -->
- <string name="more_keys_for_punctuation">"!fixedColumnOrder!9,&#x00B7;,\",\',#,-,:,!,\\,,\?,\@,&amp;,\\%,+,;,/,(,)"</string>
+ <string name="more_keys_for_punctuation">"!fixedColumnOrder!4,&#x00B7;,!,\\,,\?,:,;,\@"</string>
<string name="more_keys_for_tablet_period">\?,&#x00B7;</string>
<!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA -->
<string name="keylabel_for_spanish_row2_10">&#x00E7;</string>
diff --git a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml
index 0e58c1440..849429629 100644
--- a/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-es/donottranslate-more-keys.xml
@@ -71,7 +71,7 @@
<string name="keylabel_for_spanish_row2_10">&#x00F1;</string>
<!-- U+00A1: "¡" INVERTED EXCLAMATION MARK
U+00BF: "¿" INVERTED QUESTION MARK -->
- <string name="more_keys_for_punctuation">"!fixedColumnOrder!9,&#x00A1;,\",\',#,-,:,!,\\,,\?,&#x00BF;,\@,&amp;,\\%,+,;,/,(,)"</string>
+ <string name="more_keys_for_punctuation">"!fixedColumnOrder!4,;,!,\\,,\?,:,&#x00A1;,\@,&#x00BF;"</string>
<!-- U+00A1: "¡" INVERTED EXCLAMATION MARK -->
<string name="more_keys_for_tablet_comma">"!,&#x00A1;"</string>
<!-- U+00BF: "¿" INVERTED QUESTION MARK -->
diff --git a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
index 6d13d6bb6..5a03c803c 100644
--- a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
@@ -86,6 +86,8 @@
<string name="keylabel_for_apostrophe">&#x060C;</string>
<string name="keyhintlabel_for_apostrophe">&#x061F;</string>
<string name="more_keys_for_apostrophe">"!fixedColumnOrder!4,:,!,&#x061F;,&#x061B;,-,/,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;"</string>
+ <!-- U+FDFC: "﷼" RIAL SIGN -->
+ <string name="keylabel_for_currency">&#xFDFC;</string>
<!-- U+061F: "؟" ARABIC QUESTION MARK
U+060C: "،" ARABIC COMMA
U+061B: "؛" ARABIC SEMICOLON -->
diff --git a/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml
index 98ad2cb3e..b0d010f81 100644
--- a/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-hi/donottranslate-more-keys.xml
@@ -59,5 +59,5 @@
<string name="additional_more_keys_for_symbols_9">9</string>
<string name="additional_more_keys_for_symbols_0">0</string>
<!-- U+20B9: "₹" INDIAN RUPEE SIGN -->
- <string name="keylabel_for_currency_generic">&#x20B9;</string>
+ <string name="keylabel_for_currency">&#x20B9;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml
new file mode 100644
index 000000000..2f34128bd
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-hy/donottranslate-more-keys.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- U+058A: "֊" ARMENIAN HYPHEN -->
+ <!-- U+055C: "՜" ARMENIAN EXCLAMATION MARK -->
+ <!-- U+055D: "՝" ARMENIAN COMMA -->
+ <!-- U+055E: "՞" ARMENIAN QUESTION MARK -->
+ <!-- U+0559: "ՙ" ARMENIAN MODIFIER LETTER LEFT HALF RING -->
+ <!-- U+055A: "՚" ARMENIAN APOSTROPHE -->
+ <!-- U+055B: "՛" ARMENIAN EMPHASIS MARK -->
+ <!-- U+055F: "՟" ARMENIAN ABBREVIATION MARK -->
+ <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,!,?,\\,,.,&#x058A;,&#x055C;,&#x055D;,&#x055E;,:,;,\@,&#x0559;,&#x055A;,&#x055B;,&#x055F;"</string>
+ <!-- U+055E: "՞" ARMENIAN QUESTION MARK -->
+ <!-- U+00BF: "¿" INVERTED QUESTION MARK -->
+ <string name="more_keys_for_symbols_question">&#x055E;,&#x00BF;</string>
+ <!-- U+055C: "՜" ARMENIAN EXCLAMATION MARK -->
+ <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK -->
+ <string name="more_keys_for_symbols_exclamation">&#x055C;,&#x00A1;</string>
+ <!-- U+058F: "֏" ARMENIAN DRAM SIGN -->
+ <!-- TODO: Enable this when we have glyph for the following letter
+ <string name="keylabel_for_currency">&#x058F;</string>
+ -->
+</resources>
diff --git a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml
index 9d2e01ebd..feaed4c98 100644
--- a/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-iw/donottranslate-more-keys.xml
@@ -23,7 +23,6 @@
U+05D1: "ב" HEBREW LETTER BET
U+05D2: "ג" HEBREW LETTER GIMEL -->
<string name="label_to_alpha_key">&#x05D0;&#x05D1;&#x05D2;</string>
- <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,\\,,\?,\@,&amp;,\\%,+,;,/,(|),)|("</string>
<!-- U+2605: "★" BLACK STAR -->
<string name="more_keys_for_star">&#x2605;</string>
<!-- U+00B1: "±" PLUS-MINUS SIGN
@@ -52,4 +51,10 @@
<string name="double_quotes">&#x201C;,&#x201D;,&#x201E;</string>
<string name="single_angle_quotes">!text/single_laqm_raqm_rtl</string>
<string name="double_angle_quotes">!text/double_laqm_raqm_rtl</string>
+ <!-- U+20AA: "₪" NEW SHEQEL SIGN -->
+ <string name="keylabel_for_currency">&#x20AA;</string>
+ <string name="keyhintlabel_for_tablet_comma">!</string>
+ <string name="more_keys_for_tablet_comma">!</string>
+ <string name="keyhintlabel_for_tablet_period">\?</string>
+ <string name="more_keys_for_tablet_period">\?</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml
new file mode 100644
index 000000000..c33831c56
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-km/donottranslate-more-keys.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+1780: "ក" KHMER LETTER KA
+ U+1781: "ខ" KHMER LETTER KHA
+ U+1782: "គ" KHMER LETTER KO -->
+ <string name="label_to_alpha_key">&#x1780;&#x1781;&#x1782;</string>
+ <!-- U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL -->
+ <string name="more_keys_for_currency_dollar">&#x17DB;,&#x00A2;,&#x00A3;,&#x20AC;,&#x00A5;,&#x20B1;</string>
+
+</resources>
diff --git a/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml
new file mode 100644
index 000000000..1d8ffa8cf
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0E81: "ກ" LAO LETTER KO
+ U+0E82: "ຂ" LAO LETTER KHO SUNG
+ U+0E84: "ຄ" LAO LETTER KHO TAM -->
+ <string name="label_to_alpha_key">&#x0E81;&#x0E82;&#x0E84;</string>
+ <!-- U+20AD: "₭" KIP SIGN -->
+ <string name="keylabel_for_currency">&#x20AD;</string>
+</resources>
diff --git a/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml
index fd1853e85..a7f366685 100644
--- a/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-mn/donottranslate-more-keys.xml
@@ -24,5 +24,5 @@
U+0412: "В" CYRILLIC CAPITAL LETTER VE -->
<string name="label_to_alpha_key">&#x0410;&#x0411;&#x0412;</string>
<!-- U+20AE: "₮" TUGRIK SIGN -->
- <string name="keylabel_for_currency_generic">&#x20AE;</string>
+ <string name="keylabel_for_currency">&#x20AE;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml
new file mode 100644
index 000000000..9205e5309
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0915: "क" DEVANAGARI LETTER KA
+ U+0916: "ख" DEVANAGARI LETTER KHA
+ U+0917: "ग" DEVANAGARI LETTER GA -->
+ <string name="label_to_alpha_key">&#x0915;&#x0916;&#x0917;</string>
+ <!-- U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <string name="keylabel_for_symbols_1">&#x0967;</string>
+ <!-- U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <string name="keylabel_for_symbols_2">&#x0968;</string>
+ <!-- U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <string name="keylabel_for_symbols_3">&#x0969;</string>
+ <!-- U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <string name="keylabel_for_symbols_4">&#x096A;</string>
+ <!-- U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <string name="keylabel_for_symbols_5">&#x096B;</string>
+ <!-- U+096C: "६" DEVANAGARI DIGIT SIX -->
+ <string name="keylabel_for_symbols_6">&#x096C;</string>
+ <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN -->
+ <string name="keylabel_for_symbols_7">&#x096D;</string>
+ <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT -->
+ <string name="keylabel_for_symbols_8">&#x096E;</string>
+ <!-- U+096F: "९" DEVANAGARI DIGIT NINE -->
+ <string name="keylabel_for_symbols_9">&#x096F;</string>
+ <!-- U+0966: "०" DEVANAGARI DIGIT ZERO -->
+ <string name="keylabel_for_symbols_0">&#x0966;</string>
+ <!-- Label for "switch to symbols" key. -->
+ <string name="label_to_symbol_key">\?&#x0967;&#x0968;&#x0969;</string>
+ <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ part because it'll be appended by the code. -->
+ <string name="label_to_symbol_with_microphone_key">&#x0967;&#x0968;&#x0969;</string>
+ <string name="additional_more_keys_for_symbols_1">1</string>
+ <string name="additional_more_keys_for_symbols_2">2</string>
+ <string name="additional_more_keys_for_symbols_3">3</string>
+ <string name="additional_more_keys_for_symbols_4">4</string>
+ <string name="additional_more_keys_for_symbols_5">5</string>
+ <string name="additional_more_keys_for_symbols_6">6</string>
+ <string name="additional_more_keys_for_symbols_7">7</string>
+ <string name="additional_more_keys_for_symbols_8">8</string>
+ <string name="additional_more_keys_for_symbols_9">9</string>
+ <string name="additional_more_keys_for_symbols_0">0</string>
+ <!-- U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN -->
+ <string name="keylabel_for_currency">&#x0930;&#x0941;&#x002E;</string>
+</resources>
diff --git a/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml
index 6350d4b8e..070c91526 100644
--- a/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-th/donottranslate-more-keys.xml
@@ -24,5 +24,5 @@
U+0E04: "ค" THAI CHARACTER KHO KHWAI -->
<string name="label_to_alpha_key">&#x0E01;&#x0E02;&#x0E04;</string>
<!-- U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT -->
- <string name="keylabel_for_currency_generic">&#x0E3F;</string>
+ <string name="keylabel_for_currency">&#x0E3F;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml
index cc05cc697..6ee34e305 100644
--- a/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-uk/donottranslate-more-keys.xml
@@ -35,7 +35,7 @@
<!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
<string name="more_keys_for_cyrillic_soft_sign">&#x044A;</string>
<!-- U+20B4: "₴" HRYVNIA SIGN -->
- <string name="keylabel_for_currency_generic">&#x20B4;</string>
+ <string name="keylabel_for_currency">&#x20B4;</string>
<!-- Label for "switch to alphabetic" key.
U+0410: "А" CYRILLIC CAPITAL LETTER A
U+0411: "Б" CYRILLIC CAPITAL LETTER BE
diff --git a/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml
index fa98ea9e1..f01f0687a 100644
--- a/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-vi/donottranslate-more-keys.xml
@@ -93,5 +93,5 @@
<!-- U+0111: "đ" LATIN SMALL LETTER D WITH STROKE -->
<string name="more_keys_for_d">&#x0111;</string>
<!-- U+20AB: "₫" DONG SIGN -->
- <string name="keylabel_for_currency_generic">&#x20AB;</string>
+ <string name="keylabel_for_currency">&#x20AB;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
index 4cf26505f..cc09f7fe5 100644
--- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
@@ -75,9 +75,9 @@
U+00A5: "¥" YEN SIGN
U+20B1: "₱" PESO SIGN -->
<string name="more_keys_for_currency_dollar">&#x00A2;,&#x00A3;,&#x20AC;,&#x00A5;,&#x20B1;</string>
- <string name="keylabel_for_currency_generic">$</string>
- <string name="more_keys_for_currency_generic">$,&#x00A2;,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
- <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,\\,,\?,\@,&amp;,\\%,+,;,/,(,)"</string>
+ <string name="keylabel_for_currency">$</string>
+ <string name="more_keys_for_currency">$,&#x00A2;,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
+ <string name="more_keys_for_punctuation">"!fixedColumnOrder!3,!,\\,,\?,:,;,\@"</string>
<!-- U+2020: "†" DAGGER
U+2021: "‡" DOUBLE DAGGER
U+2605: "★" BLACK STAR -->
@@ -167,10 +167,11 @@
<!-- U+2030: "‰" PER MILLE SIGN -->
<string name="more_keys_for_symbols_percent">&#x2030;</string>
<string name="keylabel_for_tablet_comma">,</string>
- <string name="keyhintlabel_for_tablet_comma">!</string>
- <string name="more_keys_for_tablet_comma">!</string>
- <string name="keyhintlabel_for_tablet_period">\?</string>
- <string name="more_keys_for_tablet_period">\?</string>
+ <string name="keyhintlabel_for_tablet_comma"></string>
+ <string name="more_keys_for_tablet_comma"></string>
+ <string name="keyhintlabel_for_tablet_period"></string>
+ <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
+ <string name="more_keys_for_tablet_period">&#x2026;</string>
<string name="keylabel_for_apostrophe">\'</string>
<string name="keyhintlabel_for_apostrophe">\"</string>
<string name="more_keys_for_apostrophe">\"</string>
@@ -189,7 +190,7 @@
<!-- Label for "switch to more symbol" modifier key. Must be short to fit on key! -->
<string name="label_to_more_symbol_key">= \\ &lt;</string>
<!-- Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! -->
- <string name="label_to_more_symbol_for_tablet_key">~ \\ {</string>
+ <string name="label_to_more_symbol_for_tablet_key">~ [ &lt;</string>
<!-- Label for "Tab" key. Must be short to fit on key! -->
<string name="label_tab_key">Tab</string>
<!-- Label for "switch to phone numeric" key. Must be short to fit on key! -->
@@ -202,8 +203,6 @@
<string name="label_time_am">"AM"</string>
<!-- Key label for "post meridiem" -->
<string name="label_time_pm">"PM"</string>
- <!-- Label for "switch to symbols" key on PC QWERTY layout -->
- <string name="label_to_symbol_key_pcqwerty">Sym</string>
<string name="keylabel_for_popular_domain">".com"</string>
<!-- popular web domains for the locale - most popular, displayed on the keyboard -->
<string name="more_keys_for_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string>